- 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>
70 lines
2.4 KiB
Lua
70 lines
2.4 KiB
Lua
-- =====================================================================
|
|
-- aether-admin — Prüfprotokoll
|
|
--
|
|
-- Jede eingreifende Aktion hinterlässt eine Spur: wer, was, an wem,
|
|
-- mit welchem Detail. Einträge werden nur geschrieben und gelesen —
|
|
-- nie geändert oder entfernt.
|
|
-- =====================================================================
|
|
|
|
Admin = Admin or {}
|
|
Admin.Log = {}
|
|
|
|
--- Schreibt einen Protokolleintrag
|
|
--- @param handelnder table|nil { lizenz, name } — der Admin
|
|
--- @param aktion string Was getan wurde
|
|
--- @param ziel string|nil An wem / woran
|
|
--- @param detail string|nil Zusatz
|
|
function Admin.Log.Schreibe(handelnder, aktion, ziel, detail)
|
|
MySQL.insert([[
|
|
INSERT INTO aether_admin_log (admin_license, admin_name, aktion, ziel, detail)
|
|
VALUES (?, ?, ?, ?, ?)
|
|
]], {
|
|
handelnder and handelnder.lizenz or nil,
|
|
handelnder and handelnder.name or 'System',
|
|
aktion,
|
|
ziel and tostring(ziel):sub(1, 96) or nil,
|
|
detail and tostring(detail):sub(1, 512) or nil,
|
|
})
|
|
end
|
|
|
|
--- Liest Protokolleinträge mit einfachen Filtern
|
|
--- @param filter table { suche?, admin?, limit? }
|
|
--- @return table
|
|
function Admin.Log.Lies(filter)
|
|
filter = filter or {}
|
|
local bedingungen, werte = {}, {}
|
|
|
|
if filter.admin and filter.admin ~= '' then
|
|
bedingungen[#bedingungen + 1] = 'admin_name = ?'
|
|
werte[#werte + 1] = filter.admin
|
|
end
|
|
if filter.suche and filter.suche ~= '' then
|
|
local muster = '%' .. filter.suche .. '%'
|
|
bedingungen[#bedingungen + 1] = '(aktion LIKE ? OR ziel LIKE ? OR detail LIKE ?)'
|
|
werte[#werte + 1] = muster
|
|
werte[#werte + 1] = muster
|
|
werte[#werte + 1] = muster
|
|
end
|
|
|
|
local wo = #bedingungen > 0 and ('WHERE ' .. table.concat(bedingungen, ' AND ')) or ''
|
|
werte[#werte + 1] = math.min(tonumber(filter.limit) or 200, 500)
|
|
|
|
return MySQL.query.await(([[
|
|
SELECT admin_name, aktion, ziel, detail, erstellt_am
|
|
FROM aether_admin_log
|
|
%s
|
|
ORDER BY id DESC
|
|
LIMIT ?
|
|
]]):format(wo), werte) or {}
|
|
end
|
|
|
|
--- Liste der Admins, die je etwas protokolliert haben (für den Filter)
|
|
--- @return table
|
|
function Admin.Log.Admins()
|
|
local zeilen = MySQL.query.await(
|
|
'SELECT DISTINCT admin_name FROM aether_admin_log ORDER BY admin_name') or {}
|
|
local liste = {}
|
|
for _, z in ipairs(zeilen) do liste[#liste + 1] = z.admin_name end
|
|
return liste
|
|
end
|