137 lines
5.9 KiB
Lua
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)
|