- 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>
151 lines
5.2 KiB
Lua
151 lines
5.2 KiB
Lua
-- =====================================================================
|
|
-- aether-admin — Datenbankzugriff (oxmysql)
|
|
--
|
|
-- Kapselt die wiederkehrenden Abfragen, die mehrere Fachmodule teilen:
|
|
-- Einstellungen, Benutzer-/Charakterdaten, Bans. Domänenspezifische
|
|
-- Abfragen (Reports, Warns, Immobilien …) liegen in ihren Modulen.
|
|
-- =====================================================================
|
|
|
|
Admin = Admin or {}
|
|
Admin.DB = {}
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Persistierte Einstellungen (Schlüssel/Wert)
|
|
-- ---------------------------------------------------------------------
|
|
|
|
--- Liest eine Einstellung als Text
|
|
--- @param schluessel string
|
|
--- @param standard any Rückfallwert
|
|
--- @return string
|
|
function Admin.DB.Einstellung(schluessel, standard)
|
|
local wert = MySQL.scalar.await(
|
|
'SELECT wert FROM aether_admin_settings WHERE schluessel = ?', { schluessel })
|
|
if wert == nil then return standard end
|
|
return wert
|
|
end
|
|
|
|
--- Liest eine Einstellung als Zahl
|
|
--- @param schluessel string
|
|
--- @param standard number
|
|
--- @return number
|
|
function Admin.DB.EinstellungZahl(schluessel, standard)
|
|
return tonumber(Admin.DB.Einstellung(schluessel, standard)) or standard or 0
|
|
end
|
|
|
|
--- Liest eine Einstellung als Schalter
|
|
--- @param schluessel string
|
|
--- @param standard boolean
|
|
--- @return boolean
|
|
function Admin.DB.EinstellungAn(schluessel, standard)
|
|
local wert = Admin.DB.Einstellung(schluessel, standard and '1' or '0')
|
|
return wert == '1' or wert == 'true' or wert == true
|
|
end
|
|
|
|
--- Schreibt eine Einstellung
|
|
--- @param schluessel string
|
|
--- @param wert any
|
|
function Admin.DB.SetzeEinstellung(schluessel, wert)
|
|
MySQL.prepare.await([[
|
|
INSERT INTO aether_admin_settings (schluessel, wert) VALUES (?, ?)
|
|
ON DUPLICATE KEY UPDATE wert = VALUES(wert)
|
|
]], { schluessel, tostring(wert) })
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Benutzer & Charaktere (aus aether-core)
|
|
-- ---------------------------------------------------------------------
|
|
|
|
--- Rechtegruppe eines Benutzers direkt aus der Datenbank
|
|
--- @param lizenz string
|
|
--- @return string
|
|
function Admin.DB.GruppeVonLizenz(lizenz)
|
|
local wert = MySQL.scalar.await(
|
|
'SELECT admin_group FROM aether_users WHERE license = ?', { lizenz })
|
|
return wert or 'user'
|
|
end
|
|
|
|
--- Setzt die Rechtegruppe eines Benutzers
|
|
--- @param lizenz string
|
|
--- @param gruppe string
|
|
--- @return boolean
|
|
function Admin.DB.SetzeGruppe(lizenz, gruppe)
|
|
local betroffen = MySQL.update.await(
|
|
'UPDATE aether_users SET admin_group = ? WHERE license = ?', { gruppe, lizenz })
|
|
return (betroffen or 0) > 0
|
|
end
|
|
|
|
--- Sucht einen Benutzer über Lizenz oder Namen
|
|
--- @param begriff string
|
|
--- @return table Liste
|
|
function Admin.DB.SucheBenutzer(begriff)
|
|
local muster = '%' .. begriff .. '%'
|
|
return MySQL.query.await([[
|
|
SELECT license, name, admin_group, is_banned
|
|
FROM aether_users
|
|
WHERE license = ? OR name LIKE ?
|
|
ORDER BY last_seen DESC
|
|
LIMIT 25
|
|
]], { begriff, muster }) or {}
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------
|
|
-- Bans · Durchsetzung in aether_users, Gedächtnis in aether_admin_bans
|
|
-- ---------------------------------------------------------------------
|
|
|
|
--- Sperrt einen Benutzer: setzt die Core-Felder und schreibt den Verlauf.
|
|
--- @param lizenz string|nil Lizenz (nil = nur Verlaufseintrag, Offline-Ban)
|
|
--- @param name string Anzeigename
|
|
--- @param grund string
|
|
--- @param bis string|nil DATETIME oder nil (dauerhaft)
|
|
--- @param adminLizenz string|nil
|
|
--- @param adminName string
|
|
--- @return number Ban-ID
|
|
function Admin.DB.Sperre(lizenz, name, grund, bis, adminLizenz, adminName)
|
|
if lizenz then
|
|
MySQL.update.await([[
|
|
UPDATE aether_users SET is_banned = 1, ban_reason = ?, ban_until = ?
|
|
WHERE license = ?
|
|
]], { grund, bis, lizenz })
|
|
end
|
|
|
|
return MySQL.insert.await([[
|
|
INSERT INTO aether_admin_bans
|
|
(license, name, grund, admin_license, admin_name, bis, aktiv)
|
|
VALUES (?, ?, ?, ?, ?, ?, 1)
|
|
]], { lizenz, name, grund, adminLizenz, adminName, bis })
|
|
end
|
|
|
|
--- Hebt einen Bann auf: löscht die Core-Sperre und markiert den Verlauf.
|
|
--- @param banId number
|
|
--- @param adminName string
|
|
--- @return boolean
|
|
function Admin.DB.Entsperre(banId, adminName)
|
|
local zeilen = MySQL.query.await(
|
|
'SELECT license FROM aether_admin_bans WHERE id = ? AND aktiv = 1', { banId })
|
|
if not zeilen or not zeilen[1] then return false end
|
|
|
|
if zeilen[1].license then
|
|
MySQL.update.await([[
|
|
UPDATE aether_users SET is_banned = 0, ban_reason = NULL, ban_until = NULL
|
|
WHERE license = ?
|
|
]], { zeilen[1].license })
|
|
end
|
|
|
|
MySQL.update.await([[
|
|
UPDATE aether_admin_bans
|
|
SET aktiv = 0, aufgehoben_am = NOW(), aufgehoben_von = ?
|
|
WHERE id = ?
|
|
]], { adminName, banId })
|
|
return true
|
|
end
|
|
|
|
--- Liste aktiver Bans
|
|
--- @return table
|
|
function Admin.DB.AktiveBans()
|
|
return MySQL.query.await([[
|
|
SELECT id, license, name, grund, admin_name, bis, erstellt_am
|
|
FROM aether_admin_bans WHERE aktiv = 1
|
|
ORDER BY id DESC LIMIT 200
|
|
]]) or {}
|
|
end
|