import { NextResponse } from "next/server"; import { z } from "zod"; import { getAppSettings, serializeAppSettings, toApprovalThresholdNumber } from "@/lib/app-settings"; import { snapshotAppSettings } from "@/lib/audit-snapshots"; import { createAuditLog } from "@/lib/audit-log"; import { APPROVAL_FLOW, canManageSettings, canManageUsers, normalizeRequiredApprovalTypes } from "@/lib/domain"; import prisma from "@/lib/prisma"; import { getCurrentViewer } from "@/lib/session"; const settingsSchema = z.object({ approvalThreshold: z.coerce.number().min(0).max(100000).optional(), requiredApprovalTypes: z.array(z.enum(APPROVAL_FLOW)).min(1).optional(), budgetReleaseNotifyTarget: z.enum(["ALL_GROUP_USERS", "GROUP_MEMBERS_ONLY"]).optional() }); export async function PATCH(request: Request) { const viewer = await getCurrentViewer(); if (!viewer) { return NextResponse.json({ error: "Nicht angemeldet." }, { status: 401 }); } if (!canManageUsers(viewer.role)) { return NextResponse.json({ error: "Nur Vorstand allgemein, AG Orga oder AG Finanzen duerfen Einstellungen aendern." }, { status: 403 }); } const body = await request.json().catch(() => null); const parsed = settingsSchema.safeParse(body); if (!parsed.success) { return NextResponse.json({ error: "Bitte gueltige Einstellungen eingeben." }, { status: 400 }); } const changesOrgaSettings = parsed.data.requiredApprovalTypes !== undefined || parsed.data.budgetReleaseNotifyTarget !== undefined; if (changesOrgaSettings && !canManageSettings(viewer.role)) { return NextResponse.json({ error: "Nur AG Orga darf Zuständigkeiten und Benachrichtigungen ändern." }, { status: 403 }); } const existingSettings = await getAppSettings(); const previousSnapshot = snapshotAppSettings(existingSettings); const appSettings = await prisma.appSettings.update({ where: { id: existingSettings.id }, data: { ...(parsed.data.approvalThreshold !== undefined ? { approvalThreshold: parsed.data.approvalThreshold } : {}), ...(parsed.data.requiredApprovalTypes !== undefined ? { requiredApprovalTypes: normalizeRequiredApprovalTypes(parsed.data.requiredApprovalTypes) } : {}), ...(parsed.data.budgetReleaseNotifyTarget !== undefined ? { budgetReleaseNotifyTarget: parsed.data.budgetReleaseNotifyTarget } : {}) } }); await createAuditLog(prisma, { actorId: viewer.id, action: "settings.update", entityType: "settings", entityId: appSettings.id, entityLabel: "Freigabe-Schwelle", summary: changesOrgaSettings ? "Zuständigkeiten und Benachrichtigungen wurden aktualisiert." : `Freigabe-Schwelle wurde auf ${toApprovalThresholdNumber(appSettings.approvalThreshold).toFixed(2)} EUR gesetzt.`, metadata: { settings: serializeAppSettings(appSettings), rollback: { kind: "settings.update", previous: previousSnapshot } } }); return NextResponse.json({ ok: true, settings: serializeAppSettings(appSettings) }); }