aether-framework/resources/[aether]/aether-admin/server/module/reports.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

115 lines
4.4 KiB
Lua

-- =====================================================================
-- aether-admin / Modul: Reports / Support
--
-- Spieler melden über `/report` — das Team übernimmt, antwortet und
-- schließt hier. Antworten gehen als Hinweis zurück an den Melder,
-- falls er online ist.
-- =====================================================================
Admin = Admin or {}
--- Legt einen Report an (aus dem Spiel heraus aufgerufen)
--- @param quelle number Server-ID des Melders
--- @param betreff string
--- @param nachricht string|nil
--- @return number Report-ID
function Admin.ErstelleReport(quelle, betreff, nachricht)
local id = MySQL.insert.await([[
INSERT INTO aether_admin_reports (melder_license, melder_name, betreff, nachricht)
VALUES (?, ?, ?, ?)
]], { Admin.Auth.Lizenz(quelle), GetPlayerName(quelle),
tostring(betreff):sub(1, 160), nachricht and tostring(nachricht):sub(1, 2000) or nil })
-- Team im Dienst benachrichtigen
for _, sid in ipairs(GetPlayers() or {}) do
local s = tonumber(sid)
if Admin.Auth.Hat(s, 'support') then
TriggerClientEvent('aether-admin:client:hinweis', s,
'🎫 Neuer Report von ' .. GetPlayerName(quelle))
end
end
return id
end
Admin.Kern.Registriere('reports', 'laden', function(handelnder, daten)
local liste = MySQL.query.await([[
SELECT id, melder_name, betreff, nachricht, prioritaet, status, bearbeiter,
erstellt_am, aktualisiert_am
FROM aether_admin_reports
ORDER BY (status = 'geschlossen'), prioritaet, id DESC
LIMIT 100
]]) or {}
-- Für ein offenes Detail: Nachrichtenverlauf mitliefern
local detailId = tonumber(daten.detail)
local verlauf = {}
if detailId then
verlauf = MySQL.query.await([[
SELECT autor, ist_admin, nachricht, erstellt_am
FROM aether_admin_report_msgs WHERE report = ? ORDER BY id
]], { detailId }) or {}
end
return { reports = liste, verlauf = verlauf, detail = detailId,
rechte = Admin.Kern.RechteAbbild(handelnder.quelle) }
end)
Admin.Kern.Registriere('reports', 'claim', function(handelnder, daten)
local id = tonumber(daten.id)
if not id then return nil, 'Ungültige Kennung.' end
MySQL.update.await([[
UPDATE aether_admin_reports SET status = 'bearbeitung', bearbeiter = ?
WHERE id = ? AND status <> 'geschlossen'
]], { handelnder.name, id })
Admin.Log.Schreibe(handelnder, 'Report übernommen', 'Report #' .. id)
return { ok = true }
end)
Admin.Kern.Registriere('reports', 'status', function(handelnder, daten)
local id = tonumber(daten.id)
local status = tostring(daten.status or '')
local erlaubt = { offen = true, bearbeitung = true, geschlossen = true }
if not id or not erlaubt[status] then return nil, 'Ungültige Angabe.' end
MySQL.update.await('UPDATE aether_admin_reports SET status = ? WHERE id = ?', { status, id })
Admin.Log.Schreibe(handelnder, 'Report ' .. status, 'Report #' .. id)
return { ok = true }
end)
Admin.Kern.Registriere('reports', 'antwort', function(handelnder, daten)
local id = tonumber(daten.id)
local text = tostring(daten.text or ''):sub(1, 2000)
if not id then return nil, 'Ungültige Kennung.' end
if #text < 2 then return nil, 'Bitte eine Antwort schreiben.' end
local report = MySQL.query.await(
'SELECT melder_license, status FROM aether_admin_reports WHERE id = ?', { id })
if not report or not report[1] then return nil, 'Report nicht gefunden.' end
MySQL.insert.await([[
INSERT INTO aether_admin_report_msgs (report, autor, ist_admin, nachricht)
VALUES (?, ?, 1, ?)
]], { id, handelnder.name, text })
if report[1].status == 'offen' then
MySQL.update.await(
"UPDATE aether_admin_reports SET status = 'bearbeitung', bearbeiter = ? WHERE id = ?",
{ handelnder.name, id })
end
-- Melder benachrichtigen, falls online
local melderQuelle
for _, sid in ipairs(GetPlayers() or {}) do
if Admin.Auth.Lizenz(tonumber(sid)) == report[1].melder_license then
melderQuelle = tonumber(sid); break
end
end
if melderQuelle then
TriggerClientEvent('aether-admin:client:hinweis', melderQuelle,
'🎫 Antwort vom Team: ' .. text:sub(1, 120))
end
Admin.Log.Schreibe(handelnder, 'Report beantwortet', 'Report #' .. id)
return { ok = true }
end)