import { NextRequest, NextResponse } from "next/server"; import { db } from "@/lib/db"; function isAuthorized(req: NextRequest): boolean { const apiKey = process.env.API_SECRET_KEY; if (!apiKey) return false; const authHeader = req.headers.get("authorization") ?? ""; if (authHeader.startsWith("Bearer ")) { return authHeader.slice(7) === apiKey; } const headerKey = req.headers.get("x-api-key") ?? ""; return headerKey === apiKey; } // ── GET /api/ext/shots/[shotId] ─────────────────────────────────────────────── // // Returns full shot detail including tasks and latest version status. // Accepts either the database id or the shotCode via query param: // /api/ext/shots/ // /api/ext/shots/?byCode=1&projectId= export async function GET( req: NextRequest, { params }: { params: Promise<{ shotId: string }> } ) { if (!isAuthorized(req)) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { shotId } = await params; const { searchParams } = new URL(req.url); const byCode = searchParams.get("byCode") === "1"; const projectId = searchParams.get("projectId") ?? undefined; const shot = await db.shot.findFirst({ where: byCode ? { shotCode: shotId, ...(projectId ? { projectId } : {}) } : { id: shotId }, select: { id: true, shotCode: true, scene: true, episode: true, shotNumber: true, description: true, status: true, priority: true, frameStart: true, frameEnd: true, fps: true, dueDate: true, sourceClip: true, timecodeStart: true, timecodeEnd: true, clipDuration: true, exrOutput: true, seqTimecodeStart: true, seqTimecodeEnd: true, shotVersion: true, createdAt: true, updatedAt: true, project: { select: { id: true, name: true, code: true, showId: true }, }, artist: { select: { id: true, name: true, email: true }, }, tasks: { orderBy: { sortOrder: "asc" }, select: { id: true, title: true, type: true, status: true, priority: true, estimatedHours: true, dueDate: true, assignedArtist: { select: { id: true, name: true, email: true } }, _count: { select: { versions: true } }, }, }, versions: { orderBy: { versionNumber: "desc" }, take: 1, select: { id: true, versionNumber: true, approvalStatus: true, createdAt: true, artist: { select: { id: true, name: true, email: true } }, }, }, _count: { select: { versions: true, tasks: true }, }, }, }); if (!shot) { return NextResponse.json({ error: "Shot not found" }, { status: 404 }); } return NextResponse.json({ shot }); } // ── PATCH /api/ext/shots/[shotId] ───────────────────────────────────────────── // // Update mutable shot fields from pipeline tools. // Currently supports: shotVersion (format v###) // // Body (JSON): { shotVersion?: string } // Returns: { success: true, shot: { id, shotVersion } } export async function PATCH( req: NextRequest, { params }: { params: Promise<{ shotId: string }> } ) { if (!isAuthorized(req)) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const { shotId } = await params; const body = await req.json().catch(() => ({})); const { shotVersion } = body as { shotVersion?: string }; if (shotVersion !== undefined) { if (!/^v\d{3}$/.test(shotVersion)) { return NextResponse.json( { error: "shotVersion must match format v### (e.g. v001)" }, { status: 400 } ); } } else { return NextResponse.json({ error: "No updatable fields provided" }, { status: 400 }); } const shot = await db.shot.findUnique({ where: { id: shotId }, select: { id: true }, }); if (!shot) { return NextResponse.json({ error: "Shot not found" }, { status: 404 }); } const updated = await db.shot.update({ where: { id: shotId }, data: { ...(shotVersion !== undefined && { shotVersion }) }, select: { id: true, shotVersion: true }, }); return NextResponse.json({ success: true, shot: updated }); }