Files
2026-08-05 01:29:39 +02:00

137 lines
5.9 KiB
Lua

local function cleanText(value, minimum, maximum)
if type(value) ~= 'string' then return nil end
value = value:gsub('^%s+', ''):gsub('%s+$', '')
if #value < minimum or #value > maximum then return nil end
return value
end
local function ensureColumn(name, definition)
local exists = MySQL.scalar.await([[
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'devx_phone_contacts' AND COLUMN_NAME = ?
]], { name })
if tonumber(exists) == 0 then
MySQL.query.await(('ALTER TABLE devx_phone_contacts ADD COLUMN `%s` %s'):format(name, definition))
end
end
MySQL.ready(function()
ensureColumn('contact_type', "VARCHAR(32) NOT NULL DEFAULT 'player' AFTER phone_number")
ensureColumn('metadata', 'LONGTEXT NULL AFTER contact_type')
end)
local function addSystemContact(characterId, name, number, contactType, metadata)
characterId = tonumber(characterId)
name = cleanText(name, 2, 64)
number = cleanText(number, 4, 24)
contactType = cleanText(contactType or 'system', 2, 32)
if not characterId or not name or not number or not contactType then return false, 'Ungültiger Systemkontakt.' end
local existing = MySQL.scalar.await([[
SELECT id FROM devx_phone_contacts
WHERE character_id = ? AND phone_number = ? AND contact_type = ? LIMIT 1
]], { characterId, number, contactType })
if existing then return true, tonumber(existing) end
local id = MySQL.insert.await([[
INSERT INTO devx_phone_contacts
(character_id, contact_name, phone_number, contact_type, metadata)
VALUES (?, ?, ?, ?, ?)
]], { characterId, name, number, contactType, metadata and json.encode(metadata) or nil })
return id ~= nil, id
end
exports('AddSystemContact', addSystemContact)
DevXRegisterCallback('phone:state', function(source)
local player = exports.devx_core:GetPlayer(source)
if not player then return { ok = false, error = 'Kein Charakter aktiv.' } end
local contacts = MySQL.query.await([[
SELECT id, contact_name AS contactName, phone_number AS phoneNumber,
contact_type AS contactType, metadata
FROM devx_phone_contacts
WHERE character_id = ?
ORDER BY contact_name ASC
]], { player.characterId }) or {}
for _, contact in ipairs(contacts) do
contact.id = tonumber(contact.id)
if type(contact.metadata) == 'string' and contact.metadata ~= '' then
local ok, decoded = pcall(json.decode, contact.metadata)
contact.metadata = ok and decoded or {}
else
contact.metadata = {}
end
end
return {
ok = true,
phoneNumber = player.phoneNumber,
rpXp = player.rpXp or 0,
contacts = contacts
}
end)
DevXRegisterCallback('phone:contactCreate', function(source, payload)
local player = exports.devx_core:GetPlayer(source)
if not player then return { ok = false, error = 'Kein Charakter aktiv.' } end
local name = cleanText(payload.contactName, 2, 64)
local number = cleanText(payload.phoneNumber, 4, 16)
if not name or not number or not number:match('^[%d%-]+$') then
return { ok = false, error = 'Name oder Telefonnummer ist ungültig.' }
end
local exists = MySQL.scalar.await('SELECT id FROM devx_characters WHERE phone_number = ? LIMIT 1', { number })
if not exists then return { ok = false, error = 'Diese Telefonnummer existiert nicht.' } end
local duplicate = MySQL.scalar.await([[
SELECT id FROM devx_phone_contacts WHERE character_id = ? AND phone_number = ? LIMIT 1
]], { player.characterId, number })
if duplicate then return { ok = false, error = 'Diese Nummer ist bereits gespeichert.' } end
local id = MySQL.insert.await([[
INSERT INTO devx_phone_contacts (character_id, contact_name, phone_number, contact_type)
VALUES (?, ?, ?, 'player')
]], { player.characterId, name, number })
return id and { ok = true } or { ok = false, error = 'Kontakt konnte nicht gespeichert werden.' }
end)
DevXRegisterCallback('phone:contactDelete', function(source, payload)
local player = exports.devx_core:GetPlayer(source)
local contactId = tonumber(payload.contactId)
if not player or not contactId then return { ok = false, error = 'Ungültige Anfrage.' } end
local contact = MySQL.single.await([[
SELECT contact_type AS contactType FROM devx_phone_contacts
WHERE id = ? AND character_id = ? LIMIT 1
]], { contactId, player.characterId })
if not contact then return { ok = false, error = 'Kontakt wurde nicht gefunden.' } end
if contact.contactType ~= 'player' then return { ok = false, error = 'Dieser Kontakt gehört zu einer freigeschalteten Beziehung.' } end
local changed = MySQL.update.await('DELETE FROM devx_phone_contacts WHERE id = ? AND character_id = ?', { contactId, player.characterId })
return changed and changed > 0 and { ok = true } or { ok = false, error = 'Kontakt wurde nicht gefunden.' }
end)
DevXRegisterCallback('phone:companionInvite', function(source)
if GetResourceState('devx_stripclub') ~= 'started' then
return { ok = false, error = 'Die Begleiterfunktion ist nicht aktiv.' }
end
return exports.devx_stripclub:InviteCompanion(source)
end)
DevXRegisterCallback('phone:bankOverview', function(source)
local player = exports.devx_core:GetPlayer(source)
if not player then return { ok = false, error = 'Kein Charakter aktiv.' } end
local overview = exports.devx_banking:GetOverview(player.characterId)
return overview and { ok = true, overview = overview } or { ok = false, error = 'Kein Bankkonto gefunden.' }
end)
DevXRegisterCallback('phone:bankTransfer', function(source, payload)
local success, result = exports.devx_banking:TransferForSource(source, payload)
return success and { ok = true, balance = result } or { ok = false, error = result }
end)