"Mein Konto": Profil, Passwort setzen oder wechseln, Passkeys anlegen, umbenennen und entfernen, aktive Sitzungen einsehen und ueberall abmelden. Der letzte Passkey laesst sich nicht entfernen, solange kein Passwort gesetzt ist - sonst waere das Konto ausgesperrt. Admin-Einstellungen: Betriebsart umschalten, Selbstregistrierung freigeben, Konten anlegen, bearbeiten, deaktivieren und loeschen. Die Instanzwerte aus der .env werden angezeigt, damit sichtbar ist, warum Passkeys gegebenenfalls nicht verfuegbar sind. Schutzregeln: - Der Wechsel in den Einzelbetrieb wird abgelehnt, solange mehr als ein Konto existiert. - Der letzte aktive Administrator kann weder herabgestuft noch deaktiviert oder geloescht werden. - Das eigene Konto laesst sich nicht loeschen oder deaktivieren. - Deaktivieren oder ein neues Passwort beenden sofort alle Sitzungen des Kontos. Administratoren verwalten Konten, keine Inhalte: fremde Projekte sehen auch sie nicht. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { requireUserApi } from "@/lib/auth/guard";
|
|
import { prisma } from "@/lib/db";
|
|
import { readJsonBody } from "@/lib/security/request";
|
|
import { formatZodError, profileUpdateSchema } from "@/lib/validation";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export async function PATCH(request: Request) {
|
|
const auth = await requireUserApi();
|
|
if (!auth.ok) return auth.response;
|
|
|
|
const body = await readJsonBody(request);
|
|
if (!body.ok) return body.response;
|
|
|
|
const parsed = profileUpdateSchema.safeParse(body.data);
|
|
if (!parsed.success) {
|
|
return NextResponse.json(
|
|
{ error: "Validierung fehlgeschlagen", fields: formatZodError(parsed.error) },
|
|
{ status: 422 },
|
|
);
|
|
}
|
|
|
|
const { displayName, email } = parsed.data;
|
|
|
|
if (email) {
|
|
const taken = await prisma.user.findFirst({
|
|
where: { email, NOT: { id: auth.user.id } },
|
|
select: { id: true },
|
|
});
|
|
if (taken) {
|
|
return NextResponse.json(
|
|
{ error: "Diese E-Mail-Adresse wird bereits verwendet.", fields: { email: "Bereits vergeben" } },
|
|
{ status: 409 },
|
|
);
|
|
}
|
|
}
|
|
|
|
const user = await prisma.user.update({
|
|
where: { id: auth.user.id },
|
|
data: {
|
|
...(displayName !== undefined ? { displayName } : {}),
|
|
...(email !== undefined ? { email } : {}),
|
|
},
|
|
select: { id: true, username: true, displayName: true, email: true, role: true },
|
|
});
|
|
|
|
return NextResponse.json({ user });
|
|
}
|