From 06087a78007acb8879cd32f463aad2f1f5766c51 Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Tue, 12 Aug 2025 19:00:26 +0200 Subject: [PATCH] ed --- .../[tools]/nordi_infopoint/client/main.lua | 283 ++++++++++++++++++ resources/[tools]/nordi_infopoint/config.lua | 26 +- .../[tools]/nordi_infopoint/server/main.lua | 179 +++++++++++ 3 files changed, 486 insertions(+), 2 deletions(-) diff --git a/resources/[tools]/nordi_infopoint/client/main.lua b/resources/[tools]/nordi_infopoint/client/main.lua index 1a62c3040..d9f7c4f61 100644 --- a/resources/[tools]/nordi_infopoint/client/main.lua +++ b/resources/[tools]/nordi_infopoint/client/main.lua @@ -72,6 +72,14 @@ function openInfoPointMenu() onSelect = function() showEvents() end + }, + { + title = 'Allgemeine Informationen', + description = 'Wichtige Bekanntmachungen und Hinweise', + icon = 'bullhorn', + onSelect = function() + showGeneralInfo() + end } } @@ -104,6 +112,26 @@ function openInfoPointMenu() }) end + -- Option to post general information (only for authorized jobs) + local canPostInfo = false + for _, allowedJob in pairs(Config.JobPermissions.canPostGeneralInfo) do + if job == allowedJob then + canPostInfo = true + break + end + end + + if canPostInfo then + table.insert(menuOptions, { + title = 'Information veröffentlichen', + description = 'Neue allgemeine Information erstellen', + icon = 'pen', + onSelect = function() + createGeneralInfoDialog() + end + }) + end + -- Vorfall melden (für alle oder spezifische Jobs) if Config.JobPermissions.canReportIncidents == 'all' or (type(Config.JobPermissions.canReportIncidents) == 'table' and @@ -665,6 +693,261 @@ function editLicenseInfoDialog(license) end end +-- Show general information +function showGeneralInfo() + QBCore.Functions.TriggerCallback('infopoint:getGeneralInfo', function(infoList) + local infoOptions = {} + + if #infoList == 0 then + table.insert(infoOptions, { + title = 'Keine Informationen verfügbar', + description = 'Derzeit sind keine allgemeinen Informationen vorhanden', + icon = 'info' + }) + else + for _, info in pairs(infoList) do + local importanceIcon = '📄' + if info.importance == 'high' then + importanceIcon = '🔴' + elseif info.importance == 'medium' then + importanceIcon = '🟠' + end + + local createdDate = os.date('%d.%m.%Y', os.time({ + year = tonumber(string.sub(info.created_at, 1, 4)), + month = tonumber(string.sub(info.created_at, 6, 7)), + day = tonumber(string.sub(info.created_at, 9, 10)) + })) + + table.insert(infoOptions, { + title = importanceIcon .. ' ' .. info.title, + description = 'Kategorie: ' .. info.category .. ' | Erstellt: ' .. createdDate, + icon = 'bullhorn', + onSelect = function() + showGeneralInfoDetails(info) + end + }) + end + end + + table.insert(infoOptions, { + title = '← Zurück', + icon = 'arrow-left', + onSelect = function() + openInfoPointMenu() + end + }) + + lib.registerContext({ + id = 'infopoint_general_info', + title = 'Allgemeine Informationen', + options = infoOptions + }) + + lib.showContext('infopoint_general_info') + end) +end + +-- Show general information details +function showGeneralInfoDetails(info) + local PlayerData = QBCore.Functions.GetPlayerData() + local canManage = false + + -- Check if player can manage this info (created by them or has management rights) + if PlayerData.citizenid == info.created_by then + canManage = true + end + + -- Check if player has permission to post general info (they can also manage) + local job = PlayerData.job.name + for _, allowedJob in pairs(Config.JobPermissions.canPostGeneralInfo) do + if job == allowedJob then + canManage = true + break + end + end + + -- If they can manage, show management options + if canManage then + local options = { + { + title = 'Information anzeigen', + description = 'Details der Information anzeigen', + icon = 'eye', + onSelect = function() + showInfoContent(info) + end + }, + { + title = '✏️ Bearbeiten', + description = 'Information bearbeiten', + icon = 'edit', + onSelect = function() + editGeneralInfoDialog(info) + end + }, + { + title = '🗑️ Löschen', + description = 'Information löschen', + icon = 'trash', + onSelect = function() + deleteGeneralInfo(info.id) + end + }, + { + title = '← Zurück', + icon = 'arrow-left', + onSelect = function() + showGeneralInfo() + end + } + } + + lib.registerContext({ + id = 'general_info_management', + title = info.title, + options = options + }) + + lib.showContext('general_info_management') + return + end + + -- If they can't manage, just show the content + showInfoContent(info) +end + +-- Function to show just the content +function showInfoContent(info) + local createdDate = os.date('%d.%m.%Y', os.time({ + year = tonumber(string.sub(info.created_at, 1, 4)), + month = tonumber(string.sub(info.created_at, 6, 7)), + day = tonumber(string.sub(info.created_at, 9, 10)) + })) + + local expiryInfo = '' + if info.expires_at then + local expiryDate = os.date('%d.%m.%Y', os.time({ + year = tonumber(string.sub(info.expires_at, 1, 4)), + month = tonumber(string.sub(info.expires_at, 6, 7)), + day = tonumber(string.sub(info.expires_at, 9, 10)) + })) + expiryInfo = 'Gültig bis: ' .. expiryDate .. '\n\n' + end + + local importanceText = 'Normal' + if info.importance == 'high' then + importanceText = 'Hoch' + elseif info.importance == 'medium' then + importanceText = 'Mittel' + end + + lib.alertDialog({ + header = info.title, + content = 'Kategorie: ' .. info.category .. '\n\n' .. + 'Wichtigkeit: ' .. importanceText .. '\n\n' .. + 'Erstellt am: ' .. createdDate .. '\n\n' .. + expiryInfo .. + 'Inhalt:\n' .. info.content .. '\n\n' .. + 'Veröffentlicht von: ' .. info.created_by_name .. ' (' .. info.created_by_job .. ')', + centered = true, + cancel = true + }) +end + +-- Create general information dialog +function createGeneralInfoDialog() + local categoryOptions = {} + for _, category in pairs(Config.GeneralInfoCategories) do + table.insert(categoryOptions, {value = category, label = category}) + end + + local importanceOptions = { + {value = 'normal', label = 'Normal'}, + {value = 'medium', label = 'Mittel'}, + {value = 'high', label = 'Hoch'} + } + + local input = lib.inputDialog('Information veröffentlichen', { + {type = 'input', label = 'Titel', required = true, max = 100}, + {type = 'textarea', label = 'Inhalt', required = true, max = 1000}, + {type = 'select', label = 'Kategorie', options = categoryOptions, required = true}, + {type = 'select', label = 'Wichtigkeit', options = importanceOptions, default = 'normal'}, + {type = 'date', label = 'Gültig bis (optional)'} + }) + + if input then + local infoData = { + title = input[1], + content = input[2], + category = input[3], + importance = input[4], + expires_at = input[5] ~= '' and input[5] or nil + } + + TriggerServerEvent('infopoint:createGeneralInfo', infoData) + end +end + +-- Function to edit general info +function editGeneralInfoDialog(info) + local categoryOptions = {} + for _, category in pairs(Config.GeneralInfoCategories) do + table.insert(categoryOptions, {value = category, label = category}) + end + + local importanceOptions = { + {value = 'normal', label = 'Normal'}, + {value = 'medium', label = 'Mittel'}, + {value = 'high', label = 'Hoch'} + } + + local expiryDate = nil + if info.expires_at then + expiryDate = string.sub(info.expires_at, 1, 10) + end + + local input = lib.inputDialog('Information bearbeiten', { + {type = 'input', label = 'Titel', required = true, max = 100, default = info.title}, + {type = 'textarea', label = 'Inhalt', required = true, max = 1000, default = info.content}, + {type = 'select', label = 'Kategorie', options = categoryOptions, required = true, default = info.category}, + {type = 'select', label = 'Wichtigkeit', options = importanceOptions, default = info.importance}, + {type = 'date', label = 'Gültig bis (optional)', default = expiryDate} + }) + + if input then + local infoData = { + title = input[1], + content = input[2], + category = input[3], + importance = input[4], + expires_at = input[5] ~= '' and input[5] or nil + } + + TriggerServerEvent('infopoint:updateGeneralInfo', info.id, infoData) + end +end + +-- Function to delete general info +function deleteGeneralInfo(infoId) + lib.alertDialog({ + header = 'Information löschen', + content = 'Bist du sicher, dass du diese Information löschen möchtest?', + centered = true, + cancel = true, + labels = { + cancel = 'Abbrechen', + confirm = 'Löschen' + } + }, function(confirmed) + if confirmed then + TriggerServerEvent('infopoint:deleteGeneralInfo', infoId) + Wait(500) + showGeneralInfo() -- Back to overview + end + end) +end + -- Hilfsfunktion für table.contains function table.contains(table, element) for _, value in pairs(table) do diff --git a/resources/[tools]/nordi_infopoint/config.lua b/resources/[tools]/nordi_infopoint/config.lua index 790566bfe..04496e357 100644 --- a/resources/[tools]/nordi_infopoint/config.lua +++ b/resources/[tools]/nordi_infopoint/config.lua @@ -47,8 +47,11 @@ Config.JobPermissions = { -- Wer kann Vorfälle melden canReportIncidents = 'all', -- 'all' für alle, oder spezifische Jobs als Table --- Who can manage license information -canManageLicenses = {'police'}, -- Add any other jobs that should be able to manage licenses + -- Wer kann Lizenz-Informationen verwalten + canManageLicenses = {'police'}, -- Add any other jobs that should be able to manage licenses + + -- Wer kann allgemeine Informationen veröffentlichen + canPostGeneralInfo = {'police', 'ambulance'}, -- Spezielle Job Informationen jobSpecificInfo = { @@ -102,3 +105,22 @@ Config.EventCategories = { 'Rennen', 'Sonstiges' } + +-- Allgemeine Informations-Kategorien +Config.GeneralInfoCategories = { + 'Öffentliche Bekanntmachung', + 'Sicherheitshinweis', + 'Gesundheitshinweis', + 'Verkehrsinformation', + 'Bürgerinformation', + 'Sonstiges' +} + +-- Standard Lizenz-Typen +Config.DefaultLicenseTypes = { + 'Führerschein', + 'Waffenschein', + 'Pilotenschein', + 'Motorradführerschein', + 'Bootslizenz' +} diff --git a/resources/[tools]/nordi_infopoint/server/main.lua b/resources/[tools]/nordi_infopoint/server/main.lua index b73b78aab..79fca0f34 100644 --- a/resources/[tools]/nordi_infopoint/server/main.lua +++ b/resources/[tools]/nordi_infopoint/server/main.lua @@ -65,6 +65,23 @@ CreateThread(function() ) ]]) + -- Neue Tabelle für allgemeine Informationen + MySQL.query([[ + CREATE TABLE IF NOT EXISTS infopoint_general_info ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + content TEXT, + category VARCHAR(100), + importance VARCHAR(50) DEFAULT 'normal', + created_by VARCHAR(50), + created_by_job VARCHAR(50), + created_by_name VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + expires_at DATETIME NULL, + active BOOLEAN DEFAULT TRUE + ) + ]]) + -- Standard Lizenz-Informationen einfügen falls nicht vorhanden MySQL.query('SELECT COUNT(*) as count FROM infopoint_license_info', {}, function(result) if result[1].count == 0 then @@ -174,6 +191,15 @@ QBCore.Functions.CreateCallback('infopoint:getLicenseInfo', function(source, cb) end) end) +-- Allgemeine Informationen abrufen +QBCore.Functions.CreateCallback('infopoint:getGeneralInfo', function(source, cb) + local currentDate = os.date('%Y-%m-%d') + + MySQL.query('SELECT * FROM infopoint_general_info WHERE active = 1 AND (expires_at IS NULL OR expires_at >= ?) ORDER BY importance DESC, created_at DESC', {currentDate}, function(result) + cb(result) + end) +end) + -- Prüfen ob Spieler Lizenz-Informationen verwalten kann QBCore.Functions.CreateCallback('infopoint:canManageLicenses', function(source, cb) local Player = QBCore.Functions.GetPlayer(source) @@ -435,3 +461,156 @@ RegisterNetEvent('infopoint:deleteLicenseInfo', function(licenseId) end end) end) + +-- Allgemeine Information erstellen +RegisterNetEvent('infopoint:createGeneralInfo', function(infoData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if not Player then return end + + local job = Player.PlayerData.job.name + local canPost = false + + -- Sicherheitsprüfung für Config + if Config and Config.JobPermissions and Config.JobPermissions.canPostGeneralInfo then + if type(Config.JobPermissions.canPostGeneralInfo) == 'table' then + for _, allowedJob in pairs(Config.JobPermissions.canPostGeneralInfo) do + if job == allowedJob then + canPost = true + break + end + end + end + end + + if not canPost then + TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung allgemeine Informationen zu veröffentlichen!', 'error') + return + end + + MySQL.insert('INSERT INTO infopoint_general_info (title, content, category, importance, expires_at, created_by, created_by_job, created_by_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', { + infoData.title, + infoData.content, + infoData.category, + infoData.importance, + infoData.expires_at, + Player.PlayerData.citizenid, + Player.PlayerData.job.name, + Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname + }, function(insertId) + if insertId then + TriggerClientEvent('QBCore:Notify', src, 'Information erfolgreich veröffentlicht!', 'success') + TriggerClientEvent('infopoint:refreshData', -1) + end + end) +end) + +-- Allgemeine Information bearbeiten +RegisterNetEvent('infopoint:updateGeneralInfo', function(infoId, infoData) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if not Player then return end + + -- First check if this player created the info or has permission to post general info + MySQL.query('SELECT created_by FROM infopoint_general_info WHERE id = ?', {infoId}, function(result) + if result[1] then + local canEdit = false + + -- Check if player created this info + if result[1].created_by == Player.PlayerData.citizenid then + canEdit = true + end + + -- Check if player has permission to post general info (they can also edit) + if not canEdit then + local job = Player.PlayerData.job.name + if Config and Config.JobPermissions and Config.JobPermissions.canPostGeneralInfo then + if type(Config.JobPermissions.canPostGeneralInfo) == 'table' then + for _, allowedJob in pairs(Config.JobPermissions.canPostGeneralInfo) do + if job == allowedJob then + canEdit = true + break + end + end + end + end + end + + if not canEdit then + TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diese Information zu bearbeiten!', 'error') + return + end + + -- Update the info + MySQL.update('UPDATE infopoint_general_info SET title = ?, content = ?, category = ?, importance = ?, expires_at = ? WHERE id = ?', { + infoData.title, + infoData.content, + infoData.category, + infoData.importance, + infoData.expires_at, + infoId + }, function(affectedRows) + if affectedRows > 0 then + TriggerClientEvent('QBCore:Notify', src, 'Information erfolgreich aktualisiert!', 'success') + TriggerClientEvent('infopoint:refreshData', -1) + else + TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Aktualisieren der Information!', 'error') + end + end) + else + TriggerClientEvent('QBCore:Notify', src, 'Information nicht gefunden!', 'error') + end + end) +end) + +-- Allgemeine Information löschen +RegisterNetEvent('infopoint:deleteGeneralInfo', function(infoId) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if not Player then return end + + -- First check if this player created the info or has permission to post general info + MySQL.query('SELECT created_by FROM infopoint_general_info WHERE id = ?', {infoId}, function(result) + if result[1] then + local canDelete = false + + -- Check if player created this info + if result[1].created_by == Player.PlayerData.citizenid then + canDelete = true + end + + -- Check if player has permission to post general info (they can also delete) + if not canDelete then + local job = Player.PlayerData.job.name + if Config and Config.JobPermissions and Config.JobPermissions.canPostGeneralInfo then + if type(Config.JobPermissions.canPostGeneralInfo) == 'table' then + for _, allowedJob in pairs(Config.JobPermissions.canPostGeneralInfo) do + if job == allowedJob then + canDelete = true + break + end + end + end + end + end + + if not canDelete then + TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung diese Information zu löschen!', 'error') + return + end + + -- Delete (set inactive) the info + MySQL.update('UPDATE infopoint_general_info SET active = 0 WHERE id = ?', {infoId}, function(affectedRows) + if affectedRows > 0 then + TriggerClientEvent('QBCore:Notify', src, 'Information erfolgreich gelöscht!', 'success') + TriggerClientEvent('infopoint:refreshData', -1) + else + TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Löschen der Information!', 'error') + end + end) + else + TriggerClientEvent('QBCore:Notify', src, 'Information nicht gefunden!', 'error') + end + end) +end) +