-- ===================================================================== -- aether-police / Modul: MDT -- -- Personensuche, Fahrzeugsuche und Aktenverwaltung. -- Das MDT zeigt und dokumentiert — es bewertet nichts und ergreift -- keine Maßnahme. Jede Änderung wird protokolliert. -- ===================================================================== Kern.RegistriereModul({ id = 'mdt', name = 'MDT', icon = '🔎', reihenfolge = 2, recht = 'person.suchen', beschreibung = 'Personen, Fahrzeuge und Akten', }) -- --------------------------------------------------------------------- -- Hilfsfunktionen -- --------------------------------------------------------------------- --- Liest den Namen eines Beamten anhand der Charakter-ID --- @param charakterId number|nil --- @return string local function NameVon(charakterId) if not charakterId then return '—' end local zeile = MySQL.query.await( 'SELECT firstname, lastname FROM aether_characters WHERE id = ?', { charakterId }) if not zeile or not zeile[1] then return '#' .. tostring(charakterId) end return zeile[1].firstname .. ' ' .. zeile[1].lastname end --- Prüft, ob eine Zeichenkette als Suchbegriff taugt local function SuchbegriffGueltig(begriff) return type(begriff) == 'string' and #begriff:gsub('%s', '') >= 2 end -- ===================================================================== -- PERSONENSUCHE -- ===================================================================== Kern.RegistriereAktion('mdt', 'personSuchen', 'person.suchen', function(quelle, beamter, daten) if not SuchbegriffGueltig(daten.begriff) then return nil, 'Bitte mindestens zwei Zeichen eingeben.' end local muster = '%' .. daten.begriff .. '%' -- Sucht über Name, Geburtsdatum und Telefonnummer local treffer = MySQL.query.await([[ SELECT c.id, c.firstname, c.lastname, c.dob, c.gender, c.job, p.warnhinweis, p.gefahrenstufe, p.lichtbild, t.number AS telefon, (SELECT COUNT(*) FROM police_fahndung f WHERE f.typ = 'person' AND f.ziel_id = c.id AND f.aktiv = 1) AS fahndung FROM aether_characters c LEFT JOIN police_person p ON p.`character` = c.id LEFT JOIN aether_phone t ON t.`character` = c.id WHERE c.deleted = 0 AND (c.firstname LIKE ? OR c.lastname LIKE ? OR CONCAT(c.firstname, ' ', c.lastname) LIKE ? OR c.dob LIKE ? OR t.number LIKE ?) ORDER BY c.lastname, c.firstname LIMIT 40 ]], { muster, muster, muster, muster, muster }) or {} return { treffer = treffer } end) -- ===================================================================== -- PERSONENAKTE -- ===================================================================== Kern.RegistriereAktion('mdt', 'personAkte', 'person.suchen', function(quelle, beamter, daten) local charakterId = tonumber(daten.charakterId) if not charakterId then return nil, 'Ungültige Kennung.' end -- --- Stammdaten --- local person = MySQL.query.await([[ SELECT c.id, c.firstname, c.lastname, c.dob, c.gender, c.nationality, c.job, c.iban, p.lichtbild, p.fingerabdruck, p.dna, p.warnhinweis, p.gefahrenstufe FROM aether_characters c LEFT JOIN police_person p ON p.`character` = c.id WHERE c.id = ? AND c.deleted = 0 ]], { charakterId }) if not person or not person[1] then return nil, 'Person nicht gefunden.' end -- --- Telefonnummer --- local telefon = MySQL.scalar.await( 'SELECT number FROM aether_phone WHERE `character` = ?', { charakterId }) -- --- Dokumente (Führerschein, Waffenschein ...) --- local dokumente = MySQL.query.await([[ SELECT type, data, issued_by, issued_at, valid_until, revoked FROM aether_documents WHERE `character` = ? ]], { charakterId }) or {} local lizenzen = {} for _, dokument in ipairs(dokumente) do local zusatz = {} if dokument.data then local erfolg, entschluesselt = pcall(json.decode, dokument.data) if erfolg and type(entschluesselt) == 'table' then zusatz = entschluesselt end end -- Gültig, wenn nicht entzogen und (unbefristet oder noch nicht abgelaufen) local gueltig = dokument.revoked == 0 if gueltig and dokument.valid_until then gueltig = tostring(dokument.valid_until):sub(1, 10) >= os.date('%Y-%m-%d') end lizenzen[#lizenzen + 1] = { typ = dokument.type, nummer = zusatz.nummer, klassen = zusatz.klassen, waffen = zusatz.waffen, aussteller = dokument.issued_by, gueltigBis = dokument.valid_until and tostring(dokument.valid_until):sub(1, 10) or nil, entzogen = dokument.revoked == 1, gueltig = gueltig, } end -- --- Bekannte Fahrzeuge --- local fahrzeuge = MySQL.query.await([[ SELECT v.plate, v.model, v.props, v.state, v.garage, (SELECT COUNT(*) FROM police_fahndung f WHERE f.typ = 'fahrzeug' AND f.ziel_id = v.plate AND f.aktiv = 1) AS fahndung FROM aether_vehicles v WHERE v.owner = ? ]], { charakterId }) or {} for _, fahrzeug in ipairs(fahrzeuge) do if fahrzeug.props then local erfolg, props = pcall(json.decode, fahrzeug.props) if erfolg and type(props) == 'table' then fahrzeug.name = props.name fahrzeug.farbe = props.farbe end end fahrzeug.props = nil end -- --- Bekannte Kontakte (aus dem Telefonbuch) --- local kontakte = MySQL.query.await([[ SELECT k.name, k.number, (SELECT c2.id FROM aether_phone p2 JOIN aether_characters c2 ON c2.id = p2.`character` WHERE p2.number = k.number LIMIT 1) AS charakterId FROM aether_phone_contacts k WHERE k.`character` = ? ORDER BY k.name LIMIT 40 ]], { charakterId }) or {} -- --- Notizen --- local notizen = MySQL.query.await([[ SELECT n.id, n.text, n.am, c.firstname, c.lastname FROM police_person_notiz n LEFT JOIN aether_characters c ON c.id = n.von WHERE n.`character` = ? ORDER BY n.id DESC LIMIT 50 ]], { charakterId }) or {} -- --- Verknüpfte Akten --- local akten = MySQL.query.await([[ SELECT a.id, a.aktenzeichen, a.typ, a.titel, a.status, a.erstellt_am, v.rolle FROM police_verknuepfung v JOIN police_akte a ON a.id = v.akte WHERE v.typ = 'person' AND v.ziel_id = ? ORDER BY a.id DESC LIMIT 50 ]], { tostring(charakterId) }) or {} -- --- Anzeigen (nur bestätigte zählen als Vorgeschichte) --- local anzeigen = MySQL.query.await([[ SELECT id, delikte, haft_final, geld_final, status, erstellt_am, bestaetigt_am FROM police_anzeige WHERE beschuldigter = ? ORDER BY id DESC LIMIT 30 ]], { charakterId }) or {} for _, anzeige in ipairs(anzeigen) do local erfolg, liste = pcall(json.decode, anzeige.delikte) anzeige.delikte = (erfolg and type(liste) == 'table') and liste or {} end -- --- Offene Fahndung --- local fahndung = MySQL.query.await([[ SELECT id, grund, gefahr, prioritaet, hinweise, erstellt_am FROM police_fahndung WHERE typ = 'person' AND ziel_id = ? AND aktiv = 1 LIMIT 1 ]], { tostring(charakterId) }) -- --- Laufender Gewahrsam --- local gewahrsam = MySQL.query.await([[ SELECT id, grund, zelle, faellig_am, TIMESTAMPDIFF(MINUTE, NOW(), faellig_am) AS rest FROM police_gewahrsam WHERE `character` = ? AND entlassen_am IS NULL LIMIT 1 ]], { charakterId }) return { person = person[1], telefon = telefon, lizenzen = lizenzen, fahrzeuge = fahrzeuge, kontakte = kontakte, notizen = notizen, akten = akten, anzeigen = anzeigen, fahndung = fahndung and fahndung[1] or nil, gewahrsam = gewahrsam and gewahrsam[1] or nil, } end) -- --------------------------------------------------------------------- -- Notiz zu einer Person -- --------------------------------------------------------------------- Kern.RegistriereAktion('mdt', 'personNotiz', 'person.bearbeiten', function(quelle, beamter, daten) local charakterId = tonumber(daten.charakterId) local text = type(daten.text) == 'string' and daten.text:gsub('^%s+', ''):gsub('%s+$', '') or '' if not charakterId then return nil, 'Ungültige Kennung.' end if #text < 3 or #text > 1000 then return nil, 'Die Notiz muss 3 bis 1000 Zeichen lang sein.' end local id = MySQL.insert.await( 'INSERT INTO police_person_notiz (`character`, text, von) VALUES (?, ?, ?)', { charakterId, text, beamter.charakterId }) Protokoll.Schreibe(beamter, 'mdt', 'Notiz hinzugefügt', { typ = 'person', id = charakterId }, { notizId = id }) return { id = id } end) Kern.RegistriereAktion('mdt', 'personNotizLoeschen', 'person.bearbeiten', function(quelle, beamter, daten) local notizId = tonumber(daten.id) if not notizId then return nil, 'Ungültige Kennung.' end -- Eigene Notizen darf jeder löschen; fremde nur ab Captain local notiz = MySQL.query.await( 'SELECT `character`, von FROM police_person_notiz WHERE id = ?', { notizId }) if not notiz or not notiz[1] then return nil, 'Notiz nicht gefunden.' end if notiz[1].von ~= beamter.charakterId and not Rechte.Hat(beamter, 'protokoll.lesen') then return nil, 'Du kannst nur eigene Notizen entfernen.' end MySQL.update.await('DELETE FROM police_person_notiz WHERE id = ?', { notizId }) Protokoll.Schreibe(beamter, 'mdt', 'Notiz entfernt', { typ = 'person', id = notiz[1].character }, { notizId = notizId }) return { ok = true } end) -- --------------------------------------------------------------------- -- Warnhinweis und Gefahrenstufe -- --------------------------------------------------------------------- Kern.RegistriereAktion('mdt', 'personWarnhinweis', 'person.warnhinweis', function(quelle, beamter, daten) local charakterId = tonumber(daten.charakterId) if not charakterId then return nil, 'Ungültige Kennung.' end local hinweis = type(daten.hinweis) == 'string' and daten.hinweis:sub(1, 255) or nil if hinweis == '' then hinweis = nil end local stufe = math.max(0, math.min(3, tonumber(daten.stufe) or 0)) MySQL.query.await([[ INSERT INTO police_person (`character`, warnhinweis, gefahrenstufe) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE warnhinweis = VALUES(warnhinweis), gefahrenstufe = VALUES(gefahrenstufe) ]], { charakterId, hinweis, stufe }) Protokoll.Schreibe(beamter, 'mdt', hinweis and 'Warnhinweis gesetzt' or 'Warnhinweis entfernt', { typ = 'person', id = charakterId }, { hinweis = hinweis, stufe = stufe }, daten.grund) return { ok = true } end) -- --------------------------------------------------------------------- -- Erkennungsdienstliche Daten (Fingerabdruck, DNA, Lichtbild) -- --------------------------------------------------------------------- Kern.RegistriereAktion('mdt', 'personStammdaten', 'person.bearbeiten', function(quelle, beamter, daten) local charakterId = tonumber(daten.charakterId) if not charakterId then return nil, 'Ungültige Kennung.' end -- Vorhandene Werte lesen, damit leere Felder nichts überschreiben local vorhanden = MySQL.query.await( 'SELECT lichtbild, fingerabdruck, dna FROM police_person WHERE `character` = ?', { charakterId }) local alt = (vorhanden and vorhanden[1]) or {} local lichtbild = daten.lichtbild ~= nil and tostring(daten.lichtbild):sub(1, 2000) or alt.lichtbild local finger = daten.fingerabdruck ~= nil and tostring(daten.fingerabdruck):sub(1, 64) or alt.fingerabdruck local dna = daten.dna ~= nil and tostring(daten.dna):sub(1, 64) or alt.dna MySQL.query.await([[ INSERT INTO police_person (`character`, lichtbild, fingerabdruck, dna) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE lichtbild = VALUES(lichtbild), fingerabdruck = VALUES(fingerabdruck), dna = VALUES(dna) ]], { charakterId, lichtbild, finger, dna }) Protokoll.Schreibe(beamter, 'mdt', 'Erkennungsdienstliche Daten geändert', { typ = 'person', id = charakterId }) return { ok = true } end) -- ===================================================================== -- FAHRZEUGSUCHE -- ===================================================================== Kern.RegistriereAktion('mdt', 'fahrzeugSuchen', 'fahrzeug.suchen', function(quelle, beamter, daten) if not SuchbegriffGueltig(daten.begriff) then return nil, 'Bitte mindestens zwei Zeichen eingeben.' end local muster = '%' .. daten.begriff:upper() .. '%' local namensmuster = '%' .. daten.begriff .. '%' local treffer = MySQL.query.await([[ SELECT v.plate, v.model, v.props, v.state, v.garage, v.owner, c.firstname, c.lastname, (SELECT COUNT(*) FROM police_fahndung f WHERE f.typ = 'fahrzeug' AND f.ziel_id = v.plate AND f.aktiv = 1) AS fahndung FROM aether_vehicles v LEFT JOIN aether_characters c ON c.id = v.owner WHERE UPPER(v.plate) LIKE ? OR v.model LIKE ? OR CONCAT(c.firstname, ' ', c.lastname) LIKE ? ORDER BY v.plate LIMIT 40 ]], { muster, namensmuster, namensmuster }) or {} for _, fahrzeug in ipairs(treffer) do if fahrzeug.props then local erfolg, props = pcall(json.decode, fahrzeug.props) if erfolg and type(props) == 'table' then fahrzeug.name = props.name fahrzeug.farbe = props.farbe fahrzeug.klasse = props.klasse end end fahrzeug.props = nil end return { treffer = treffer } end) Kern.RegistriereAktion('mdt', 'fahrzeugAkte', 'fahrzeug.suchen', function(quelle, beamter, daten) local kennzeichen = type(daten.kennzeichen) == 'string' and daten.kennzeichen:upper() or nil if not kennzeichen then return nil, 'Ungültiges Kennzeichen.' end local fahrzeug = MySQL.query.await([[ SELECT v.*, c.firstname, c.lastname, c.dob FROM aether_vehicles v LEFT JOIN aether_characters c ON c.id = v.owner WHERE UPPER(v.plate) = ? ]], { kennzeichen }) if not fahrzeug or not fahrzeug[1] then return nil, 'Kein Fahrzeug mit diesem Kennzeichen.' end local eintrag = fahrzeug[1] if eintrag.props then local erfolg, props = pcall(json.decode, eintrag.props) if erfolg and type(props) == 'table' then eintrag.name = props.name eintrag.farbe = props.farbe eintrag.klasse = props.klasse end eintrag.props = nil end -- Fahndungsstatus local fahndung = MySQL.query.await([[ SELECT id, grund, gefahr, prioritaet, hinweise, erstellt_am FROM police_fahndung WHERE typ = 'fahrzeug' AND ziel_id = ? AND aktiv = 1 LIMIT 1 ]], { eintrag.plate }) -- Verknüpfte Akten local akten = MySQL.query.await([[ SELECT a.id, a.aktenzeichen, a.typ, a.titel, a.status, a.erstellt_am FROM police_verknuepfung v JOIN police_akte a ON a.id = v.akte WHERE v.typ = 'fahrzeug' AND v.ziel_id = ? ORDER BY a.id DESC LIMIT 30 ]], { eintrag.plate }) or {} -- Protokollhistorie zu diesem Fahrzeug local historie = Protokoll.Lies({ zielTyp = 'fahrzeug', zielId = eintrag.plate, limit = 30 }) return { fahrzeug = eintrag, fahndung = fahndung and fahndung[1] or nil, akten = akten, historie = historie, } end) -- ===================================================================== -- AKTEN -- ===================================================================== Kern.RegistriereAktion('mdt', 'aktenListe', 'akte.lesen', function(quelle, beamter, daten) local bedingungen, werte = { '1=1' }, {} if daten.typ and daten.typ ~= '' then bedingungen[#bedingungen + 1] = 'a.typ = ?' werte[#werte + 1] = daten.typ end if daten.status and daten.status ~= '' then bedingungen[#bedingungen + 1] = 'a.status = ?' werte[#werte + 1] = daten.status end if SuchbegriffGueltig(daten.begriff) then bedingungen[#bedingungen + 1] = '(a.titel LIKE ? OR a.aktenzeichen LIKE ?)' werte[#werte + 1] = '%' .. daten.begriff .. '%' werte[#werte + 1] = '%' .. daten.begriff .. '%' end local akten = MySQL.query.await(([[ SELECT a.id, a.aktenzeichen, a.typ, a.titel, a.status, a.erstellt_am, a.version, c.firstname, c.lastname FROM police_akte a LEFT JOIN aether_characters c ON c.id = a.erstellt_von WHERE %s ORDER BY a.id DESC LIMIT 60 ]]):format(table.concat(bedingungen, ' AND ')), werte) or {} return { akten = akten } end) Kern.RegistriereAktion('mdt', 'akteOeffnen', 'akte.lesen', function(quelle, beamter, daten) local akteId = tonumber(daten.id) if not akteId then return nil, 'Ungültige Kennung.' end local akte = MySQL.query.await([[ SELECT a.*, c.firstname, c.lastname FROM police_akte a LEFT JOIN aether_characters c ON c.id = a.erstellt_von WHERE a.id = ? ]], { akteId }) if not akte or not akte[1] then return nil, 'Akte nicht gefunden.' end -- Verknüpfungen mit lesbaren Bezeichnungen anreichern local verknuepfungen = MySQL.query.await( 'SELECT * FROM police_verknuepfung WHERE akte = ? ORDER BY id ASC', { akteId }) or {} for _, verknuepfung in ipairs(verknuepfungen) do if verknuepfung.typ == 'person' then verknuepfung.bezeichnung = NameVon(tonumber(verknuepfung.ziel_id)) elseif verknuepfung.typ == 'fahrzeug' then local modell = MySQL.scalar.await( 'SELECT model FROM aether_vehicles WHERE plate = ?', { verknuepfung.ziel_id }) verknuepfung.bezeichnung = verknuepfung.ziel_id .. (modell and (' · ' .. modell) or '') else verknuepfung.bezeichnung = verknuepfung.ziel_id end end -- Versionshistorie local versionen = MySQL.query.await([[ SELECT v.version, v.geaendert_am, v.grund, c.firstname, c.lastname FROM police_akte_version v LEFT JOIN aether_characters c ON c.id = v.geaendert_von WHERE v.akte = ? ORDER BY v.version DESC ]], { akteId }) or {} return { akte = akte[1], verknuepfungen = verknuepfungen, versionen = versionen, darfBearbeiten = Rechte.Hat(beamter, 'akte.bearbeiten'), darfFreigeben = Rechte.Hat(beamter, 'akte.freigeben'), darfSchliessen = Rechte.Hat(beamter, 'akte.schliessen'), } end) Kern.RegistriereAktion('mdt', 'akteErstellen', 'akte.erstellen', function(quelle, beamter, daten) local titel = type(daten.titel) == 'string' and daten.titel:gsub('^%s+', ''):gsub('%s+$', '') or '' if #titel < 3 or #titel > 160 then return nil, 'Der Titel muss 3 bis 160 Zeichen lang sein.' end -- Aktenart gegen die Konfiguration prüfen local gueltig = false for _, art in ipairs(Polizei.Config.Aktenarten) do if art.id == daten.typ then gueltig = true break end end if not gueltig then return nil, 'Unbekannte Aktenart.' end local aktenzeichen = Kern.ErzeugeKennung('AZ', 'police_akte', 'aktenzeichen') local akteId = MySQL.insert.await([[ INSERT INTO police_akte (aktenzeichen, typ, titel, inhalt, erstellt_von) VALUES (?, ?, ?, ?, ?) ]], { aktenzeichen, daten.typ, titel, type(daten.inhalt) == 'string' and daten.inhalt or nil, beamter.charakterId }) -- Erste Version festhalten MySQL.insert('INSERT INTO police_akte_version (akte, version, inhalt, geaendert_von, grund) VALUES (?, 1, ?, ?, ?)', { akteId, daten.inhalt, beamter.charakterId, 'Akte angelegt' }) -- Optionale Erstverknüpfung (z. B. direkt aus einer Personenakte heraus) if daten.verknuepfeTyp and daten.verknuepfeId then MySQL.insert('INSERT INTO police_verknuepfung (akte, typ, ziel_id, rolle) VALUES (?, ?, ?, ?)', { akteId, tostring(daten.verknuepfeTyp), tostring(daten.verknuepfeId), daten.verknuepfeRolle }) end Protokoll.Schreibe(beamter, 'mdt', 'Akte angelegt', { typ = 'akte', id = akteId }, { aktenzeichen = aktenzeichen, typ = daten.typ }) Kern.Loese('akte.erstellt', akteId, beamter) return { id = akteId, aktenzeichen = aktenzeichen } end) Kern.RegistriereAktion('mdt', 'akteBearbeiten', 'akte.bearbeiten', function(quelle, beamter, daten) local akteId = tonumber(daten.id) if not akteId then return nil, 'Ungültige Kennung.' end local akte = MySQL.query.await('SELECT * FROM police_akte WHERE id = ?', { akteId }) if not akte or not akte[1] then return nil, 'Akte nicht gefunden.' end if akte[1].status == 'geschlossen' and not Rechte.Hat(beamter, 'akte.freigeben') then return nil, 'Diese Akte ist geschlossen und kann nicht mehr bearbeitet werden.' end local grund = type(daten.grund) == 'string' and daten.grund:sub(1, 255) or nil if not grund or #grund < 3 then return nil, 'Bitte gib einen Grund für die Änderung an.' end local neueVersion = (akte[1].version or 1) + 1 MySQL.update.await('UPDATE police_akte SET titel = ?, inhalt = ?, version = ? WHERE id = ?', { type(daten.titel) == 'string' and daten.titel:sub(1, 160) or akte[1].titel, daten.inhalt, neueVersion, akteId }) MySQL.insert('INSERT INTO police_akte_version (akte, version, inhalt, geaendert_von, grund) VALUES (?, ?, ?, ?, ?)', { akteId, neueVersion, daten.inhalt, beamter.charakterId, grund }) Protokoll.Schreibe(beamter, 'mdt', 'Akte bearbeitet', { typ = 'akte', id = akteId }, { version = neueVersion }, grund) return { version = neueVersion } end) --- Status einer Akte ändern — jede Stufe braucht ein eigenes Recht Kern.RegistriereAktion('mdt', 'akteStatus', 'akte.lesen', function(quelle, beamter, daten) local akteId = tonumber(daten.id) local status = tostring(daten.status or '') if not akteId then return nil, 'Ungültige Kennung.' end if status ~= 'offen' and status ~= 'pruefung' and status ~= 'geschlossen' then return nil, 'Unbekannter Status.' end -- Freigabe und Schließen sind gesondert geschützt if status == 'geschlossen' and not Rechte.Hat(beamter, 'akte.schliessen') then return nil, 'Dir fehlt die Berechtigung, Akten zu schließen.' end if status == 'pruefung' and not Rechte.Hat(beamter, 'akte.bearbeiten') then return nil, 'Dir fehlt die Berechtigung dafür.' end -- Beim Schließen wird festgehalten, WER es entschieden hat if status == 'geschlossen' then MySQL.update.await( 'UPDATE police_akte SET status = ?, freigabe_von = ?, freigabe_am = NOW() WHERE id = ?', { status, beamter.charakterId, akteId }) else MySQL.update.await('UPDATE police_akte SET status = ? WHERE id = ?', { status, akteId }) end Protokoll.Schreibe(beamter, 'mdt', 'Aktenstatus geändert', { typ = 'akte', id = akteId }, { status = status }, daten.grund) return { ok = true } end) -- --------------------------------------------------------------------- -- Verknüpfungen -- --------------------------------------------------------------------- Kern.RegistriereAktion('mdt', 'akteVerknuepfen', 'akte.bearbeiten', function(quelle, beamter, daten) local akteId = tonumber(daten.akteId) local typ = tostring(daten.typ or '') local zielId = tostring(daten.zielId or '') if not akteId or zielId == '' then return nil, 'Unvollständige Angaben.' end local erlaubt = { person = true, fahrzeug = true, beweis = true, einsatz = true, bericht = true } if not erlaubt[typ] then return nil, 'Unbekannte Verknüpfungsart.' end -- Doppelte Verknüpfungen vermeiden local vorhanden = MySQL.scalar.await( 'SELECT id FROM police_verknuepfung WHERE akte = ? AND typ = ? AND ziel_id = ?', { akteId, typ, zielId }) if vorhanden then return nil, 'Diese Verknüpfung besteht bereits.' end local id = MySQL.insert.await( 'INSERT INTO police_verknuepfung (akte, typ, ziel_id, rolle) VALUES (?, ?, ?, ?)', { akteId, typ, zielId, daten.rolle }) Protokoll.Schreibe(beamter, 'mdt', 'Verknüpfung hinzugefügt', { typ = 'akte', id = akteId }, { ziel = typ .. ':' .. zielId, rolle = daten.rolle }) return { id = id } end) Kern.RegistriereAktion('mdt', 'akteVerknuepfungLoesen', 'akte.bearbeiten', function(quelle, beamter, daten) local id = tonumber(daten.id) if not id then return nil, 'Ungültige Kennung.' end local eintrag = MySQL.query.await('SELECT akte, typ, ziel_id FROM police_verknuepfung WHERE id = ?', { id }) if not eintrag or not eintrag[1] then return nil, 'Verknüpfung nicht gefunden.' end MySQL.update.await('DELETE FROM police_verknuepfung WHERE id = ?', { id }) Protokoll.Schreibe(beamter, 'mdt', 'Verknüpfung entfernt', { typ = 'akte', id = eintrag[1].akte }, { ziel = eintrag[1].typ .. ':' .. eintrag[1].ziel_id }) return { ok = true } end) -- --------------------------------------------------------------------- -- Konfiguration für die Oberfläche -- --------------------------------------------------------------------- Kern.RegistriereAktion('mdt', 'stammdaten', nil, function() return { aktenarten = Polizei.Config.Aktenarten, rollen = { { id = 'beschuldigt', name = 'Beschuldigt' }, { id = 'zeuge', name = 'Zeuge' }, { id = 'geschaedigt', name = 'Geschädigt' }, { id = 'beteiligt', name = 'Beteiligt' }, }, } end)