- 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>
90 lines
3.2 KiB
Lua
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
|