aether-framework/resources/[aether]/aether-admin/server/kern.lua
Jerrit Fritzsche e4b82dd685 Aether-Framework: Fachmodule, Admin-Panel und Docker-Datenbank
- aether-medical: Stationen/Belegung, Intensivstation, Blutbank, Fuhrpark,
  Nachrichten/Aushänge, Berichte und Textbausteine (server + NUI)
- aether-admin: vollständiges Server-Admin-Panel als echtes FiveM-Resource,
  an aether-core gekoppelt (Rechte über aether_users.admin_group), mit
  WebRTC-Live-Kameras (Bildschirmfreigabe) und separatem Media-Server (SFU)
- Prototypen admin/ vervollständigt
- SQL-Schema aether_admin.sql
- Docker-Compose mit MariaDB und idempotenter Auto-Migration (schema_migrations)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:55:32 +02:00

90 lines
3.2 KiB
Lua

-- =====================================================================
-- aether-admin — Kern
--
-- Ein einziger Weg führt von der Oberfläche zu einer Aktion: `aufruf`.
-- Der Kern nimmt ihn entgegen, prüft das Recht anhand der Rechte-Matrix
-- und ruft die registrierte Funktion. Jedes Fachmodul meldet nur seine
-- Aktionen an — die Prüfung passiert hier, an einer Stelle, für alle.
-- =====================================================================
Admin = Admin or {}
Admin.Kern = {}
-- Registrierte Aktionen: ['modul.aktion'] = funktion
local aktionen = {}
--- Registriert eine Aktion.
--- @param modul string Modulkennung (z. B. 'spieler')
--- @param aktion string Aktionsname (z. B. 'kick')
--- @param funktion function fun(handelnder, daten): ergebnis, fehler
function Admin.Kern.Registriere(modul, aktion, funktion)
aktionen[modul .. '.' .. aktion] = funktion
end
--- Führt eine Aktion aus — inklusive Rechteprüfung.
--- @param quelle number Server-ID des Admins
--- @param modul string
--- @param aktion string
--- @param daten table Nutzdaten
--- @return any Ergebnis, string|nil Fehler
function Admin.Kern.FuehreAus(quelle, modul, aktion, daten)
local schluessel = tostring(modul) .. '.' .. tostring(aktion)
local funktion = aktionen[schluessel]
if not funktion then
return nil, 'Unbekannte Aktion.'
end
-- Panel-Grundrecht
if not Admin.Auth.DarfOeffnen(quelle) then
return nil, 'Kein Zugriff auf das Admin-Panel.'
end
-- Recht auf genau diese Aktion
local benoetigt = AdminConfig.RechtFuer(schluessel)
if not Admin.Auth.Hat(quelle, benoetigt) then
return nil, ('Dafür fehlt dir die Berechtigung (%s).'):format(benoetigt)
end
local handelnder = Admin.Auth.Handelnder(quelle)
local erfolg, ergebnis, fehler = pcall(funktion, handelnder, daten or {})
if not erfolg then
print(('[aether-admin] Fehler in %s: %s'):format(schluessel, tostring(ergebnis)))
return nil, 'Interner Fehler in der Aktion.'
end
return ergebnis, fehler
end
--- Liefert die für einen Admin sichtbaren Sektionen (nach Gruppe gefiltert)
--- @param quelle number
--- @return table Liste { id, label, icon, grp }
function Admin.Kern.SichtbareSektionen(quelle)
local gruppe = Admin.Auth.Gruppe(quelle)
local liste = {}
for _, eintrag in ipairs(AdminConfig.Sektionen) do
if eintrag.grp then
liste[#liste + 1] = { grp = eintrag.grp }
elseif AdminConfig.Erfuellt(gruppe, eintrag.min) then
liste[#liste + 1] = {
id = eintrag.id, label = eintrag.label, icon = eintrag.icon,
}
end
end
return liste
end
--- Baut das Rechte-Abbild für die Oberfläche: welche Aktionen darf dieser
--- Admin? Die UI blendet danach Knöpfe aus — die echte Prüfung bleibt aber
--- serverseitig. Das hier ist nur Kosmetik, kein Torwächter.
--- @param quelle number
--- @return table { ['modul.aktion'] = true, ... }
function Admin.Kern.RechteAbbild(quelle)
local gruppe = Admin.Auth.Gruppe(quelle)
local abbild = {}
for schluessel, benoetigt in pairs(AdminConfig.Rechte) do
abbild[schluessel] = AdminConfig.Erfuellt(gruppe, benoetigt)
end
return abbild
end