import { NextRequest, NextResponse } from 'next/server' import { getUserFromRequest, getAllUsers, createUser, updateUser, deleteUser, getUserById, requireRole } from '@/lib/auth' import { logAuditEvent } from '@/lib/db' import { validateBody, createUserSchema } from '@/lib/validation' import { mutationLimiter } from '@/lib/rate-limit' import { logger } from '@/lib/logger' /** * GET /api/auth/users - List all users (admin only) */ export async function GET(request: NextRequest) { const auth = requireRole(request, 'viewer') if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status }) const user = getUserFromRequest(request) if (!user || user.role !== 'admin') { return NextResponse.json({ error: 'Admin access required' }, { status: 403 }) } const users = getAllUsers() const workspaceId = user.workspace_id ?? 1 return NextResponse.json({ users: users.filter((u) => (u.workspace_id ?? 1) === workspaceId) }) } /** * POST /api/auth/users - Create a new user (admin only) */ export async function POST(request: NextRequest) { const currentUser = getUserFromRequest(request) if (!currentUser || currentUser.role !== 'admin') { return NextResponse.json({ error: 'Admin access required' }, { status: 403 }) } const rateCheck = mutationLimiter(request) if (rateCheck) return rateCheck try { const result = await validateBody(request, createUserSchema) if ('error' in result) return result.error const { username, password, display_name, role, provider, email } = result.data const workspaceId = currentUser.workspace_id ?? 1 const newUser = createUser(username, password, display_name || username, role, { provider, email: email || null, workspace_id: workspaceId, }) const ipAddress = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown' logAuditEvent({ action: 'user_create', actor: currentUser.username, actor_id: currentUser.id, target_type: 'user', target_id: newUser.id, detail: { username, role, provider, email }, ip_address: ipAddress, }) return NextResponse.json({ user: { id: newUser.id, username: newUser.username, display_name: newUser.display_name, role: newUser.role, provider: newUser.provider || 'local', email: newUser.email || null, avatar_url: newUser.avatar_url || null, is_approved: newUser.is_approved ?? 1, workspace_id: newUser.workspace_id ?? 1, tenant_id: newUser.tenant_id ?? 1, } }, { status: 201 }) } catch (error: any) { if (error.message?.includes('UNIQUE constraint failed')) { return NextResponse.json({ error: 'Username already exists' }, { status: 409 }) } logger.error({ err: error }, 'POST /api/auth/users error') return NextResponse.json({ error: 'Failed to create user' }, { status: 500 }) } } /** * PUT /api/auth/users - Update a user (admin only) */ export async function PUT(request: NextRequest) { const currentUser = getUserFromRequest(request) if (!currentUser || currentUser.role !== 'admin') { return NextResponse.json({ error: 'Admin access required' }, { status: 403 }) } try { const { id, display_name, role, password, is_approved, email, avatar_url } = await request.json() const userId = parseInt(String(id)) if (!id || Number.isNaN(userId)) { return NextResponse.json({ error: 'User ID is required' }, { status: 400 }) } if (role && !['admin', 'operator', 'viewer'].includes(role)) { return NextResponse.json({ error: 'Invalid role' }, { status: 400 }) } // Prevent demoting yourself if (userId === currentUser.id && role && role !== currentUser.role) { return NextResponse.json({ error: 'Cannot change your own role' }, { status: 400 }) } const workspaceId = currentUser.workspace_id ?? 1 const existing = getUserById(userId) if (!existing || (existing.workspace_id ?? 1) !== workspaceId) { return NextResponse.json({ error: 'User not found' }, { status: 404 }) } const updated = updateUser(userId, { display_name, role, password: password || undefined, is_approved, email, avatar_url }) if (!updated) { return NextResponse.json({ error: 'User not found' }, { status: 404 }) } const ipAddress = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown' logAuditEvent({ action: 'user_update', actor: currentUser.username, actor_id: currentUser.id, target_type: 'user', target_id: userId, detail: { display_name, role, password_changed: !!password, is_approved }, ip_address: ipAddress, }) return NextResponse.json({ user: { id: updated.id, username: updated.username, display_name: updated.display_name, role: updated.role, provider: updated.provider || 'local', email: updated.email || null, avatar_url: updated.avatar_url || null, is_approved: updated.is_approved ?? 1, workspace_id: updated.workspace_id ?? 1, tenant_id: updated.tenant_id ?? 1, } }) } catch (error) { logger.error({ err: error }, 'PUT /api/auth/users error') return NextResponse.json({ error: 'Failed to update user' }, { status: 500 }) } } /** * DELETE /api/auth/users - Delete a user (admin only) */ export async function DELETE(request: NextRequest) { const currentUser = getUserFromRequest(request) if (!currentUser || currentUser.role !== 'admin') { return NextResponse.json({ error: 'Admin access required' }, { status: 403 }) } let body: any try { body = await request.json() } catch { return NextResponse.json({ error: 'Request body required' }, { status: 400 }) } const id = body.id if (!id) { return NextResponse.json({ error: 'User ID is required' }, { status: 400 }) } const userId = parseInt(id) // Prevent deleting yourself if (userId === currentUser.id) { return NextResponse.json({ error: 'Cannot delete your own account' }, { status: 400 }) } const workspaceId = currentUser.workspace_id ?? 1 const existing = getUserById(userId) if (!existing || (existing.workspace_id ?? 1) !== workspaceId) { return NextResponse.json({ error: 'User not found' }, { status: 404 }) } const deleted = deleteUser(userId) if (!deleted) { return NextResponse.json({ error: 'User not found' }, { status: 404 }) } const ipAddress = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip') || 'unknown' logAuditEvent({ action: 'user_delete', actor: currentUser.username, actor_id: currentUser.id, target_type: 'user', target_id: userId, ip_address: ipAddress, }) return NextResponse.json({ success: true }) }