mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 04:01:32 +00:00
a9143b0fba
* ADD - build in-game admin command center * ADD - open admin panel by command * ENH - rebuild admin panel as standalone editor * ENH - compact admin workspace navigation * ENH - expand admin device controls * ENH - refine admin panel navigation style * ADD - add SQL phone configurator * FIX - expose complete phone configuration * FIX - make company jobs freely configurable * FIX - align configurator tables to left * ENH - organize configurator collection controls * ENH - organize nested configurator sections * ENH - add configurator field descriptions * FIX - hide fixed configurator add controls * ENH - refine configurator editing experience * ENH - refine admin configurator controls * FIX - apply configurator settings instantly * FIX - close live activity command registration --------- Co-authored-by: Leon.Schmidt <leonmauricewill15@gmail.com>
306 lines
10 KiB
Lua
306 lines
10 KiB
Lua
local NOTIFICATION_TEXT_MAX_LENGTH = 2000
|
|
local NOTIFICATION_TITLE_MAX_LENGTH = 160
|
|
local DEVICE_NAME_MAX_LENGTH = 128
|
|
|
|
SkyPhoneNotifications = {}
|
|
|
|
local function trim(value)
|
|
return value:match("^%s*(.-)%s*$")
|
|
end
|
|
|
|
local function normalize_text(value, error_code, maximum_length)
|
|
if type(value) ~= "string" then
|
|
return nil, error_code
|
|
end
|
|
|
|
local normalized = trim(value)
|
|
if normalized == "" or #normalized > maximum_length then
|
|
return nil, error_code
|
|
end
|
|
return normalized
|
|
end
|
|
|
|
local function resolve_alias(data, primary_key, alternate_key, error_code)
|
|
local primary = data[primary_key]
|
|
local alternate = data[alternate_key]
|
|
if primary ~= nil and alternate ~= nil and primary ~= alternate then
|
|
return nil, error_code
|
|
end
|
|
return primary ~= nil and primary or alternate
|
|
end
|
|
|
|
local function normalize_notification(notification)
|
|
if type(notification) ~= "table" then
|
|
return nil, "invalid_notification"
|
|
end
|
|
|
|
local app_id = resolve_alias(notification, "appId", "app_id", "invalid_app_id")
|
|
local valid_app_id = SkyPhoneApps.ValidateAppId(app_id)
|
|
if not valid_app_id or not SkyPhoneApps.CanReceiveNotification(app_id) then
|
|
return nil, "invalid_app_id"
|
|
end
|
|
|
|
local title, title_error = normalize_text(
|
|
notification.title,
|
|
"invalid_title",
|
|
NOTIFICATION_TITLE_MAX_LENGTH
|
|
)
|
|
if not title then
|
|
return nil, title_error
|
|
end
|
|
|
|
local raw_text = resolve_alias(notification, "text", "body", "invalid_text")
|
|
local notification_text, text_error = normalize_text(
|
|
raw_text,
|
|
"invalid_text",
|
|
NOTIFICATION_TEXT_MAX_LENGTH
|
|
)
|
|
if not notification_text then
|
|
return nil, text_error
|
|
end
|
|
|
|
return {
|
|
appId = app_id,
|
|
route = "/apps/" .. app_id,
|
|
text = notification_text,
|
|
title = title,
|
|
}
|
|
end
|
|
|
|
local function normalize_server_device(device)
|
|
if type(device) ~= "table"
|
|
or not SkyPhoneImei.IsValid(device.imei)
|
|
then
|
|
return nil, "invalid_device"
|
|
end
|
|
|
|
local name, name_error = normalize_text(
|
|
device.name,
|
|
"invalid_device",
|
|
DEVICE_NAME_MAX_LENGTH
|
|
)
|
|
if not name then
|
|
return nil, name_error
|
|
end
|
|
if device.settings ~= nil
|
|
and type(device.settings) ~= "string"
|
|
and type(device.settings) ~= "table"
|
|
then
|
|
return nil, "invalid_device"
|
|
end
|
|
|
|
return {
|
|
imei = device.imei,
|
|
name = name,
|
|
settings = device.settings,
|
|
}
|
|
end
|
|
|
|
local function show_normalized(notification)
|
|
SendNUIMessage({
|
|
type = "notification:show",
|
|
data = notification,
|
|
})
|
|
end
|
|
|
|
function SkyPhoneNotifications.Show(notification)
|
|
local normalized, error_code = normalize_notification(notification)
|
|
if not normalized then
|
|
return false, error_code
|
|
end
|
|
|
|
show_normalized(normalized)
|
|
return true
|
|
end
|
|
|
|
function SkyPhoneNotifications.Send(notification)
|
|
local normalized, error_code = normalize_notification(notification)
|
|
if not normalized then
|
|
return false, error_code
|
|
end
|
|
|
|
local result = Bridge.Callbacks.Trigger("sky_phone:notifications:self", normalized)
|
|
if type(result) ~= "table" or result.success ~= true then
|
|
return false, type(result) == "table" and result.error or "request_failed"
|
|
end
|
|
return true, result.data
|
|
end
|
|
|
|
RegisterNetEvent("sky_phone:notifications:show", function(notification)
|
|
if source ~= 65535 then
|
|
Bridge.Debug("warn", "[sky_phone] Rejected a client-triggered notification delivery event.")
|
|
return
|
|
end
|
|
|
|
local normalized, notification_error = normalize_notification(notification)
|
|
local device
|
|
local device_error = "invalid_device"
|
|
if type(notification) == "table" then
|
|
device, device_error = normalize_server_device(notification.device)
|
|
end
|
|
if not normalized or not device then
|
|
Bridge.Debug(
|
|
"warn",
|
|
"[sky_phone] Rejected an invalid server notification: %s.",
|
|
tostring(notification_error or device_error)
|
|
)
|
|
return
|
|
end
|
|
|
|
normalized.device = device
|
|
show_normalized(normalized)
|
|
TriggerEvent("sky_phone:client:pushNotification", {
|
|
appId = normalized.appId,
|
|
text = normalized.text,
|
|
title = normalized.title,
|
|
})
|
|
end)
|
|
|
|
local phone_locale = SkyPhoneLocales.Resolve(Config.Bridge.Locale)
|
|
local app_locales = phone_locale.Nui.Apps
|
|
|
|
AddEventHandler("sky_phone:configurator:updated", function()
|
|
phone_locale = SkyPhoneLocales.Resolve(Config.Bridge.Locale)
|
|
app_locales = phone_locale.Nui.Apps
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:mail:new", function(data)
|
|
local locale = app_locales.mail
|
|
data.title = locale.name
|
|
data.text = locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "mail:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:citywarn:changed", function(data)
|
|
if type(data) ~= "table" then
|
|
return
|
|
end
|
|
local locale = app_locales.citywarn
|
|
data.title = locale.name
|
|
data.text = locale.notifications[data.kind] or locale.notifications.update
|
|
SendNUIMessage({ type = "citywarn:changed", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:companies:notification", function(data)
|
|
local locale = app_locales.companies
|
|
data.title = locale.name
|
|
data.text = locale.notifications[data.kind] or locale.notifications.requestUpdated
|
|
SendNUIMessage({ type = "companies:notification", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:fliptok:command-feedback", function(data)
|
|
Bridge.Framework.Notify("FlipTok", data.message, data.notificationType, 5000)
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:fliptok:new", function(data)
|
|
local locale = app_locales.fliptok
|
|
local notification_text = locale.notifications[data.kind] or locale.notifications.default
|
|
data.title = locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "fliptok:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:picstagram:command-feedback", function(data)
|
|
Bridge.Framework.Notify("Picstagram", data.message, data.notificationType, 5000)
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:picstagram:new", function(data)
|
|
local locale = app_locales.picstagram
|
|
local notification_text = locale.notifications[data.kind] or locale.notifications.default
|
|
data.title = locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "picstagram:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:feather:new", function(data)
|
|
local locale = app_locales.feather
|
|
local notification_text = locale.notifications[data.kind] or locale.notifications.default
|
|
data.title = locale.name
|
|
data.text = notification_text:gsub("{actor}", tostring(data.actor or ""))
|
|
SendNUIMessage({ type = "feather:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:marketplace:new-message", function(data)
|
|
local locale = app_locales.citymarkt
|
|
data.title = locale.name
|
|
if data.kind == "offer" then
|
|
data.text = locale.newOffer
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
elseif data.kind == "offer-response" and data.action == "accepted" then
|
|
data.text = locale.offerAcceptedNotification
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
elseif data.kind == "offer-response" and data.action == "rejected" then
|
|
data.text = locale.offerRejectedNotification
|
|
:gsub("{sender}", tostring(data.sender))
|
|
:gsub("{price}", tostring(data.amount))
|
|
else
|
|
data.text = locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
end
|
|
SendNUIMessage({ type = "marketplace:new-message", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:calendar:reminder", function(data)
|
|
local locale = app_locales.calendar
|
|
data.title = locale.name
|
|
data.text = locale.reminder:gsub("{title}", tostring(data.eventTitle))
|
|
SendNUIMessage({ type = "calendar:reminder", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:flare:match", function(data)
|
|
local locale = app_locales.flare
|
|
data.title = locale.name
|
|
data.text = locale.newMatchNotification:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "flare:new-match", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:flare:message", function(data)
|
|
local locale = app_locales.flare
|
|
data.title = locale.name
|
|
data.text = locale.newMessageNotification:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "flare:new-message", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:billing:new", function(data)
|
|
local locale = app_locales.billing
|
|
data.title = locale.name
|
|
data.text = locale.notifications.newInvoice
|
|
:gsub("{issuer}", tostring(data.issuer))
|
|
:gsub("{amount}", ("%s %s"):format(tostring(data.amount), Config.Billing.Currency))
|
|
SendNUIMessage({ type = "billing:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:crewlink:notification", function(data)
|
|
local locale = app_locales.crewlink
|
|
local notification_text = locale.notifications[data.kind] or locale.notifications.default
|
|
data.title = locale.name
|
|
data.text = notification_text
|
|
:gsub("{actor}", tostring(data.actor or ""))
|
|
:gsub("{group}", tostring(data.groupName or ""))
|
|
:gsub("{ping}", tostring(data.pingLabel or ""))
|
|
SendNUIMessage({ type = "crewlink:notification", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:messages:new", function(data)
|
|
local locale = app_locales.messages
|
|
data.title = locale.name
|
|
data.text = locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
SendNUIMessage({ type = "messages:new", data = data })
|
|
end)
|
|
|
|
RegisterNetEvent("sky_phone:darkchat:new", function(data)
|
|
local locale = app_locales.darkchat
|
|
data.title = locale.name
|
|
if data.notificationMode == "private" then
|
|
data.sender = nil
|
|
data.text = locale.privateNotification
|
|
elseif data.notificationMode == "hidden" then
|
|
data.sender = nil
|
|
data.text = ""
|
|
else
|
|
data.text = locale.newMessage:gsub("{sender}", tostring(data.sender))
|
|
end
|
|
SendNUIMessage({ type = "darkchat:new", data = data })
|
|
end)
|