import { NextResponse } from "next/server"; import bcrypt from "bcryptjs"; import { prisma } from "../../../lib/prisma"; import { isAdminSession, isSuperAdminSession, requireSession } from "../../../lib/auth-helpers"; export async function GET(request: Request) { const { session } = await requireSession(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } if (!isAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const { searchParams } = new URL(request.url); const status = searchParams.get("status"); const users = await prisma.user.findMany({ where: status ? { status } : undefined, orderBy: { createdAt: "desc" }, select: { id: true, email: true, name: true, status: true, role: true, emailVerified: true, createdAt: true } }); if (!isSuperAdminSession(session)) { return NextResponse.json(users); } const emails = users.map((user) => user.email).filter(Boolean); const attempts = emails.length ? await prisma.loginAttempt.findMany({ where: { email: { in: emails } } }) : []; const stats = attempts.reduce>((acc, attempt) => { const current = acc[attempt.email] || { attempts: 0, lastAttempt: null, lockedUntil: null }; current.attempts += attempt.attempts; if (!current.lastAttempt || attempt.lastAttempt > current.lastAttempt) { current.lastAttempt = attempt.lastAttempt; } if (!current.lockedUntil || (attempt.lockedUntil && attempt.lockedUntil > current.lockedUntil)) { current.lockedUntil = attempt.lockedUntil; } acc[attempt.email] = current; return acc; }, {}); const enriched = users.map((user) => ({ ...user, loginStats: stats[user.email] || { attempts: 0, lastAttempt: null, lockedUntil: null } })); return NextResponse.json(enriched); } export async function POST(request: Request) { const { session } = await requireSession(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } if (!isAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const body = await request.json(); const { email, name, password, role, status, emailVerified } = body || {}; if (!email || !password) { return NextResponse.json( { error: "E-Mail und Passwort sind erforderlich." }, { status: 400 } ); } const normalizedEmail = String(email).trim().toLowerCase(); const allowedRoles = ["USER", "ADMIN", "SUPERADMIN"]; const allowedStatuses = ["ACTIVE", "PENDING", "DISABLED"]; const isSuperAdmin = isSuperAdminSession(session); const nextRole = isSuperAdmin && allowedRoles.includes(role) ? role : "USER"; const nextStatus = allowedStatuses.includes(status) ? status : "PENDING"; if (!normalizedEmail) { return NextResponse.json({ error: "Ungültige E-Mail." }, { status: 400 }); } const passwordHash = await bcrypt.hash(String(password), 10); try { const user = await prisma.user.create({ data: { email: normalizedEmail, name: name ? String(name).trim() : null, passwordHash, role: nextRole, status: nextStatus, emailVerified: Boolean(emailVerified) }, select: { id: true, email: true, name: true, role: true, status: true, emailVerified: true, createdAt: true } }); return NextResponse.json(user, { status: 201 }); } catch (err) { return NextResponse.json( { error: "Benutzer konnte nicht angelegt werden." }, { status: 400 } ); } } export async function PATCH(request: Request) { const { session } = await requireSession(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } if (!isAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const body = await request.json(); const { userId, status, role, name, email, password, emailVerified, resetLoginAttempts } = body || {}; if (!userId) { return NextResponse.json({ error: "Ungültige Anfrage." }, { status: 400 }); } const target = await prisma.user.findUnique({ where: { id: userId }, select: { role: true } }); if (!target) { return NextResponse.json({ error: "Benutzer nicht gefunden." }, { status: 404 }); } if (resetLoginAttempts) { if (!isSuperAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const userRecord = await prisma.user.findUnique({ where: { id: userId }, select: { email: true } }); if (userRecord?.email) { await prisma.loginAttempt.deleteMany({ where: { email: userRecord.email } }); } return NextResponse.json({ ok: true }); } if (target.role === "SUPERADMIN" && !isSuperAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const allowedStatuses = ["ACTIVE", "PENDING", "DISABLED"]; const data: Record = {}; if (status) { if (!allowedStatuses.includes(status)) { return NextResponse.json({ error: "Ungültiger Status." }, { status: 400 }); } data.status = status; } if (name !== undefined) { data.name = name ? String(name).trim() : null; } if (email) { data.email = String(email).trim().toLowerCase(); } if (emailVerified !== undefined) { data.emailVerified = Boolean(emailVerified); } if (password) { data.passwordHash = await bcrypt.hash(String(password), 10); } if (role) { if (!isSuperAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } if (!["USER", "ADMIN", "SUPERADMIN"].includes(role)) { return NextResponse.json({ error: "Ungültige Rolle." }, { status: 400 }); } data.role = role; } const user = await prisma.user.update({ where: { id: userId }, data, select: { id: true, email: true, name: true, role: true, status: true, emailVerified: true, createdAt: true } }); return NextResponse.json({ id: user.id, status: user.status }); } export async function DELETE(request: Request) { const { session } = await requireSession(); if (!session) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } if (!isAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } const { searchParams } = new URL(request.url); const userId = searchParams.get("id"); if (!userId) { return NextResponse.json({ error: "Ungültige Anfrage." }, { status: 400 }); } if (session.user?.id === userId) { return NextResponse.json( { error: "Eigenes Konto kann nicht gelöscht werden." }, { status: 400 } ); } const target = await prisma.user.findUnique({ where: { id: userId }, select: { role: true } }); if (!target) { return NextResponse.json({ error: "Benutzer nicht gefunden." }, { status: 404 }); } if (target.role !== "USER" && !isSuperAdminSession(session)) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } await prisma.session.deleteMany({ where: { userId } }); await prisma.account.deleteMany({ where: { userId } }); await prisma.user.update({ where: { id: userId }, data: { status: "DISABLED", emailVerified: false } }); return NextResponse.json({ ok: true }); }