- 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>
78 lines
3.2 KiB
Lua
78 lines
3.2 KiB
Lua
-- =====================================================================
|
|
-- aether-admin / Modul: Staatsprojekte
|
|
--
|
|
-- Projekte, über die (später aus einer Handy-App) abgestimmt wird. Ein
|
|
-- Projekt lässt sich umsetzen, sobald die Abstimmung beendet ist und
|
|
-- genug Zustimmung erreicht wurde — die Kosten kommen aus der Staatskasse.
|
|
-- =====================================================================
|
|
|
|
Admin = Admin or {}
|
|
|
|
local ZUSTIMMUNG_MIN = 0.6
|
|
|
|
Admin.Kern.Registriere('staat', 'laden', function(handelnder, daten)
|
|
local liste = MySQL.query.await([[
|
|
SELECT id, titel, beschreibung, kosten, ja, nein, abstimmung_offen, aktiviert, erstellt_am
|
|
FROM aether_admin_projects ORDER BY aktiviert, id DESC
|
|
]]) or {}
|
|
|
|
for _, p in ipairs(liste) do
|
|
local gesamt = (tonumber(p.ja) or 0) + (tonumber(p.nein) or 0)
|
|
p.zustimmung = gesamt > 0 and math.floor(tonumber(p.ja) / gesamt * 100) or 0
|
|
p.offen = tonumber(p.abstimmung_offen) == 1
|
|
p.aktiviert = tonumber(p.aktiviert) == 1
|
|
end
|
|
|
|
return {
|
|
projekte = liste,
|
|
staatskasse = Admin.DB.EinstellungZahl('staatskasse', 0),
|
|
zustimmungMin = ZUSTIMMUNG_MIN * 100,
|
|
rechte = Admin.Kern.RechteAbbild(handelnder.quelle),
|
|
}
|
|
end)
|
|
|
|
Admin.Kern.Registriere('staat', 'beenden', function(handelnder, daten)
|
|
local id = tonumber(daten.id)
|
|
if not id then return nil, 'Ungültige Kennung.' end
|
|
MySQL.update.await('UPDATE aether_admin_projects SET abstimmung_offen = 0 WHERE id = ?', { id })
|
|
Admin.Log.Schreibe(handelnder, 'Abstimmung beendet', 'Projekt #' .. id)
|
|
return { ok = true }
|
|
end)
|
|
|
|
Admin.Kern.Registriere('staat', 'aktivieren', function(handelnder, daten)
|
|
local id = tonumber(daten.id)
|
|
if not id then return nil, 'Ungültige Kennung.' end
|
|
|
|
local zeilen = MySQL.query.await([[
|
|
SELECT titel, kosten, ja, nein, abstimmung_offen, aktiviert
|
|
FROM aether_admin_projects WHERE id = ?
|
|
]], { id })
|
|
if not zeilen or not zeilen[1] then return nil, 'Projekt nicht gefunden.' end
|
|
local p = zeilen[1]
|
|
|
|
if tonumber(p.aktiviert) == 1 then return nil, 'Bereits umgesetzt.' end
|
|
if tonumber(p.abstimmung_offen) == 1 then return nil, 'Die Abstimmung läuft noch.' end
|
|
|
|
local gesamt = (tonumber(p.ja) or 0) + (tonumber(p.nein) or 0)
|
|
local quote = gesamt > 0 and (tonumber(p.ja) / gesamt) or 0
|
|
if quote < ZUSTIMMUNG_MIN then return nil, 'Nicht genug Zustimmung.' end
|
|
|
|
local kosten = tonumber(p.kosten) or 0
|
|
local kasse = Admin.DB.EinstellungZahl('staatskasse', 0)
|
|
if kosten > kasse then return nil, 'Staatskasse nicht gedeckt.' end
|
|
|
|
Admin.DB.SetzeEinstellung('staatskasse', kasse - kosten)
|
|
MySQL.update.await('UPDATE aether_admin_projects SET aktiviert = 1 WHERE id = ?', { id })
|
|
|
|
Admin.Log.Schreibe(handelnder, 'Staatsprojekt aktiviert', p.titel, tostring(kosten))
|
|
return { ok = true }
|
|
end)
|
|
|
|
Admin.Kern.Registriere('staat', 'archivieren', function(handelnder, daten)
|
|
local id = tonumber(daten.id)
|
|
if not id then return nil, 'Ungültige Kennung.' end
|
|
MySQL.update.await('DELETE FROM aether_admin_projects WHERE id = ?', { id })
|
|
Admin.Log.Schreibe(handelnder, 'Staatsprojekt archiviert', 'Projekt #' .. id)
|
|
return { ok = true }
|
|
end)
|