Files
nebula/src/app/api/admin/settings/route.ts
T
florian.wildeandClaude Opus 5 18ed4de9f9 feat(admin): Schwelle fuer den Stillstand einstellbar
Eigener Abschnitt mit der Schwelle von 14 Tagen bis zu einem Jahr, dem
Zeitpunkt der letzten Pruefung und der Zahl der Empfaenger. Steht die auf
null, sagt der Abschnitt das und verweist auf "Mein Konto".

Eine Aenderung der Schwelle setzt lastStaleCheckAt zurueck, damit sie beim
naechsten Tick greift und nicht erst in 24 Stunden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 10:55:15 +02:00

87 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextResponse } from "next/server";
import { requireAdminApi } from "@/lib/auth/guard";
import { getAppSettings } from "@/lib/auth/settings";
import { prisma } from "@/lib/db";
import { jsonError, readJsonBody } from "@/lib/security/request";
import { adminSettingsSchema, formatZodError } from "@/lib/validation";
export const dynamic = "force-dynamic";
export async function GET() {
const auth = await requireAdminApi();
if (!auth.ok) return auth.response;
const [settings, userCount] = await Promise.all([getAppSettings(), prisma.user.count()]);
return NextResponse.json({ settings, userCount });
}
export async function PATCH(request: Request) {
const auth = await requireAdminApi();
if (!auth.ok) return auth.response;
const body = await readJsonBody(request);
if (!body.ok) return body.response;
const parsed = adminSettingsSchema.safeParse(body.data);
if (!parsed.success) {
return NextResponse.json(
{ error: "Validierung fehlgeschlagen", fields: formatZodError(parsed.error) },
{ status: 422 },
);
}
const {
mode,
allowRegistration,
autoSyncEnabled,
autoSyncIntervalMinutes,
autoSyncActiveOnly,
autoSyncBatchSize,
staleAfterDays,
} = parsed.data;
// Der Wechsel in den Einzelbetrieb wuerde weitere Konten aussperren –
// deshalb nur erlauben, wenn es wirklich nur ein Konto gibt.
if (mode === "SINGLE_USER") {
const userCount = await prisma.user.count();
if (userCount > 1) {
return jsonError(
`Einzelbetrieb ist nicht moeglich, solange ${userCount} Konten existieren. ` +
"Bitte zuerst die uebrigen Konten entfernen.",
409,
);
}
}
const autoSyncFields = {
...(autoSyncEnabled !== undefined ? { autoSyncEnabled } : {}),
...(autoSyncIntervalMinutes !== undefined ? { autoSyncIntervalMinutes } : {}),
...(autoSyncActiveOnly !== undefined ? { autoSyncActiveOnly } : {}),
...(autoSyncBatchSize !== undefined ? { autoSyncBatchSize } : {}),
// Neue Schwelle: die Pruefung soll beim naechsten Tick greifen, nicht
// erst in 24 Stunden.
...(staleAfterDays !== undefined
? { staleAfterDays, lastStaleCheckAt: null }
: {}),
};
const settings = await prisma.appSettings.upsert({
where: { id: "singleton" },
create: {
id: "singleton",
...(mode ? { mode } : {}),
...(allowRegistration !== undefined ? { allowRegistration } : {}),
...autoSyncFields,
},
update: {
...(mode ? { mode } : {}),
...(allowRegistration !== undefined ? { allowRegistration } : {}),
// Im Einzelbetrieb ergibt eine offene Registrierung keinen Sinn.
...(mode === "SINGLE_USER" ? { allowRegistration: false } : {}),
...autoSyncFields,
},
});
return NextResponse.json({ settings });
}