"use server"; import { prisma } from "@/lib/prisma"; import { s3 } from "@/lib/s3"; import { DeleteObjectCommand } from "@aws-sdk/client-s3"; // Deletes an artwork and all related assets and records. export async function deleteArtwork(artworkId: string) { const artwork = await prisma.artwork.findUnique({ where: { id: artworkId }, include: { variants: true, timelapse: true, colors: true, metadata: true, tags: true, categories: true, }, }); if (!artwork) throw new Error("Artwork not found"); // Delete S3 objects for (const variant of artwork.variants) { try { await s3.send( new DeleteObjectCommand({ Bucket: `${process.env.BUCKET_NAME}`, Key: variant.s3Key, }) ); } catch (err) { console.warn("Failed to delete S3 object: " + variant.s3Key + ". " + err); } } // Delete timelapse S3 object (if present) if (artwork.timelapse?.s3Key) { try { await s3.send( new DeleteObjectCommand({ Bucket: `${process.env.BUCKET_NAME}`, Key: artwork.timelapse.s3Key, }) ); } catch (err) { console.warn(`Failed to delete timelapse S3 object: ${artwork.timelapse.s3Key}. ${err}`); } } // Step 1: Delete join entries await prisma.artworkColor.deleteMany({ where: { artworkId } }); // Colors for (const color of artwork.colors) { const count = await prisma.artworkColor.count({ where: { colorId: color.colorId }, }); if (count === 0) { await prisma.color.delete({ where: { id: color.colorId } }); } } // Delete variants await prisma.fileVariant.deleteMany({ where: { artworkId } }); // Delete timelapse DB row (relation also cascades, but be explicit) await prisma.artworkTimelapse.deleteMany({ where: { artworkId } }); // Delete metadata await prisma.artworkMetadata.deleteMany({ where: { artworkId } }); // Clean many-to-many tag/category joins await prisma.artwork.update({ where: { id: artworkId }, data: { tags: { set: [] }, categories: { set: [] }, }, }); // Finally delete the image await prisma.artwork.delete({ where: { id: artworkId } }); return { success: true }; }