Files
DogFatherGit e87aca3019 Postfach/Team-Verwaltung/Supporter-Abo als Node.js/Express-Server portiert
Vollständiger 1:1-Port des cloudflare-worker/ (dogfather-universe-postfach)
auf server-internal/: Bewerbungs-Postfach mit Rollen/Rechten, Team-
Zugangsverwaltung (verschlüsselte Owner-only-Codes), DogiCrew-Supporter-Abo
(PayPal Subscriptions, Google-Login, Resend-E-Mail, 30-Monats-Prämienzyklus)
und automatische TikTok-Live-Erkennung. D1 -> better-sqlite3, Cloudflare-
Cron -> node-cron. Läuft ohne gesetzte Secrets weiter (PayPal/Google/Resend/
Ticketanizer/Discord bleiben "nicht konfiguriert" statt kaputt), bis die
echten Zugangsdaten eingetragen werden.
2026-08-05 18:57:19 +02:00

94 lines
4.1 KiB
JavaScript

/* =====================================================================
routes/roles.js — Rollen erstellen/umbenennen/verwalten. 1:1 portiert
aus cloudflare-worker/src/routes/roles.js.
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 { db } from "../db.js";
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(req, res, session) {
if (!canViewRoles(session)) return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
const rows = db.prepare(`SELECT * FROM roles ORDER BY created_at ASC`).all();
const roles = rows.map((r) => ({ ...r, permissions: JSON.parse(r.permissions || "[]") }));
return json(res, { ok: true, roles });
}
export async function createRole(req, res, session) {
if (!canManageRoles(session)) return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
const body = req.body || {};
const name = String(body.name || "").trim().slice(0, 60);
if (!name) return json(res, { ok: false, error: "Name fehlt." }, 400);
const permissions = sanitizePermissions(body.permissions);
const id = generateId();
db.prepare(`INSERT INTO roles (id, name, permissions, created_at) VALUES (?, ?, ?, ?)`).run(id, name, JSON.stringify(permissions), nowIso());
logAction(session.actor, "role.create", id, { name, permissions });
return json(res, { ok: true, role: { id, name, permissions } });
}
export async function updateRole(req, res, session) {
if (!canManageRoles(session)) return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
const body = req.body || {};
const id = String(body.id || "");
if (!id) return json(res, { ok: false, error: "id fehlt." }, 400);
const existing = db.prepare(`SELECT * FROM roles WHERE id = ?`).get(id);
if (!existing) return json(res, { 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 || "[]");
db.prepare(`UPDATE roles SET name = ?, permissions = ? WHERE id = ?`).run(name, JSON.stringify(permissions), id);
logAction(session.actor, "role.update", id, { name, permissions });
return json(res, { ok: true });
}
export async function deleteRole(req, res, session) {
if (!canManageRoles(session)) return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
const body = req.body || {};
const id = String(body.id || "");
if (!id) return json(res, { ok: false, error: "id fehlt." }, 400);
const inUse = db.prepare(`SELECT COUNT(*) as n FROM users WHERE role_id = ?`).get(id);
if (inUse && inUse.n > 0) {
return json(res, { ok: false, error: "Rolle ist noch Personen zugewiesen — erst umziehen." }, 400);
}
db.prepare(`DELETE FROM roles WHERE id = ?`).run(id);
logAction(session.actor, "role.delete", id, null);
return json(res, { ok: true });
}