Files
mrp/server/src/modules/admin/router.ts

130 lines
4.1 KiB
TypeScript
Raw Normal View History

2026-03-15 14:11:21 -05:00
import { permissions } from "@mrp/shared";
import { Router } from "express";
2026-03-15 14:47:58 -05:00
import { z } from "zod";
2026-03-15 14:11:21 -05:00
2026-03-15 14:47:58 -05:00
import { fail, ok } from "../../lib/http.js";
2026-03-15 14:11:21 -05:00
import { requirePermissions } from "../../lib/rbac.js";
2026-03-15 14:47:58 -05:00
import {
createAdminRole,
createAdminUser,
2026-03-15 15:04:18 -05:00
getBackupGuidance,
2026-03-15 14:47:58 -05:00
getAdminDiagnostics,
2026-03-15 15:04:18 -05:00
getSupportSnapshot,
2026-03-15 14:47:58 -05:00
listAdminPermissions,
listAdminRoles,
listAdminUsers,
updateAdminRole,
updateAdminUser,
} from "./service.js";
2026-03-15 14:11:21 -05:00
export const adminRouter = Router();
2026-03-15 14:47:58 -05:00
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;
}
2026-03-15 14:11:21 -05:00
adminRouter.get("/diagnostics", requirePermissions([permissions.adminManage]), async (_request, response) => {
return ok(response, await getAdminDiagnostics());
});
2026-03-15 14:47:58 -05:00
2026-03-15 15:04:18 -05:00
adminRouter.get("/backup-guidance", requirePermissions([permissions.adminManage]), async (_request, response) => {
return ok(response, getBackupGuidance());
});
adminRouter.get("/support-snapshot", requirePermissions([permissions.adminManage]), async (_request, response) => {
return ok(response, await getSupportSnapshot());
});
2026-03-15 14:47:58 -05:00
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);
});