google-labs-jules[bot] 589e146ecc feat(routes): decompose admin and auth monolith routes
Extracted domain-specific sub-routers from monolithic `server/routes/admin.ts` and `server/routes/auth.ts` into isolated modules within `server/routes/admin/` and `server/routes/auth/` respectively. The original entry routers were updated to import and assemble these sub-routers without breaking their current HTTP interface or rate limiting/authorization middleware. Testing and linting were run ensuring perfect functionality and 100% test passing score.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-26 04:37:26 +00:00

156 lines
4.7 KiB
TypeScript

import { Hono } from "jsr:@hono/hono@4";
import { sqlWrapper } from "../../db.ts";
import { auditWrapper } from "../../audit.ts";
import { getAuthenticatedUser } from "../../auth-session.ts";
import { getClientIp } from "../../middleware.ts";
export const rolesAdminRoutes = new Hono();
rolesAdminRoutes.get("/", async (c) => {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
const appId = c.req.query("appId");
let roles;
if (appId) {
roles = await sqlWrapper.sql`
SELECT r.id, r.name, r.description, r.app_id, r.created_at,
a.name AS app_name
FROM roles r
LEFT JOIN apps a ON r.app_id = a.id
WHERE r.app_id IS NULL OR r.app_id = ${appId}
ORDER BY r.app_id NULLS FIRST, r.name ASC
`;
} else {
roles = await sqlWrapper.sql`
SELECT r.id, r.name, r.description, r.app_id, r.created_at,
a.name AS app_name
FROM roles r
LEFT JOIN apps a ON r.app_id = a.id
ORDER BY r.app_id NULLS FIRST, r.name ASC
`;
}
return c.json({ roles });
});
rolesAdminRoutes.post("/", async (c) => {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
const { name, description, appId } = await c.req.json();
if (
!name || typeof name !== "string" || name.trim().length < 2 ||
name.trim().length > 32
) {
return c.json(
{ error: "Role name must be between 2 and 32 characters" },
400,
);
}
const normalizedName = name.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "_");
let validatedAppId = null;
if (appId && typeof appId === "string" && appId.trim()) {
const uuidRegex =
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
if (!uuidRegex.test(appId)) {
return c.json({ error: "Invalid App UUID" }, 400);
}
const appExists = await sqlWrapper
.sql`SELECT id, name FROM apps WHERE id = ${appId}`
.then((res: any) => res[0]);
if (!appExists) {
return c.json({ error: "Selected application does not exist" }, 404);
}
validatedAppId = appId;
}
try {
const newRole = await sqlWrapper.sql`
INSERT INTO roles (name, description, app_id)
VALUES (${normalizedName}, ${
description?.trim() || null
}, ${validatedAppId})
RETURNING id, name, description, app_id, created_at
`.then((res: any) => res[0]);
auditWrapper.auditLog(auth.userId, "role_created", validatedAppId, {
role_name: newRole.name,
scope: validatedAppId ? "app-specific" : "global",
}, getClientIp(c));
return c.json({ success: true, role: newRole });
} catch (err: any) {
if (err.code === "23505") {
return c.json({
error: "This role already exists for the selected scope",
}, 409);
}
return c.json({ error: "Failed to create role" }, 500);
}
});
rolesAdminRoutes.put("/:id", async (c) => {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
const roleId = c.req.param("id");
const { name, description } = await c.req.json();
if (!name || typeof name !== "string" || name.trim().length < 2) {
return c.json({ error: "Role name must be at least 2 characters" }, 400);
}
const normalizedName = name.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "_");
try {
const updatedRole = await sqlWrapper.sql`
UPDATE roles
SET name = ${normalizedName},
description = ${description?.trim() || null}
WHERE id = ${roleId}
RETURNING id, name, description, app_id, created_at
`.then((res: any) => res[0]);
if (!updatedRole) return c.json({ error: "Role not found" }, 404);
auditWrapper.auditLog(auth.userId, "role_updated", updatedRole.app_id, {
role_name: updatedRole.name,
}, getClientIp(c));
return c.json({ success: true, role: updatedRole });
} catch (_err: any) {
return c.json({ error: "Failed to update role" }, 500);
}
});
rolesAdminRoutes.delete("/:id", async (c) => {
const auth = await getAuthenticatedUser(c);
if (!auth) return c.json({ error: "Unauthorized" }, 401);
const roleId = c.req.param("id");
const role = await sqlWrapper
.sql`SELECT id, name, app_id FROM roles WHERE id = ${roleId}`.then(
(res: any) => res[0],
);
if (!role) {
return c.json({ error: "Role not found" }, 404);
}
if (role.name === "admin" && role.app_id === null) {
return c.json({ error: "The global 'admin' role cannot be deleted" }, 400);
}
await sqlWrapper.sql`DELETE FROM roles WHERE id = ${roleId}`;
auditWrapper.auditLog(
auth.userId,
"role_deleted",
role.app_id,
{ role_name: role.name },
getClientIp(c),
);
return c.json({ success: true });
});