diff --git a/apps/frontend/app/actions.ts b/apps/frontend/app/actions.ts index b7580a4..f90371c 100644 --- a/apps/frontend/app/actions.ts +++ b/apps/frontend/app/actions.ts @@ -22,10 +22,22 @@ export async function addChannel(formData: FormData) { revalidatePath("/"); } +/** ShortVideo has a required FK to CandidateSegment (candidate_id) — every deletion path that removes candidates must clear their shorts (row + rendered file) first, or Postgres rejects the candidate delete. */ +async function deleteShortsForCandidates(candidateIds: string[]): Promise { + if (candidateIds.length === 0) return; + const shorts = await prisma.shortVideo.findMany({ where: { candidateId: { in: candidateIds } } }); + await prisma.shortVideo.deleteMany({ where: { candidateId: { in: candidateIds } } }); + await Promise.all(shorts.filter((s) => s.filePath).map((s) => unlink(s.filePath!).catch(() => {}))); +} + export async function deleteRawSegment(segmentId: string) { - const segment = await prisma.rawSegment.findUnique({ where: { id: segmentId } }); + const segment = await prisma.rawSegment.findUnique({ + where: { id: segmentId }, + include: { candidates: true }, + }); if (!segment) return; + await deleteShortsForCandidates(segment.candidates.map((c) => c.id)); await prisma.candidateSegment.deleteMany({ where: { rawSegmentId: segmentId } }); await prisma.rawSegment.delete({ where: { id: segmentId } }); await unlink(segment.filePath).catch(() => {}); @@ -35,6 +47,7 @@ export async function deleteRawSegment(segmentId: string) { } export async function deleteCandidateSegment(candidateId: string) { + await deleteShortsForCandidates([candidateId]); await prisma.candidateSegment.delete({ where: { id: candidateId } }); revalidatePath("/segments"); @@ -44,11 +57,13 @@ export async function deleteCandidateSegment(candidateId: string) { export async function deleteChannel(channelId: string) { const sessions = await prisma.streamSession.findMany({ where: { channelId }, - include: { segments: true }, + include: { segments: { include: { candidates: true } } }, }); const rawSegmentIds = sessions.flatMap((s) => s.segments.map((seg) => seg.id)); + const candidateIds = sessions.flatMap((s) => s.segments.flatMap((seg) => seg.candidates.map((c) => c.id))); const filePaths = sessions.flatMap((s) => s.segments.map((seg) => seg.filePath)); + await deleteShortsForCandidates(candidateIds); await prisma.candidateSegment.deleteMany({ where: { rawSegmentId: { in: rawSegmentIds } } }); await prisma.rawSegment.deleteMany({ where: { sessionId: { in: sessions.map((s) => s.id) } } }); await prisma.streamSession.deleteMany({ where: { channelId } });