import { NextResponse } from "next/server"; import { getPayload } from "payload"; import config from "@payload-config"; import { createMeetingToken } from "@/lib/meeting/token"; import { authorizeMeeting } from "@/lib/meeting/access"; export const dynamic = "force-dynamic"; type Body = { eventSlug?: unknown }; /** Creates a host session for an online event from the authenticated CRM. */ export async function POST(request: Request) { let body: Body; try { body = await request.json(); if (!body || typeof body !== "object" || Array.isArray(body)) throw new Error("Invalid body"); } catch { return NextResponse.json({ error: "Ungültige Anfrage." }, { status: 400 }); } const eventSlug = typeof body.eventSlug === "string" ? body.eventSlug.trim() : ""; if (!eventSlug) return NextResponse.json({ error: "Online-Termin fehlt." }, { status: 400 }); try { const payload = await getPayload({ config }); const { user } = await payload.auth({ headers: request.headers }); if (!user || user.collection !== "users" || user.role !== "admin") { return NextResponse.json({ error: "Nicht autorisiert." }, { status: 401 }); } const { docs } = await payload.find({ collection: "events", where: { slug: { equals: eventSlug } }, limit: 1, }); const event = docs[0]; if (!event || !event.isOnline) { return NextResponse.json({ error: "Dieser Termin ist kein Online-Termin." }, { status: 404 }); } const access = await authorizeMeeting(payload, event, "host"); if (!access) return NextResponse.json({ error: "Dieser Termin ist nicht offen oder wurde storniert." }, { status: 403 }); const { token } = createMeetingToken({ eventSlug, name: typeof user.name === "string" && user.name.trim() ? user.name.trim() : "Host", role: "host", accessVersion: access.accessVersion, ttlMs: Math.min(6 * 3600000, access.expiresAt - Date.now()), }); // Keep the token in the URL fragment: browsers do not send fragments to // the server, so the temporary host credential does not enter request or // reverse-proxy logs. The CRM copies this test link without navigating. const baseUrl = process.env.NEXT_PUBLIC_SERVER_URL || new URL(request.url).origin; const testUrl = `${baseUrl.replace(/\/$/, "")}/termine/${encodeURIComponent(eventSlug)}/call#token=${encodeURIComponent(token)}`; return NextResponse.json({ testUrl }); } catch (error) { console.error("admin meeting start failed", error); return NextResponse.json({ error: "Der Video-Call konnte nicht gestartet werden." }, { status: 500 }); } }