mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-04 16:23:22 +00:00
ENH - expand phone apps and polish iOS UI
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
Bridge.Database.AfterMigration("sky_phone", function()
|
||||
local marker_colors = {
|
||||
blue = true,
|
||||
green = true,
|
||||
orange = true,
|
||||
purple = true,
|
||||
red = true,
|
||||
}
|
||||
|
||||
local function affected_rows(result)
|
||||
if type(result) == "number" then
|
||||
return result
|
||||
end
|
||||
|
||||
return type(result) == "table" and tonumber(result.affectedRows) or 0
|
||||
end
|
||||
|
||||
local function text_length(value)
|
||||
return type(value) == "string" and utf8.len(value) or nil
|
||||
end
|
||||
|
||||
local function marker_dto(row)
|
||||
return {
|
||||
id = row.id,
|
||||
label = row.label,
|
||||
color = row.color,
|
||||
coords = {
|
||||
x = tonumber(row.position_x) or 0.0,
|
||||
y = tonumber(row.position_y) or 0.0,
|
||||
z = tonumber(row.position_z) or 0.0,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local function validate_marker(data)
|
||||
if type(data) ~= "table" or type(data.coords) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local label = type(data.label) == "string" and data.label:match("^%s*(.-)%s*$") or nil
|
||||
local label_length = text_length(label)
|
||||
local color = data.color
|
||||
local x = tonumber(data.coords.x)
|
||||
local y = tonumber(data.coords.y)
|
||||
local z = tonumber(data.coords.z)
|
||||
if not label_length
|
||||
or label_length < 1
|
||||
or label_length > Config.MapMarkers.LabelMaxLength
|
||||
or not marker_colors[color]
|
||||
or not x
|
||||
or not y
|
||||
or (data.coords.z ~= nil and not z)
|
||||
or x ~= x
|
||||
or y ~= y
|
||||
or (z and z ~= z)
|
||||
or math.abs(x) > 10000.0
|
||||
or math.abs(y) > 10000.0
|
||||
or (z and z < -1000.0)
|
||||
or (z and z > 3000.0)
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
label = label,
|
||||
color = color,
|
||||
x = x,
|
||||
y = y,
|
||||
z = z or 0.0,
|
||||
}
|
||||
end
|
||||
|
||||
Bridge.Callbacks.Register("sky_phone:map:markers", function(source)
|
||||
local session, error_response = SkyPhone.RequireSession(source)
|
||||
if not session then
|
||||
return error_response
|
||||
end
|
||||
|
||||
local rows = Bridge.Database.Query([[
|
||||
SELECT `id`, `label`, `color`, `position_x`, `position_y`, `position_z`
|
||||
FROM `sky_phone_map_markers`
|
||||
WHERE `device_imei` = ?
|
||||
ORDER BY `created_at`, `id`
|
||||
LIMIT ?
|
||||
]], { session.imei, Config.MapMarkers.MaximumMarkers })
|
||||
local markers = {}
|
||||
for index = 1, #rows do
|
||||
markers[index] = marker_dto(rows[index])
|
||||
end
|
||||
return { success = true, data = markers }
|
||||
end)
|
||||
|
||||
Bridge.Callbacks.Register("sky_phone:map:create-marker", function(source, data)
|
||||
if not SkyPhone.AllowOperation(source, "map_marker_write", Config.MapMarkers.ActionsPerMinute, 60) then
|
||||
return { success = false, error = "rate_limited" }
|
||||
end
|
||||
|
||||
local session, error_response = SkyPhone.RequireSession(source)
|
||||
if not session then
|
||||
return error_response
|
||||
end
|
||||
|
||||
local marker = validate_marker(data)
|
||||
if not marker then
|
||||
return { success = false, error = "invalid_marker" }
|
||||
end
|
||||
|
||||
local count_rows = Bridge.Database.Query([[
|
||||
SELECT COUNT(*) AS `count`
|
||||
FROM `sky_phone_map_markers`
|
||||
WHERE `device_imei` = ?
|
||||
]], { session.imei })
|
||||
if (tonumber(count_rows[1] and count_rows[1].count) or 0) >= Config.MapMarkers.MaximumMarkers then
|
||||
return { success = false, error = "marker_limit" }
|
||||
end
|
||||
|
||||
local ids = Bridge.Database.Query("SELECT UUID() AS `id`", {})
|
||||
local id = ids[1] and ids[1].id
|
||||
if type(id) ~= "string" then
|
||||
error("[sky_phone] Database did not generate a map marker id.")
|
||||
end
|
||||
|
||||
Bridge.Database.Query([[
|
||||
INSERT INTO `sky_phone_map_markers`
|
||||
(`id`, `device_imei`, `label`, `color`, `position_x`, `position_y`, `position_z`)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
]], { id, session.imei, marker.label, marker.color, marker.x, marker.y, marker.z })
|
||||
return {
|
||||
success = true,
|
||||
data = {
|
||||
id = id,
|
||||
label = marker.label,
|
||||
color = marker.color,
|
||||
coords = { x = marker.x, y = marker.y, z = marker.z },
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
Bridge.Callbacks.Register("sky_phone:map:delete-marker", function(source, data)
|
||||
if not SkyPhone.AllowOperation(source, "map_marker_write", Config.MapMarkers.ActionsPerMinute, 60) then
|
||||
return { success = false, error = "rate_limited" }
|
||||
end
|
||||
|
||||
local session, error_response = SkyPhone.RequireSession(source)
|
||||
if not session then
|
||||
return error_response
|
||||
end
|
||||
if type(data) ~= "table" or type(data.id) ~= "string" or #data.id ~= 36 then
|
||||
return { success = false, error = "invalid_marker" }
|
||||
end
|
||||
|
||||
local result = Bridge.Database.Query(
|
||||
"DELETE FROM `sky_phone_map_markers` WHERE `id` = ? AND `device_imei` = ?",
|
||||
{ data.id, session.imei }
|
||||
)
|
||||
if affected_rows(result) ~= 1 then
|
||||
return { success = false, error = "marker_not_found" }
|
||||
end
|
||||
return { success = true }
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user