Vollständiges Zugangs-/Rollen-/Rechtesystem gebaut (Anforderungsdokument): D1-Datenbank, AES-verschlüsselte Codes nur für Owner einsehbar, granulare Permissions, Session-Auth mit Lockout, Zugänge-&-Teammitglieder-Verwaltungsseite, Bewerbungen mit Status/Notizen/Entwürfen
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/* =====================================================================
|
||||
routes/roles.js — Rollen erstellen/umbenennen/verwalten
|
||||
|
||||
Die Owner-Rolle existiert absichtlich NICHT in dieser Tabelle — sie ist
|
||||
fest an POSTFACH_CODE gebunden und kann hier weder erstellt, verändert
|
||||
noch gelöscht werden (siehe Anforderungsdokument: "Meine persönliche
|
||||
Hauptadministrator-Rolle bleibt davon ausgeschlossen").
|
||||
===================================================================== */
|
||||
import { generateId, nowIso } from "../lib/crypto.js";
|
||||
import { isValidPermissionKey, hasPermission } from "../lib/permissions.js";
|
||||
import { logAction } from "../lib/audit.js";
|
||||
import { json } from "../lib/http.js";
|
||||
|
||||
function canManageRoles(session) {
|
||||
if (!session) return false;
|
||||
if (session.isOwner) return true;
|
||||
return (
|
||||
hasPermission(session.permissions, session.overrides, "TEAM_CREATE_ROLE") ||
|
||||
hasPermission(session.permissions, session.overrides, "TEAM_EDIT_PERMISSIONS")
|
||||
);
|
||||
}
|
||||
|
||||
function canViewRoles(session) {
|
||||
if (!session) return false;
|
||||
if (session.isOwner) return true;
|
||||
return (
|
||||
canManageRoles(session) ||
|
||||
hasPermission(session.permissions, session.overrides, "TEAM_ASSIGN_ROLE") ||
|
||||
hasPermission(session.permissions, session.overrides, "TEAM_VIEW")
|
||||
);
|
||||
}
|
||||
|
||||
function sanitizePermissions(list) {
|
||||
if (!Array.isArray(list)) return [];
|
||||
return [...new Set(list.filter((k) => typeof k === "string" && isValidPermissionKey(k)))];
|
||||
}
|
||||
|
||||
export async function listRoles(env, session) {
|
||||
if (!canViewRoles(session)) return json({ ok: false, error: "Keine Berechtigung." }, 403);
|
||||
const rows = await env.DB.prepare(`SELECT * FROM roles ORDER BY created_at ASC`).all();
|
||||
const roles = (rows.results || []).map((r) => ({ ...r, permissions: JSON.parse(r.permissions || "[]") }));
|
||||
return json({ ok: true, roles });
|
||||
}
|
||||
|
||||
export async function createRole(request, env, session) {
|
||||
if (!canManageRoles(session)) return json({ ok: false, error: "Keine Berechtigung." }, 403);
|
||||
const body = await request.json().catch(() => ({}));
|
||||
const name = String(body.name || "").trim().slice(0, 60);
|
||||
if (!name) return json({ ok: false, error: "Name fehlt." }, 400);
|
||||
const permissions = sanitizePermissions(body.permissions);
|
||||
const id = generateId();
|
||||
|
||||
await env.DB.prepare(`INSERT INTO roles (id, name, permissions, created_at) VALUES (?, ?, ?, ?)`)
|
||||
.bind(id, name, JSON.stringify(permissions), nowIso())
|
||||
.run();
|
||||
|
||||
await logAction(env, session.actor, "role.create", id, { name, permissions });
|
||||
return json({ ok: true, role: { id, name, permissions } });
|
||||
}
|
||||
|
||||
export async function updateRole(request, env, session) {
|
||||
if (!canManageRoles(session)) return json({ ok: false, error: "Keine Berechtigung." }, 403);
|
||||
const body = await request.json().catch(() => ({}));
|
||||
const id = String(body.id || "");
|
||||
if (!id) return json({ ok: false, error: "id fehlt." }, 400);
|
||||
|
||||
const existing = await env.DB.prepare(`SELECT * FROM roles WHERE id = ?`).bind(id).first();
|
||||
if (!existing) return json({ ok: false, error: "Rolle nicht gefunden." }, 404);
|
||||
|
||||
const name = body.name !== undefined ? String(body.name).trim().slice(0, 60) || existing.name : existing.name;
|
||||
const permissions = body.permissions !== undefined ? sanitizePermissions(body.permissions) : JSON.parse(existing.permissions || "[]");
|
||||
|
||||
await env.DB.prepare(`UPDATE roles SET name = ?, permissions = ? WHERE id = ?`)
|
||||
.bind(name, JSON.stringify(permissions), id)
|
||||
.run();
|
||||
|
||||
await logAction(env, session.actor, "role.update", id, { name, permissions });
|
||||
return json({ ok: true });
|
||||
}
|
||||
|
||||
export async function deleteRole(request, env, session) {
|
||||
if (!canManageRoles(session)) return json({ ok: false, error: "Keine Berechtigung." }, 403);
|
||||
const body = await request.json().catch(() => ({}));
|
||||
const id = String(body.id || "");
|
||||
if (!id) return json({ ok: false, error: "id fehlt." }, 400);
|
||||
|
||||
const inUse = await env.DB.prepare(`SELECT COUNT(*) as n FROM users WHERE role_id = ?`).bind(id).first();
|
||||
if (inUse && inUse.n > 0) {
|
||||
return json({ ok: false, error: "Rolle ist noch Personen zugewiesen — erst umziehen." }, 400);
|
||||
}
|
||||
|
||||
await env.DB.prepare(`DELETE FROM roles WHERE id = ?`).bind(id).run();
|
||||
await logAction(env, session.actor, "role.delete", id, null);
|
||||
return json({ ok: true });
|
||||
}
|
||||
Reference in New Issue
Block a user