120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
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);
|
|
});
|