generated from your-land/yl_template
284 lines
7.5 KiB
Lua
284 lines
7.5 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 function log(text)
|
|
local logmessage = yl_survey.t("log_prefix", yl_survey.modname, text)
|
|
if yl_survey.settings.debug then minetest.log("action", logmessage) end
|
|
return logmessage
|
|
end
|
|
|
|
function yl_survey.log(text) return log(text) end
|
|
|
|
-- Helpers
|
|
|
|
local function filename2uuid(filename) return filename:sub(1, -6) end
|
|
|
|
local function is_visible(filename) return (string.sub(filename, 1, 1) ~= ".") end
|
|
|
|
local function is_json(filename) return (filename:match("%.json$")) end
|
|
|
|
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 yl_survey.priv_exists(priv) return priv_exists(priv) end
|
|
|
|
-- table.contains
|
|
|
|
local function table_contains(t, m)
|
|
if ((type(m) ~= "number") and (type(m) ~= "string") and (type(m) ~= "boolean")) then
|
|
return nil, yl_survey.t("member must be primitive")
|
|
end
|
|
for _, v in pairs(t) do
|
|
if (v == m) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function yl_survey.table_contains(t, m)
|
|
return table_contains(t, m)
|
|
end
|
|
|
|
-- Hash name
|
|
|
|
local function hash_name(name)
|
|
if ((type(name) ~= "string") or (name == "")) then
|
|
return nil
|
|
end
|
|
return minetest.sha256(name, false)
|
|
end
|
|
|
|
function yl_survey.hash_name(name) return hash_name(name) end
|
|
|
|
-- UUID
|
|
|
|
local function generate_uuid()
|
|
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
|
return string.gsub(template, '[xy]', function(c)
|
|
local v = (c == 'x') and math.random(0, 15) or math.random(8, 11)
|
|
return string.format('%x', v)
|
|
end)
|
|
end
|
|
|
|
local function is_uuid_duplicate(UUID)
|
|
for i, record in pairs(yl_survey.data) do
|
|
local message = "is_uuid_duplicate record.id=%s, UUID=%s"
|
|
local formatted = string.format(message, dump(record.id), dump(UUID))
|
|
log(formatted)
|
|
if record.id == UUID then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function create_uuid()
|
|
local max_attempts = 10
|
|
|
|
local UUID
|
|
|
|
repeat
|
|
UUID = generate_uuid()
|
|
max_attempts = max_attempts - 1
|
|
if max_attempts < 0 then
|
|
return false, "Cannot find non-duplicate UUID"
|
|
end
|
|
until (is_uuid_duplicate(UUID) == false)
|
|
|
|
if UUID == "" then return false, "UUID empty" end
|
|
|
|
return true, UUID
|
|
|
|
end
|
|
|
|
function yl_survey.create_uuid() return create_uuid() end
|
|
|
|
-- delete responses
|
|
|
|
local function delete_responses(record)
|
|
local no = 0
|
|
for key, question in pairs(record) do
|
|
if (tonumber(key) ~= nil) then
|
|
if question.responses ~= nil then
|
|
question.responses = nil
|
|
no = no + 1
|
|
end
|
|
end
|
|
end
|
|
return record, no
|
|
end
|
|
|
|
function yl_survey.delete_responses(record)
|
|
return delete_responses(record)
|
|
end
|
|
|
|
-- yl_survey.find_next_free_sort_number(record)
|
|
|
|
local function find_next_free_number(record, target)
|
|
local highest_no = 1
|
|
local duplicates = {}
|
|
for key, question in pairs(record) do
|
|
if (tonumber(key) ~= nil) then
|
|
table.insert(duplicates, question[target])
|
|
if (question[target] >= highest_no) then
|
|
highest_no = question[target] + 1
|
|
end
|
|
end
|
|
end
|
|
local is_duplicate = false
|
|
for _, dupe in ipairs(duplicates) do
|
|
if (highest_no == dupe) then
|
|
is_duplicate = true
|
|
end
|
|
end
|
|
return highest_no, is_duplicate
|
|
end
|
|
|
|
function yl_survey.find_next_free_number(record, target)
|
|
return find_next_free_number(record, target)
|
|
end
|
|
|
|
-- yl_survey.is_duplicate(record, sort)
|
|
|
|
local function is_duplicate(record, sort)
|
|
for key, question in pairs(record) do
|
|
if (tonumber(key) ~= nil) then
|
|
if (question[sort] == sort) then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function yl_survey.is_duplicate(record, sort)
|
|
return is_duplicate(record, sort)
|
|
end
|
|
|
|
-- Load and save
|
|
|
|
local function get_savepath()
|
|
local savepath = yl_survey.worldpath .. yl_survey.settings.save_path
|
|
log(savepath or "")
|
|
return savepath
|
|
end
|
|
|
|
local function get_filepath(filename)
|
|
local path_to_file = get_savepath() .. DIR_DELIM .. filename .. ".json"
|
|
log(yl_survey.t("get_filepath", 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 savepath = get_filepath(filename)
|
|
local savecontent = minetest.write_json(content)
|
|
return minetest.safe_file_write(savepath, savecontent)
|
|
end
|
|
|
|
local function load_json(path)
|
|
local file = io.open(path, "r")
|
|
if not file then
|
|
return false, yl_survey.t("error_cannot_open_file", dump(path))
|
|
end
|
|
|
|
local content = file:read("*all")
|
|
file:close()
|
|
|
|
if not content then
|
|
return false, yl_survey.t("error_cannot_read_file", dump(path))
|
|
end
|
|
|
|
return true, minetest.parse_json(content)
|
|
end
|
|
|
|
-- Public functions wrap the private ones, so they can be exchanged easily
|
|
|
|
function yl_survey.load(filename, ...) return load_json(filename, ...) end
|
|
|
|
function yl_survey.save(filename, content, ...)
|
|
return save_json(filename, content, ...)
|
|
end
|
|
|
|
-- Remove file
|
|
|
|
local function remove_file(UUID)
|
|
local path = get_filepath(UUID)
|
|
return os.remove(path)
|
|
end
|
|
|
|
function yl_survey.remove_file(UUID) return remove_file(UUID) end
|
|
|
|
-- Load all data
|
|
--
|
|
|
|
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 UUID = filename2uuid(filename)
|
|
local filepath = get_filepath(UUID)
|
|
local success, content = load_json(filepath)
|
|
|
|
if ((success == true) and (content ~= nil) and (content["metadata"].id == UUID)) then
|
|
good = good + 1
|
|
data[UUID] = content
|
|
else
|
|
bad = bad + 1
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
yl_survey.data = data
|
|
|
|
local message = "[MOD] %s : bad = %s, good = %s, total = %s"
|
|
local formatted = string.format(message, yl_survey.information.name, tostring(bad), tostring(good), tostring(total))
|
|
if bad == 0 then
|
|
minetest.log("action", formatted)
|
|
return true, good, bad
|
|
else
|
|
minetest.log("warning", formatted)
|
|
return false, good, bad
|
|
end
|
|
end
|
|
|
|
function yl_survey.load_all_data() return load_all_data() end
|
|
|
|
-- Check privs
|
|
--
|
|
|
|
local function check_privs(settings)
|
|
for key, value in pairs(settings) do
|
|
if ends_with(key, "_privs") then
|
|
local parts = split(value)
|
|
for _, part in ipairs(parts) do
|
|
local message = "[MOD] %s : configured priv %s does not exist."
|
|
local formatted = string.format(message, yl_survey.information.name, dump(part))
|
|
assert(priv_exists(part), formatted)
|
|
end
|
|
end
|
|
end
|
|
log("PASS priv check")
|
|
end
|
|
|
|
function yl_survey.check_privs(settings) return check_privs(settings) end
|