yl_ticker/internal.lua
AliasAlreadyTaken 1edbfca06b Formatting
2024-05-12 17:30:17 +02:00

347 lines
11 KiB
Lua

-- The functions and variables in this file are only for use in the mod itself.
-- Those that do real work should be local and wrapped in public functions
local debug = yl_announcements.settings.debug or true
local function say(text)
if debug then minetest.log("action", "[MOD] yl_announcements : " .. text) end
end
-- Storage
local function get_savepath()
local save_path = yl_announcements.settings.save_path
local path = yl_announcements.worldpath .. DIR_DELIM .. save_path
say("get_savepath : " .. dump(path))
return path
end
local function get_filepath(filename)
local path_to_file = get_savepath() .. DIR_DELIM .. filename
say("get_filepath : " .. dump(filename) .. ":" .. dump(path_to_file))
return path_to_file
end
local function save_json(filename, content)
if type(filename) ~= "string" or type(content) ~= "table" then
return false
end
local save_path = get_filepath(filename)
local save_content = minetest.write_json(content)
say("save_json : " .. dump(save_path) .. ":" .. dump(save_content))
return minetest.safe_file_write(save_path, save_content)
end
local function load_json(path_to_file)
local file = io.open(path_to_file, "r")
if not file then return false, "Error opening file: " .. path_to_file end
local content = file:read("*all")
file:close()
if not content then return false, "Error reading file: " .. path_to_file end
say("load_json : " .. dump(path_to_file) .. ":" .. dump(content))
return true, minetest.parse_json(content)
end
-- Public functions wrap the private ones, so they can be exchanged easily
function yl_announcements.load_json(filename, ...)
return load_json(filename, ...)
end
function yl_announcements.save_json(filename, content, ...)
return save_json(filename, content, ...)
end
-- load_all_data
--
local function is_visible(filename) return (string.sub(filename, 1, 1) ~= ".") end
local function is_json(filename) return (filename:match("%.json$")) end
local function load_all_data()
-- Get all json files from savepath
-- Excluding invisible
-- Excluding non-json files
local save_path = get_savepath()
local files = minetest.get_dir_list(save_path, false) or {}
local data = {}
local total = 0
local good = 0
local bad = 0
for key, filename in ipairs(files) do
if is_visible(filename) and is_json(filename) then
total = total + 1
local filepath = get_filepath(filename)
local success, content = load_json(filepath)
if success and content.id then
good = good + 1
data[content.id] = content
else
bad = bad + 1
end
end
end
yl_announcements.data = data
if bad == 0 then
minetest.log("action",
"[MOD] yl_announcements : bad = " .. tostring(bad) ..
", good = " .. tostring(good) .. ", total = " ..
tostring(total))
return true, good, bad
else
minetest.log("warning",
"[MOD] yl_announcements : bad = " .. tostring(bad) ..
", good = " .. tostring(good) .. ", total = " ..
tostring(total))
return false, good, bad
end
end
function yl_announcements.load_all_data() return load_all_data() end
-- check privs
--
local function ends_with(str, suffix) return str:sub(-suffix:len()) == suffix end
local function split(str)
local parts = {}
for part in str:gmatch("[^,%s]+") do table.insert(parts, part) end
return parts
end
local function priv_exists(priv)
return (minetest.registered_privileges[priv] ~= nil) or false
end
function check_privs()
for key, value in pairs(yl_announcements.settings) do
if ends_with(key, "_privs") then
local parts = split(value)
for _, part in ipairs(parts) do
assert(priv_exists(part),
"yl_announcements : configured priv " .. dump(part) ..
" does not exist.")
end
end
end
say("PASS priv check")
end
function yl_announcements.check_privs() return check_privs() end
-- Remove file
--
local function remove_file(filename)
local filepath = get_filepath(filename)
return os.remove(filepath)
end
function yl_announcements.remove_file(filename) return remove_file(filename) end
-- Chatcommands
--
function yl_announcements.chatcommand_announcement_add(name, param) -- param is a string containing a message and more
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if (not param) or (type(param) ~= "string") or (param == "") then
return false, "Requirements not met"
end
-- Create announcement
local announcement = string.split(param, "$", true)
local message = announcement[1] or ""
local frequency = tonumber(announcement[2]) or
yl_announcements.settings.frequency or 3600
local runtime = tonumber(announcement[3]) or 7257600 -- 12 weeks
local owner = name
local success, announcement_id = yl_announcements.set(message, frequency,
runtime, owner)
return success, "Announcement ID " .. tostring(announcement_id)
end
function yl_announcements.chatcommand_announcement_copy(name, param) -- param is a numerical a_id
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param == "" then return false, "Announcement ID missing" end
local announcement_id = tonumber(param)
if type(announcement_id) ~= "number" then
return false, "Announcement ID is not a number"
end
if (announcement_id <= 0) then
return false, "Announcement ID cannot be zero or negative"
end
local success, formspecstring = yl_announcements.formspec(announcement_id)
if (success == false) then return false, formspecstring end
-- Send the formspec
minetest.show_formspec(name, "yl_announcements:copy", formspecstring)
-- Report
return true, "Copied announcement ID " .. tostring(announcement_id)
end
function yl_announcements.chatcommand_announcement_delete(name, param) -- param is a numerical a_id
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param == "" then return false, "Announcement ID missing" end
local announcement_id = tonumber(param)
if type(announcement_id) ~= "number" then
return false, "Announcement ID not a number"
end
local success, announcement = yl_announcements.delete(announcement_id)
if success == false then
return false, announcement
else
return true, "Deleted announcement ID " .. tostring(announcement_id)
end
end
-- List announcements
-- taken from yl_cinema
-- TODO: Shoudl we API-fy this?
local function format_table(t)
-- Format of t must be {{row1,row2,row3, ...},{row1,row2,row3, ...},...}
local blanks_between_rows = 3
local max_row_length = {}
for linenumber = 1, #t do
for rownumber = 1, #t[linenumber] do
local row_length = #tostring(t[linenumber][rownumber])
if (max_row_length[rownumber] or 0) < row_length then
max_row_length[rownumber] = row_length
end
end
end
local ret = {}
for linenumber = 1, #t do
local line_s = ""
for rownumber = 1, #t[linenumber] do
local text = t[linenumber][rownumber]
local text_length = #tostring(text)
local add_blanks = max_row_length[rownumber] - text_length
local newtext = t[linenumber][rownumber]
for add = 1, (add_blanks + blanks_between_rows) do
newtext = newtext .. " "
end
line_s = line_s .. newtext
end
table.insert(ret, line_s)
end
return table.concat(ret, "\n")
end
function yl_announcements.chatcommand_announcement_list_all(name, param) -- param must be empty
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param ~= "" then
return false, "This command lists all announcements. " ..
"Do /announcement_list <announcement_id> if you want to have only one."
end
local success, data = yl_announcements.list()
if (success == false) then return false, data end
local f_announcements = {
{"ID", "message", "created", "owner", "runtime", "frequency"}
}
for _, announcement in pairs(data) do
local id = tostring(announcement.id) or "N/A"
local message = announcement.message or "N/A"
local created = os.date("!%Y-%m-%d %H:%M:%S",
(announcement.creation_date or 0)) or "N/A"
local owner = announcement.owner or "N/A"
local runtime = tostring(announcement.runtime) or "N/A"
local frequency = tostring(announcement.frequency) or "N/A"
local t = {id, message, created, owner, runtime, frequency}
table.insert(f_announcements, t)
end
return true, format_table(f_announcements)
end
function yl_announcements.chatcommand_announcement_list(name, param) -- param is a numerical a_id
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param == "" then return false, "Announcement ID missing" end
local announcement_id = tonumber(param)
if type(announcement_id) ~= "number" then
return false, "Announcement ID not a number"
end
local success, announcement = yl_announcements.get(announcement_id)
if ((success == false) or (success == nil)) then
return false, "Announcement not found"
end
return true, dump(announcement)
end
function yl_announcements.chatcommand_announcement_say_all(name, param) -- param must be empty
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param ~= "" then
return false,
"This command sends all announcements to the main chat. " ..
"Do /announcement_say <announcement_id> if you want to send only one."
end
local success, data = yl_announcements.list()
if (success == false) then return false, data end
local n = 0
for _, announcement in pairs(data) do
local s_success, s_message = yl_announcements.say(announcement.id, "*")
if (s_success == false) then return false, s_message end
n = n + 1
end
return true, "Sent " .. tostring(n) .. " announcements to public."
end
function yl_announcements.chatcommand_announcement_say(name, param) -- param is a numerical a_id
-- defense
local player = minetest.get_player_by_name(name)
if not player then return false, "Player not online" end
if param == "" then return false, "Announcement ID missing" end
local announcement_id = tonumber(param)
if type(announcement_id) ~= "number" then
return false, "Announcement ID not a number"
end
local s_success, s_message = yl_announcements.say(announcement_id, "*")
if (s_success == false) then return false, s_message end
return true,
"Sent announcement " .. tostring(announcement_id) .. " to public."
end