import { NextResponse } from "next/server"; import { query, queryOne } from "@/lib/db"; import { hashPassword } from "@/lib/auth/password"; import { requireRole, UnauthorizedError, ForbiddenError } from "@/lib/auth/session"; import { isSameOrigin } from "@/lib/origin"; import type { Profile } from "@/lib/types"; // Benutzerverwaltung (nur Admin). async function requireAdmin(request: Request) { if (!isSameOrigin(request)) throw new ForbiddenError(); return requireRole(["admin"]); } function errorResponse(err: unknown) { if (err instanceof UnauthorizedError || err instanceof ForbiddenError) { return NextResponse.json({ error: "Nicht berechtigt." }, { status: 403 }); } return null; } export async function GET(request: Request) { try { await requireAdmin(request); } catch (err) { const res = errorResponse(err); if (res) return res; throw err; } const profiles = await query( "select id, email, full_name, role, password_auth_enabled, created_at from users order by created_at" ); return NextResponse.json(profiles); } export async function POST(request: Request) { let session; try { session = await requireAdmin(request); } catch (err) { const res = errorResponse(err); if (res) return res; throw err; } void session; const body = await request.json().catch(() => null); const { email, password, full_name, role } = body ?? {}; if (!email || !password || !["admin", "staff"].includes(role)) { return NextResponse.json({ error: "Ungültige Eingaben." }, { status: 400 }); } if (String(password).length < 8) { return NextResponse.json( { error: "Das Passwort muss mindestens 8 Zeichen lang sein." }, { status: 400 } ); } try { const user = await queryOne<{ id: string }>( `insert into users (email, password_hash, full_name, role) values ($1, $2, $3, $4) returning id`, [String(email).trim().toLowerCase(), hashPassword(password), full_name ?? "", role] ); return NextResponse.json({ id: user?.id }); } catch (err) { if (err instanceof Error && /unique/i.test(err.message)) { return NextResponse.json( { error: "Diese E-Mail-Adresse ist bereits registriert." }, { status: 400 } ); } throw err; } } export async function PATCH(request: Request) { let session; try { session = await requireAdmin(request); } catch (err) { const res = errorResponse(err); if (res) return res; throw err; } const body = await request.json().catch(() => null); const { id, full_name, role, password } = body ?? {}; if (!id || (role && !["admin", "staff"].includes(role))) { return NextResponse.json({ error: "Ungültige Eingaben." }, { status: 400 }); } // Der Admin darf sich nicht selbst die Admin-Rolle entziehen, // sonst sperrt er sich aus der Verwaltung aus. if (id === session.user.id && role === "staff") { return NextResponse.json( { error: "Du kannst dir nicht selbst die Admin-Rolle entziehen." }, { status: 400 } ); } if (password) { if (String(password).length < 8) { return NextResponse.json( { error: "Das Passwort muss mindestens 8 Zeichen lang sein." }, { status: 400 } ); } await query("update users set password_hash = $1 where id = $2", [ hashPassword(password), id, ]); } const fields: string[] = []; const values: unknown[] = []; if (typeof full_name === "string") { values.push(full_name); fields.push(`full_name = $${values.length}`); } if (role) { values.push(role); fields.push(`role = $${values.length}`); } if (fields.length > 0) { values.push(id); await query(`update users set ${fields.join(", ")} where id = $${values.length}`, values); } return NextResponse.json({ ok: true }); } export async function DELETE(request: Request) { let session; try { session = await requireAdmin(request); } catch (err) { const res = errorResponse(err); if (res) return res; throw err; } const body = await request.json().catch(() => null); const { id } = body ?? {}; if (!id) return NextResponse.json({ error: "Ungültige Eingaben." }, { status: 400 }); if (id === session.user.id) { return NextResponse.json( { error: "Du kannst dich nicht selbst löschen." }, { status: 400 } ); } await query("delete from users where id = $1", [id]); return NextResponse.json({ ok: true }); }