Repository Public
1import { sql } from "@/lib/db";2import { clientIpHash, sameOrigin } from "@/lib/auth";3import { rateLimit } from "@/lib/ratelimit";4import { bad } from "@/lib/api";56const REASONS = ["inaccurate", "harmful", "likeness", "copyright", "other"];7/** POST /api/reports — public takedown / problem report. Reviewed by a person in the studio. */8export async function POST(req: Request) {9 if (!sameOrigin(req)) return bad("bad_origin", 403);10 if (!(await rateLimit(`report:${await clientIpHash()}`, 5, 3600))) return bad("rate_limited", 429);11 const b = (await req.json().catch(() => null)) as Record<string, unknown> | null;12 if (!b) return bad("invalid_body");13 if (typeof b.website === "string" && b.website) return new Response(null, { status: 204 }); // honeypot14 const detail = String(b.detail ?? "").trim().slice(0, 2000), reason = String(b.reason ?? "other");15 if (detail.length < 8 || !REASONS.includes(reason)) return bad("invalid_body");16 const ref = String(b.film ?? "").trim().slice(0, 200);17 const slug = ref.split("/film/").pop()?.split(/[?#]/)[0] ?? "";18 const [film] = await sql<{ id: string }[]>`SELECT id FROM films WHERE slug = ${slug} OR lower(title_en) = lower(${ref}) OR lower(title_fr) = lower(${ref}) LIMIT 1`;19 await sql`INSERT INTO reports (film_id, reason, detail, contact) VALUES (${film?.id ?? null}, ${reason}, ${film ? detail : `[${ref}] ${detail}`}, ${String(b.contact ?? "").trim().slice(0, 200)})`;20 return Response.json({ ok: true }, { status: 201 });21}22