import type { NextRequest } from "next/server"; import { z } from "zod"; import { getActor } from "@/lib/auth/actor"; import { can, requirePermission, visibleGroupIds } from "@/lib/auth/policy"; import { prisma } from "@/lib/db"; import { errorResponse, firstZodMessage, jsonError } from "@/lib/http"; import { QrRequestError } from "@/lib/qr/type-module"; export const dynamic = "force-dynamic"; const createSchema = z.object({ name: z .string() .trim() .min(1, { error: "Bitte gib einen Namen für die Gruppe ein." }) .max(80, { error: "Der Name darf höchstens 80 Zeichen lang sein." }), description: z.string().trim().max(300).optional(), }); /** Gruppen samt Mitgliedern — gefiltert nach dem, was der Actor sehen darf. */ export async function GET(): Promise { try { const actor = await getActor(); if (actor.kind === "anonymous") { throw new QrRequestError("Bitte melde dich an.", 401); } const visible = visibleGroupIds(actor); const groups = await prisma.group.findMany({ where: visible === null ? undefined : { id: { in: visible } }, orderBy: { name: "asc" }, include: { memberships: { include: { user: { select: { id: true, email: true, name: true } } }, orderBy: { createdAt: "asc" }, }, _count: { select: { codes: true } }, }, }); return Response.json({ groups: groups.map((group) => ({ id: group.id, name: group.name, description: group.description, codeCount: group._count.codes, canManage: can(actor, "group:manage", { groupId: group.id }), members: group.memberships.map((m) => ({ userId: m.user.id, email: m.user.email, name: m.user.name, role: m.role, })), })), }); } catch (error) { return errorResponse(error); } } export async function POST(request: NextRequest): Promise { try { requirePermission(await getActor(), "instance:manage"); const parsed = createSchema.safeParse(await request.json()); if (!parsed.success) { return jsonError(firstZodMessage(parsed.error)); } const existing = await prisma.group.findUnique({ where: { name: parsed.data.name }, select: { id: true }, }); if (existing) { throw new QrRequestError("Eine Gruppe mit diesem Namen gibt es schon.", 409); } const group = await prisma.group.create({ data: { name: parsed.data.name, description: parsed.data.description || null, }, }); return Response.json({ group: { id: group.id, name: group.name } }, { status: 201 }); } catch (error) { return errorResponse(error); } }