import { permissions } from "@mrp/shared"; import { Router } from "express"; import { z } from "zod"; import { fail, ok } from "../../lib/http.js"; import { requirePermissions } from "../../lib/rbac.js"; import { createAdminRole, createAdminUser, getAdminDiagnostics, listAdminPermissions, listAdminRoles, listAdminUsers, updateAdminRole, updateAdminUser, } from "./service.js"; export const adminRouter = Router(); const roleSchema = z.object({ name: z.string().trim().min(1).max(120), description: z.string(), permissionKeys: z.array(z.string().trim().min(1)), }); const userSchema = z.object({ email: z.string().email(), firstName: z.string().trim().min(1).max(120), lastName: z.string().trim().min(1).max(120), isActive: z.boolean(), roleIds: z.array(z.string().trim().min(1)), password: z.string().min(8).nullable(), }); function getRouteParam(value: unknown) { return typeof value === "string" ? value : null; } adminRouter.get("/diagnostics", requirePermissions([permissions.adminManage]), async (_request, response) => { return ok(response, await getAdminDiagnostics()); }); adminRouter.get("/permissions", requirePermissions([permissions.adminManage]), async (_request, response) => { return ok(response, await listAdminPermissions()); }); adminRouter.get("/roles", requirePermissions([permissions.adminManage]), async (_request, response) => { return ok(response, await listAdminRoles()); }); adminRouter.post("/roles", requirePermissions([permissions.adminManage]), async (request, response) => { const parsed = roleSchema.safeParse(request.body); if (!parsed.success) { return fail(response, 400, "INVALID_INPUT", "Role payload is invalid."); } const result = await createAdminRole(parsed.data, request.authUser?.id); if (!result.ok) { return fail(response, 400, "INVALID_INPUT", result.reason); } return ok(response, result.role, 201); }); adminRouter.put("/roles/:roleId", requirePermissions([permissions.adminManage]), async (request, response) => { const roleId = getRouteParam(request.params.roleId); if (!roleId) { return fail(response, 400, "INVALID_INPUT", "Role id is invalid."); } const parsed = roleSchema.safeParse(request.body); if (!parsed.success) { return fail(response, 400, "INVALID_INPUT", "Role payload is invalid."); } const result = await updateAdminRole(roleId, parsed.data, request.authUser?.id); if (!result.ok) { return fail(response, 400, "INVALID_INPUT", result.reason); } return ok(response, result.role); }); adminRouter.get("/users", requirePermissions([permissions.adminManage]), async (_request, response) => { return ok(response, await listAdminUsers()); }); adminRouter.post("/users", requirePermissions([permissions.adminManage]), async (request, response) => { const parsed = userSchema.safeParse(request.body); if (!parsed.success) { return fail(response, 400, "INVALID_INPUT", "User payload is invalid."); } const result = await createAdminUser(parsed.data, request.authUser?.id); if (!result.ok) { return fail(response, 400, "INVALID_INPUT", result.reason); } return ok(response, result.user, 201); }); adminRouter.put("/users/:userId", requirePermissions([permissions.adminManage]), async (request, response) => { const userId = getRouteParam(request.params.userId); if (!userId) { return fail(response, 400, "INVALID_INPUT", "User id is invalid."); } const parsed = userSchema.safeParse(request.body); if (!parsed.success) { return fail(response, 400, "INVALID_INPUT", "User payload is invalid."); } const result = await updateAdminUser(userId, parsed.data, request.authUser?.id); if (!result.ok) { return fail(response, 400, "INVALID_INPUT", result.reason); } return ok(response, result.user); });