184 lines
7.5 KiB
Lua
184 lines
7.5 KiB
Lua
|
|
-- ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
-- Kalender
|
|||
|
|
--
|
|||
|
|
-- Drei Arten von Terminen:
|
|||
|
|
--
|
|||
|
|
-- privat gehoert einer Person, sonst sieht ihn niemand
|
|||
|
|
-- geteilt gehoert einem Postfach, sichtbar fuer alle, die es bedienen
|
|||
|
|
-- oeffentlich gehoert einem Postfach, sichtbar fuer jeden auf dem Server
|
|||
|
|
--
|
|||
|
|
-- Geteilt wird ueber dasselbe Mittel wie Postfaecher und Ordner: die Adresse.
|
|||
|
|
-- Ein oeffentlicher Termin haengt bewusst auch an einem Postfach – sonst gaebe
|
|||
|
|
-- es niemanden, der ihn spaeter aendern oder absagen koennte.
|
|||
|
|
-- ─────────────────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
--- Alle Postfaecher, die diese Person bedienen darf.
|
|||
|
|
---@return string[]
|
|||
|
|
local function MailboxesOf(identifier)
|
|||
|
|
if GetResourceState('ic-mail') ~= 'started' then return {} end
|
|||
|
|
|
|||
|
|
local out = {}
|
|||
|
|
for _, mb in ipairs(exports['ic-mail']:GetAddressesForIdentifier(identifier) or {}) do
|
|||
|
|
if mb.address then out[#out + 1] = mb.address end
|
|||
|
|
end
|
|||
|
|
return out
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local function CanUseMailbox(identifier, address)
|
|||
|
|
if address == '' then return true end
|
|||
|
|
for _, addr in ipairs(MailboxesOf(identifier)) do
|
|||
|
|
if addr == address then return true end
|
|||
|
|
end
|
|||
|
|
return false
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Darf diese Person den Termin aendern?
|
|||
|
|
--- Privat: nur wer ihn angelegt hat. Postfach: wer das Postfach bedient –
|
|||
|
|
--- auch wenn jemand anderes ihn eingetragen hat. Genau das macht ihn geteilt.
|
|||
|
|
local function CanEditEvent(identifier, event)
|
|||
|
|
if not event then return false end
|
|||
|
|
if event.address and event.address ~= '' then
|
|||
|
|
return CanUseMailbox(identifier, event.address)
|
|||
|
|
end
|
|||
|
|
return event.identifier == identifier
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Eingaben pruefen und in die Form bringen, die die Datenbank erwartet.
|
|||
|
|
--- Gibt (daten, adresse, sichtbarkeit) oder nil zurueck.
|
|||
|
|
local function ReadEvent(identifier, data)
|
|||
|
|
if type(data) ~= 'table' then return nil end
|
|||
|
|
|
|||
|
|
local d = {
|
|||
|
|
title = Utils.Sanitize(tostring(data.title or "")):sub(1, 120),
|
|||
|
|
description = Utils.Sanitize(tostring(data.description or "")):sub(1, 500),
|
|||
|
|
start_at = Utils.Sanitize(tostring(data.start_at or "")):sub(1, 20),
|
|||
|
|
end_at = data.end_at and Utils.Sanitize(tostring(data.end_at)):sub(1, 20) or nil,
|
|||
|
|
color = Utils.Sanitize(tostring(data.color or "#00aaff")):sub(1, 20),
|
|||
|
|
}
|
|||
|
|
if #d.title < 1 or #d.start_at < 1 then return nil end
|
|||
|
|
|
|||
|
|
local address = Utils.Sanitize(tostring(data.address or '')):sub(1, 200)
|
|||
|
|
if not CanUseMailbox(identifier, address) then
|
|||
|
|
-- Kein Zugriff auf das Postfach: der Termin wird privat, statt in einem
|
|||
|
|
-- fremden Kalender zu landen.
|
|||
|
|
address = ''
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local visibility = tostring(data.visibility or 'private')
|
|||
|
|
if address == '' then
|
|||
|
|
-- Ohne Postfach gibt es niemanden, der einen oeffentlichen Termin
|
|||
|
|
-- pflegen koennte. Also bleibt er privat.
|
|||
|
|
visibility = 'private'
|
|||
|
|
elseif visibility ~= 'public' then
|
|||
|
|
visibility = 'shared'
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
return d, address, visibility
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Termin so aufbereiten, wie ihn der Client braucht.
|
|||
|
|
local function PublicEvent(identifier, row)
|
|||
|
|
row.can_edit = CanEditEvent(identifier, row)
|
|||
|
|
row.address = row.address or ''
|
|||
|
|
return row
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
local function SendCalendar(src, identifier)
|
|||
|
|
local rows = DB.GetCalendar(identifier, MailboxesOf(identifier))
|
|||
|
|
for _, row in ipairs(rows) do PublicEvent(identifier, row) end
|
|||
|
|
TriggerClientEvent('pc-live:client:calendarData', src, rows)
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
--- Alle, die einen Termin sehen, bekommen die Aenderung sofort.
|
|||
|
|
--- Ohne das haette jeder eine andere Vorstellung vom Dienstplan, bis er den
|
|||
|
|
--- PC neu oeffnet – und genau dafuer ist ein geteilter Kalender da.
|
|||
|
|
local function NotifyOthers(src, event)
|
|||
|
|
if not event then return end
|
|||
|
|
local shared = (event.address and event.address ~= '') or event.visibility == 'public'
|
|||
|
|
if not shared then return end
|
|||
|
|
|
|||
|
|
for playerSrc, session in pairs(ActiveSessions) do
|
|||
|
|
if playerSrc ~= src then
|
|||
|
|
if event.visibility == 'public'
|
|||
|
|
or CanUseMailbox(session.identifier, event.address or '') then
|
|||
|
|
SendCalendar(playerSrc, session.identifier)
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
end
|
|||
|
|
|
|||
|
|
-- ── Lesen ────────────────────────────────────────────────────────────────────
|
|||
|
|
RegisterNetEvent('pc-live:server:getCalendar', function()
|
|||
|
|
local src = source
|
|||
|
|
local user = ActiveSessions[src]
|
|||
|
|
if not user then return end
|
|||
|
|
|
|||
|
|
SendCalendar(src, user.identifier)
|
|||
|
|
end)
|
|||
|
|
|
|||
|
|
-- ── Anlegen ──────────────────────────────────────────────────────────────────
|
|||
|
|
RegisterNetEvent('pc-live:server:addCalendarEvent', function(data)
|
|||
|
|
local src = source
|
|||
|
|
local user = ActiveSessions[src]
|
|||
|
|
if not user then return end
|
|||
|
|
|
|||
|
|
local d, address, visibility = ReadEvent(user.identifier, data)
|
|||
|
|
if not d then return end
|
|||
|
|
|
|||
|
|
local id = DB.AddCalendarEvent(user.identifier, address, visibility, d)
|
|||
|
|
|
|||
|
|
d.id = id
|
|||
|
|
d.address = address
|
|||
|
|
d.visibility = visibility
|
|||
|
|
d.identifier = user.identifier
|
|||
|
|
d.can_edit = true
|
|||
|
|
|
|||
|
|
TriggerClientEvent('pc-live:client:calendarEventAdded', src, d)
|
|||
|
|
NotifyOthers(src, d)
|
|||
|
|
end)
|
|||
|
|
|
|||
|
|
-- ── Aendern ──────────────────────────────────────────────────────────────────
|
|||
|
|
RegisterNetEvent('pc-live:server:updateCalendarEvent', function(id, data)
|
|||
|
|
local src = source
|
|||
|
|
local user = ActiveSessions[src]
|
|||
|
|
if not user then return end
|
|||
|
|
if type(id) ~= "number" then return end
|
|||
|
|
|
|||
|
|
-- Erst der bestehende Termin: sonst koennte man einen fremden aendern,
|
|||
|
|
-- indem man einfach eine Adresse mitschickt, auf die man Zugriff hat.
|
|||
|
|
local existing = DB.GetCalendarEvent(id)
|
|||
|
|
if not CanEditEvent(user.identifier, existing) then return end
|
|||
|
|
|
|||
|
|
local d, address, visibility = ReadEvent(user.identifier, data)
|
|||
|
|
if not d then return end
|
|||
|
|
|
|||
|
|
DB.UpdateCalendarEvent(id, address, visibility, d)
|
|||
|
|
|
|||
|
|
d.id = id
|
|||
|
|
d.address = address
|
|||
|
|
d.visibility = visibility
|
|||
|
|
d.can_edit = true
|
|||
|
|
|
|||
|
|
TriggerClientEvent('pc-live:client:calendarEventUpdated', src, d)
|
|||
|
|
|
|||
|
|
-- Beide Seiten benachrichtigen: der Termin kann aus einem geteilten
|
|||
|
|
-- Kalender herausgenommen worden sein, dann muss er dort verschwinden.
|
|||
|
|
NotifyOthers(src, existing)
|
|||
|
|
NotifyOthers(src, d)
|
|||
|
|
end)
|
|||
|
|
|
|||
|
|
-- ── Loeschen ─────────────────────────────────────────────────────────────────
|
|||
|
|
RegisterNetEvent('pc-live:server:deleteCalendarEvent', function(id)
|
|||
|
|
local src = source
|
|||
|
|
local user = ActiveSessions[src]
|
|||
|
|
if not user then return end
|
|||
|
|
if type(id) ~= "number" then return end
|
|||
|
|
|
|||
|
|
local existing = DB.GetCalendarEvent(id)
|
|||
|
|
if not CanEditEvent(user.identifier, existing) then return end
|
|||
|
|
|
|||
|
|
DB.DeleteCalendarEvent(id)
|
|||
|
|
TriggerClientEvent('pc-live:client:calendarEventDeleted', src, id)
|
|||
|
|
NotifyOthers(src, existing)
|
|||
|
|
end)
|