From 9461b582f6ec6c1112a018b7988cca60683558f9 Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Mon, 4 Aug 2025 09:15:25 +0200 Subject: [PATCH] Update main.lua --- .../[tools]/nordi_license/server/main.lua | 380 ++++++++++++------ 1 file changed, 268 insertions(+), 112 deletions(-) diff --git a/resources/[tools]/nordi_license/server/main.lua b/resources/[tools]/nordi_license/server/main.lua index 82c272383..f39483fb8 100644 --- a/resources/[tools]/nordi_license/server/main.lua +++ b/resources/[tools]/nordi_license/server/main.lua @@ -35,7 +35,7 @@ local function hasPermission(src) return Config.AuthorizedJobs[job.name] or false end --- Cache-Funktionen +-- Cache-Funktionen (KORRIGIERT - Aggressive Cache-Invalidierung) local function getCachedLicense(citizenid, licenseType) local cacheKey = citizenid .. "_" .. licenseType local cached = licenseCache[cacheKey] @@ -57,6 +57,24 @@ local function setCachedLicense(citizenid, licenseType, data) debugPrint("Lizenz gecacht: " .. cacheKey) end +-- Cache invalidieren (ERWEITERT) +local function invalidateCache(citizenid, licenseType) + if licenseType then + -- Spezifische Lizenz invalidieren + local cacheKey = citizenid .. "_" .. licenseType + licenseCache[cacheKey] = nil + debugPrint("Cache invalidiert für: " .. cacheKey) + else + -- Alle Lizenzen des Spielers invalidieren + for key, _ in pairs(licenseCache) do + if string.find(key, citizenid .. "_") then + licenseCache[key] = nil + debugPrint("Cache invalidiert für: " .. key) + end + end + end +end + -- Spieler-Name aus JSON extrahieren local function extractPlayerName(charinfo_json) if not charinfo_json then return "Unbekannt" end @@ -94,61 +112,87 @@ local function safeDBOperation(operation, errorMessage, maxRetries) return nil end --- KORRIGIERTE Lizenz-Abfrage (Erweiterte Suche) -local function getLicenseFromDB(citizenid, licenseType) - debugPrint("=== getLicenseFromDB START ===") - debugPrint("CitizenID: " .. tostring(citizenid)) - debugPrint("LicenseType: " .. tostring(licenseType)) +-- Lizenz-Status prüfen (NEUE FUNKTION) +local function isLicenseActive(license) + if not license then return false end - -- Cache prüfen - local cached = getCachedLicense(citizenid, licenseType) - if cached then - debugPrint("Lizenz aus Cache geladen") - return cached + -- is_active prüfen (1 = aktiv, 0 = inaktiv, nil = aktiv per default) + local isActive = license.is_active + if isActive == nil then + isActive = 1 -- Default: aktiv end - -- ERWEITERTE SUCHE: Erst aktive, dann alle Lizenzen - local queries = { - -- 1. Suche nach aktiven Lizenzen (is_active = 1) - { - query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? AND is_active = 1 ORDER BY created_at DESC LIMIT 1", - description = "Aktive Lizenz" - }, - -- 2. Suche nach allen Lizenzen (falls is_active nicht gesetzt) - { - query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? ORDER BY created_at DESC LIMIT 1", - description = "Neueste Lizenz" - }, - -- 3. Fallback: Suche ohne is_active Bedingung - { - query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? ORDER BY id DESC LIMIT 1", - description = "Fallback-Suche" - } - } + if isActive ~= 1 then + debugPrint("Lizenz inaktiv (is_active = " .. tostring(isActive) .. ")") + return false + end - local license = nil - - for i, queryData in ipairs(queries) do - debugPrint("Versuche Query " .. i .. ": " .. queryData.description) + -- Ablaufdatum prüfen (falls vorhanden) + if license.expire_date and license.expire_date ~= "" then + local expireDate = license.expire_date + local currentDate = os.date("%d.%m.%Y") - local result = safeDBOperation(function() - return MySQL.query.await(queryData.query, {citizenid, licenseType}) - end, "Fehler bei " .. queryData.description) + -- Einfache Datumsvergleich (DD.MM.YYYY) + local function parseDate(dateStr) + local day, month, year = dateStr:match("(%d+)%.(%d+)%.(%d+)") + if day and month and year then + return os.time({year = tonumber(year), month = tonumber(month), day = tonumber(day)}) + end + return nil + end - if result and #result > 0 then - license = result[1] - debugPrint("Lizenz gefunden mit Query " .. i .. ": " .. queryData.description) - break - else - debugPrint("Keine Lizenz mit Query " .. i .. " gefunden") + local expireTimestamp = parseDate(expireDate) + local currentTimestamp = parseDate(currentDate) + + if expireTimestamp and currentTimestamp and expireTimestamp < currentTimestamp then + debugPrint("Lizenz abgelaufen: " .. expireDate .. " < " .. currentDate) + return false end end - if not license then + debugPrint("Lizenz ist aktiv und gültig") + return true +end + +-- KORRIGIERTE Lizenz-Abfrage (Ohne Cache für frische Daten) +local function getLicenseFromDB(citizenid, licenseType, skipCache) + debugPrint("=== getLicenseFromDB START ===") + debugPrint("CitizenID: " .. tostring(citizenid)) + debugPrint("LicenseType: " .. tostring(licenseType)) + debugPrint("SkipCache: " .. tostring(skipCache)) + + -- Cache prüfen (nur wenn nicht übersprungen) + if not skipCache then + local cached = getCachedLicense(citizenid, licenseType) + if cached then + debugPrint("Lizenz aus Cache geladen") + return cached + end + end + + -- Direkte DB-Abfrage (VEREINFACHT - nur aktive Lizenzen) + local query = [[ + SELECT * FROM player_licenses + WHERE citizenid = ? AND license_type = ? + ORDER BY created_at DESC + LIMIT 1 + ]] + + local result = safeDBOperation(function() + return MySQL.query.await(query, {citizenid, licenseType}) + end, "Fehler beim Abrufen der Lizenz") + + if not result or #result == 0 then debugPrint("^1Keine Lizenz in DB gefunden für " .. citizenid .. " / " .. licenseType .. "^7") return nil end + local license = result[1] + debugPrint("Rohe Lizenz-Daten aus DB:") + debugPrint("ID: " .. tostring(license.id)) + debugPrint("is_active: " .. tostring(license.is_active)) + debugPrint("created_at: " .. tostring(license.created_at)) + -- Spieler-Namen abrufen local holderQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local holderResult = safeDBOperation(function() @@ -189,15 +233,27 @@ local function getLicenseFromDB(citizenid, licenseType) license.classes = {} end - -- is_active standardisieren (falls nicht gesetzt) + -- is_active normalisieren (WICHTIG!) if license.is_active == nil then license.is_active = 1 + debugPrint("is_active war nil, auf 1 gesetzt") + end + + -- Status prüfen + local isActive = isLicenseActive(license) + debugPrint("Lizenz-Status-Prüfung: " .. tostring(isActive)) + + if not isActive then + debugPrint("Lizenz ist nicht aktiv/gültig") + return nil end debugPrint("Lizenz erfolgreich geladen: " .. license.license_type .. " (Active: " .. tostring(license.is_active) .. ")") - -- In Cache speichern - setCachedLicense(citizenid, licenseType, license) + -- In Cache speichern (nur wenn aktiv) + if not skipCache then + setCachedLicense(citizenid, licenseType, license) + end return license end @@ -207,28 +263,12 @@ local function getAllPlayerLicenses(citizenid) debugPrint("=== getAllPlayerLicenses START ===") debugPrint("CitizenID: " .. tostring(citizenid)) - -- Erweiterte Suche für alle Lizenzen - local queries = { - -- 1. Aktive Lizenzen - "SELECT * FROM player_licenses WHERE citizenid = ? AND is_active = 1 ORDER BY license_type, created_at DESC", - -- 2. Alle Lizenzen (Fallback) - "SELECT * FROM player_licenses WHERE citizenid = ? ORDER BY license_type, created_at DESC" - } + -- Alle Lizenzen abrufen (ohne is_active Filter) + local query = "SELECT * FROM player_licenses WHERE citizenid = ? ORDER BY license_type, created_at DESC" - local result = nil - - for i, query in ipairs(queries) do - debugPrint("Versuche Abfrage " .. i .. " für alle Lizenzen") - - result = safeDBOperation(function() - return MySQL.query.await(query, {citizenid}) - end, "Fehler bei Abfrage " .. i) - - if result and #result > 0 then - debugPrint("Lizenzen gefunden mit Abfrage " .. i .. ": " .. #result .. " Einträge") - break - end - end + local result = safeDBOperation(function() + return MySQL.query.await(query, {citizenid}) + end, "Fehler beim Abrufen aller Lizenzen") if not result or #result == 0 then debugPrint("Keine Lizenzen gefunden für: " .. citizenid) @@ -284,20 +324,26 @@ local function getAllPlayerLicenses(citizenid) license.classes = {} end - -- is_active standardisieren + -- is_active normalisieren if license.is_active == nil then license.is_active = 1 end - table.insert(licenses, license) + -- Status prüfen und nur aktive Lizenzen hinzufügen + if isLicenseActive(license) then + table.insert(licenses, license) + debugPrint("Aktive Lizenz hinzugefügt: " .. license.license_type) + else + debugPrint("Inaktive Lizenz übersprungen: " .. license.license_type) + end end end - debugPrint("Verarbeitete Lizenzen: " .. #licenses) + debugPrint("Verarbeitete aktive Lizenzen: " .. #licenses) return licenses end --- Lizenz in Datenbank speichern (KORRIGIERT) +-- Lizenz in Datenbank speichern (KORRIGIERT - Explizite is_active Setzung) local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) debugPrint("=== saveLicenseToDB START ===") debugPrint("CitizenID: " .. tostring(citizenid)) @@ -310,6 +356,9 @@ local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) return false end + -- Cache für diesen Spieler komplett invalidieren + invalidateCache(citizenid) + -- Spieler-Name abrufen local holderQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local holderResult = safeDBOperation(function() @@ -333,17 +382,19 @@ local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) -- Classes zu JSON konvertieren local classesJson = json.encode(classes or {}) - -- Alte Lizenz deaktivieren + -- WICHTIG: Alte Lizenz explizit deaktivieren local deactivateQuery = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?" - safeDBOperation(function() + local deactivateResult = safeDBOperation(function() return MySQL.query.await(deactivateQuery, {citizenid, licenseType}) end, "Fehler beim Deaktivieren alter Lizenz") - -- Neue Lizenz einfügen + debugPrint("Alte Lizenzen deaktiviert: " .. tostring(deactivateResult ~= nil)) + + -- Neue Lizenz einfügen (EXPLIZIT is_active = 1) local insertQuery = [[ INSERT INTO player_licenses (citizenid, license_type, name, issue_date, expire_date, issued_by, is_active, classes, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?) ]] local createdAt = os.time() -- Unix Timestamp @@ -355,7 +406,7 @@ local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) issueDate, expireDate, issuedBy, - 1, -- is_active = 1 + -- is_active = 1 ist direkt in der Query classesJson, createdAt } @@ -370,9 +421,18 @@ local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) if result then debugPrint("Lizenz erfolgreich gespeichert. ID: " .. result) - -- Cache invalidieren - local cacheKey = citizenid .. "_" .. licenseType - licenseCache[cacheKey] = nil + -- Cache komplett invalidieren (sicherstellen dass neue Daten geladen werden) + invalidateCache(citizenid) + + -- Sofort neue Lizenz aus DB laden um zu verifizieren + Wait(100) -- Kurz warten + local newLicense = getLicenseFromDB(citizenid, licenseType, true) -- Skip Cache + + if newLicense then + debugPrint("Neue Lizenz erfolgreich verifiziert: is_active = " .. tostring(newLicense.is_active)) + else + debugPrint("^3Warnung: Neue Lizenz konnte nicht verifiziert werden^7") + end return true else @@ -381,13 +441,13 @@ local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) end end --- Lizenz entziehen +-- Lizenz entziehen (KORRIGIERT) local function revokeLicenseInDB(citizenid, licenseType) debugPrint("=== revokeLicenseInDB START ===") debugPrint("CitizenID: " .. tostring(citizenid)) debugPrint("LicenseType: " .. tostring(licenseType)) - local query = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?" + local query = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ? AND is_active = 1" local result = safeDBOperation(function() return MySQL.query.await(query, {citizenid, licenseType}) @@ -397,8 +457,7 @@ local function revokeLicenseInDB(citizenid, licenseType) debugPrint("Lizenz erfolgreich entzogen") -- Cache invalidieren - local cacheKey = citizenid .. "_" .. licenseType - licenseCache[cacheKey] = nil + invalidateCache(citizenid, licenseType) return true else @@ -432,7 +491,7 @@ CreateThread(function() end end) --- EVENT HANDLER: Lizenz anfordern (KORRIGIERT für Ausweis-Anzeige) +-- EVENT HANDLER: Lizenz anfordern RegisterNetEvent('license-system:server:requestLicense', function(targetId) local src = source debugPrint("=== Event: requestLicense ===") @@ -459,7 +518,7 @@ RegisterNetEvent('license-system:server:requestLicense', function(targetId) for _, licenseType in ipairs(licenseTypes) do if Config.LicenseTypes[licenseType] then - local license = getLicenseFromDB(citizenid, licenseType) + local license = getLicenseFromDB(citizenid, licenseType, true) -- Skip Cache für frische Daten if license then foundLicense = { @@ -502,7 +561,7 @@ RegisterNetEvent('license-system:server:requestMyLicense', function(licenseType) debugPrint("Kein Lizenztyp angegeben, verwende: " .. licenseType) end - local license = getLicenseFromDB(citizenid, licenseType) + local license = getLicenseFromDB(citizenid, licenseType, true) -- Skip Cache für frische Daten if license then local licenseData = { @@ -544,7 +603,7 @@ RegisterNetEvent('license-system:server:requestPlayerLicenses', function(targetI TriggerClientEvent('license-system:client:receivePlayerLicenses', src, licenses, targetId, targetName) end) --- EVENT HANDLER: Lizenz ausstellen +-- EVENT HANDLER: Lizenz ausstellen (KORRIGIERT) RegisterNetEvent('license-system:server:issueLicense', function(targetId, licenseType, classes) local src = source debugPrint("=== Event: issueLicense ===") @@ -572,10 +631,10 @@ RegisterNetEvent('license-system:server:issueLicense', function(targetId, licens local targetCitizenId = targetPlayer.PlayerData.citizenid local issuerCitizenId = issuerPlayer.PlayerData.citizenid - -- Prüfen ob aktive Lizenz bereits existiert - local existingLicense = getLicenseFromDB(targetCitizenId, licenseType) + -- Prüfen ob aktive Lizenz bereits existiert (Skip Cache) + local existingLicense = getLicenseFromDB(targetCitizenId, licenseType, true) - if existingLicense and existingLicense.is_active == 1 then + if existingLicense then debugPrint("Lizenz bereits vorhanden und aktiv") TriggerClientEvent('QBCore:Notify', src, 'Spieler hat bereits eine aktive ' .. (Config.LicenseTypes[licenseType].label or licenseType) .. '!', 'error') return @@ -663,7 +722,8 @@ RegisterNetEvent('license-system:server:revokeLicense', function(targetId, licen debugPrint("Lizenz " .. licenseType .. " entzogen von " .. issuerName .. " für " .. targetName) else debugPrint("^1Fehler beim Entziehen der Lizenz^7") - TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Entziehen der Lizenz!', 'error') + TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Entziehen der Lizenz!', + 'error') end end) @@ -671,8 +731,8 @@ end) exports('hasLicense', function(citizenid, licenseType) if not citizenid or not licenseType then return false end - local license = getLicenseFromDB(citizenid, licenseType) - return license ~= nil and (license.is_active == 1 or license.is_active == nil) + local license = getLicenseFromDB(citizenid, licenseType, true) -- Skip Cache für aktuelle Daten + return license ~= nil end) exports('issueLicense', function(citizenid, licenseType, issuedBy, classes) @@ -697,7 +757,7 @@ end) exports('getPlayerLicense', function(citizenid, licenseType) if not citizenid or not licenseType then return nil end - return getLicenseFromDB(citizenid, licenseType) + return getLicenseFromDB(citizenid, licenseType, true) -- Skip Cache end) -- DEBUG COMMAND: Lizenz manuell erstellen @@ -726,7 +786,7 @@ RegisterCommand('createlicense', function(source, args, rawCommand) end end, true) --- DEBUG COMMAND: Lizenz prüfen +-- DEBUG COMMAND: Lizenz prüfen (ERWEITERT) RegisterCommand('checklicense', function(source, args, rawCommand) if source == 0 then -- Console only if #args < 2 then @@ -737,30 +797,127 @@ RegisterCommand('checklicense', function(source, args, rawCommand) local citizenid = args[1] local licenseType = args[2] - local license = getLicenseFromDB(citizenid, licenseType) + -- Direkte DB-Abfrage ohne Cache + local query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? ORDER BY created_at DESC" + local result = MySQL.query.await(query, {citizenid, licenseType}) - if license then - print("=== LIZENZ GEFUNDEN ===") - print("ID: " .. (license.id or "N/A")) - print("CitizenID: " .. (license.citizenid or "N/A")) - print("Typ: " .. (license.license_type or "N/A")) - print("Name: " .. (license.name or "N/A")) - print("Ausstellungsdatum: " .. (license.issue_date or "N/A")) - print("Ablaufdatum: " .. (license.expire_date or "N/A")) - print("Ausgestellt von: " .. (license.issued_by or "N/A")) - print("Aktiv: " .. tostring(license.is_active)) - print("Klassen: " .. (license.classes and json.encode(license.classes) or "[]")) - print("Erstellt am: " .. (license.created_at or "N/A")) - print("=====================") + if result and #result > 0 then + print("=== ALLE LIZENZEN GEFUNDEN ===") + for i, license in ipairs(result) do + print("--- Lizenz " .. i .. " ---") + print("ID: " .. (license.id or "N/A")) + print("CitizenID: " .. (license.citizenid or "N/A")) + print("Typ: " .. (license.license_type or "N/A")) + print("Name: " .. (license.name or "N/A")) + print("Ausstellungsdatum: " .. (license.issue_date or "N/A")) + print("Ablaufdatum: " .. (license.expire_date or "N/A")) + print("Ausgestellt von: " .. (license.issued_by or "N/A")) + print("Aktiv (DB): " .. tostring(license.is_active)) + print("Klassen: " .. (license.classes or "[]")) + print("Erstellt am: " .. (license.created_at or "N/A")) + print("---") + end + print("===============================") + + -- Zusätzlich: Lizenz über Funktion prüfen + local license = getLicenseFromDB(citizenid, licenseType, true) + if license then + print("=== AKTIVE LIZENZ (über Funktion) ===") + print("Typ: " .. license.license_type) + print("Aktiv: " .. tostring(license.is_active)) + print("Status-Check: " .. tostring(isLicenseActive(license))) + print("====================================") + else + print("=== KEINE AKTIVE LIZENZ (über Funktion) ===") + end else print("Keine Lizenz gefunden für: " .. citizenid .. " / " .. licenseType) end end end, true) +-- DEBUG COMMAND: Alle Lizenzen eines Spielers anzeigen +RegisterCommand('checkalllicenses', function(source, args, rawCommand) + if source == 0 then -- Console only + if #args < 1 then + print("Usage: checkalllicenses ") + return + end + + local citizenid = args[1] + + -- Direkte DB-Abfrage + local query = "SELECT * FROM player_licenses WHERE citizenid = ? ORDER BY license_type, created_at DESC" + local result = MySQL.query.await(query, {citizenid}) + + if result and #result > 0 then + print("=== ALLE LIZENZEN FÜR " .. citizenid .. " ===") + for i, license in ipairs(result) do + print(i .. ". " .. license.license_type .. " | Aktiv: " .. tostring(license.is_active) .. " | ID: " .. license.id) + end + print("=========================================") + + -- Über Funktion + local activeLicenses = getAllPlayerLicenses(citizenid) + print("=== AKTIVE LIZENZEN (über Funktion) ===") + for i, license in ipairs(activeLicenses) do + print(i .. ". " .. license.license_type .. " | Aktiv: " .. tostring(license.is_active)) + end + print("======================================") + else + print("Keine Lizenzen gefunden für: " .. citizenid) + end + end +end, true) + +-- DEBUG COMMAND: Lizenz-Status forciert aktualisieren +RegisterCommand('fixlicense', function(source, args, rawCommand) + if source == 0 then -- Console only + if #args < 2 then + print("Usage: fixlicense ") + return + end + + local citizenid = args[1] + local licenseType = args[2] + + -- Neueste Lizenz auf aktiv setzen + local query = [[ + UPDATE player_licenses + SET is_active = 1 + WHERE citizenid = ? AND license_type = ? AND id = ( + SELECT id FROM ( + SELECT id FROM player_licenses + WHERE citizenid = ? AND license_type = ? + ORDER BY created_at DESC LIMIT 1 + ) as temp + ) + ]] + + local result = MySQL.query.await(query, {citizenid, licenseType, citizenid, licenseType}) + + if result then + print("Lizenz-Status aktualisiert für: " .. citizenid .. " / " .. licenseType) + + -- Cache invalidieren + invalidateCache(citizenid, licenseType) + + -- Prüfen + local license = getLicenseFromDB(citizenid, licenseType, true) + if license then + print("Lizenz ist jetzt aktiv: " .. tostring(license.is_active)) + else + print("Lizenz konnte nicht geladen werden") + end + else + print("Fehler beim Aktualisieren der Lizenz") + end + end +end, true) + -- INITIALISIERUNG CreateThread(function() - debugPrint("License-System Server gestartet (Ausweis-Fix)") + debugPrint("License-System Server gestartet (Status-Fix)") -- Warten bis QBCore geladen ist while not QBCore do @@ -827,5 +984,4 @@ function table.count(t) return count end -debugPrint("License-System Server vollständig geladen (Ausweis-Fix)") - +debugPrint("License-System Server vollständig geladen (Status-Fix)")