From 419fc84822ba97c399f8357dfa1f55e809611949 Mon Sep 17 00:00:00 2001 From: MisterE123 Date: Mon, 8 Mar 2021 14:06:15 -0500 Subject: [PATCH] change orgs to use id numbers as their table key and function input param --- modpol/DOCS/orgs | 22 +- modpol/orgs/orgs.lua | 242 ++++++++++++------ modpol/storage/storage-local.lua | 46 +++- modpol_minetest/chatcommands/chatcommands.lua | 3 +- .../storage/storage-mod_storage.lua | 8 +- 5 files changed, 228 insertions(+), 93 deletions(-) diff --git a/modpol/DOCS/orgs b/modpol/DOCS/orgs index 971deeb..a360bd7 100644 --- a/modpol/DOCS/orgs +++ b/modpol/DOCS/orgs @@ -4,7 +4,7 @@ they are *not* just a message in a table anymore... they have a timestamp and mo =============== -Orgs are stored in modpol.orgs by the key 'org_name' +Orgs are stored in modpol.orgs by the key 'org_id', a unique integer Old ledgers of deleted orgs are stored in modpol.old_ledgers, if preserve records is enabled @@ -36,8 +36,8 @@ to store old ledgers when an org is deleted. It is set to true. It would be possible to extend this to a settings file later. --==oo888888888888888888888888888888oo==-- -Function: modpol.record(org_name, msg, type) --- Params: strings msg, org, type +Function: modpol.record(org_id, msg, type) +-- Params: strings msg, type, org_id (number) -- Outputs: -- "msg" specifies an event and/or status message. -- "org" specifies an "org" name. @@ -52,8 +52,8 @@ Function: modpol.record(org_name, msg, type) --==oo888888888888888888888888888888oo==-- -Function: modpol.add_org(org_name, members, parent, properties) --- Params: string name, table members, string parent, table properties +Function: modpol.add_org(org_id, members, parent, properties) +-- Params: org)id (number), table members, string parent, table properties -- Parent must be an existing org, defaults to 'instance', properties -- are arbitrary properties to initialize the org with @@ -75,8 +75,8 @@ Function: modpol.add_org(org_name, members, parent, properties) --==oo888888888888888888888888888888oo==-- --- Function: modpol.remove_org(org_name, reason) --- Params: string name, opt string reason +-- Function: modpol.remove_org(org_id, reason) +-- Params: org_id (number), opt string reason -- Output: -- -- This function removes an "org". It returns a boolean @@ -114,8 +114,8 @@ Function: modpol.reset_orgs() --==oo888888888888888888888888888888oo==-- -Function: modpol.add_member(org_name, member) --- Params: org_name (string), member (string) +Function: modpol.add_member(org_id, member) +-- Params: org_id (number), member (string) -- Output: -- Adds the specified member to the specified org -- Returns a boolean success indicator and @@ -124,14 +124,14 @@ Function: modpol.add_member(org_name, member) --==oo888888888888888888888888888888oo==-- Function: modpol.is_member --- Params: org (string), member (string) +-- Params: org (number), member (string) -- Output: boolean, or nil and error message if not applicable. (org nonexistent) --==oo888888888888888888888888888888oo==-- Function: modpol.remove_member --- Params: org (string), member (string) +-- Params: org (number), member (string) -- Output: -- Removes the specified member from the specified org -- Returns confirmation or error message \ No newline at end of file diff --git a/modpol/orgs/orgs.lua b/modpol/orgs/orgs.lua index 95c05bd..4260118 100644 --- a/modpol/orgs/orgs.lua +++ b/modpol/orgs/orgs.lua @@ -6,29 +6,58 @@ -- =================================================================== -- preserve records -- if true, will store org ledgers when they are closed, for later reference. local preserve_records = true + +-- policies assigned to any org can go here modpol.default_org_policies = modpol.default_org_policies or {} --- initiate the table of orgs -modpol.orgs = {} +-- initiate the table of orgs, if it doesnt already exist from storage! +modpol.orgs = modpol.orgs or {} + + + if preserve_records then - modpol.old_ledgers = {} -- a backup of all legders of all closed orgs. + modpol.old_ledgers = modpol.old_ledgers or {} -- a backup of all legders of all closed orgs. end +-- this counter will increment every time a new org is created, and the current value will be used as the org id +-- we set it to 1 for init, and then run through all existing orgs and take only the greatest... which we then add 1 to. +-- this ensures a unique id for each org. +modpol.id_counter = 1 +if #modpol.orgs > 0 then + for id,org in pairs(modpol.orgs) do + if id > modpol.id_counter then + modpol.id_counter = id + end + + end + for id,ledg in pairs(modpol.old_ledgers) do + if id > modpol.id_counter then + modpol.id_counter = id + end + end + modpol.id_counter = modpol.id_counter +1 +end + + + + --define the template of a ledger entry modpol.ledger_entry_temp = { timestamp = '', entrytype = nil, action_msg = '', org_name = nil, + org_id = nil, } -- define the basic template of an org. modpol.org_temp = { + id = nil, name = nil, policies = {}, members = {}, @@ -42,19 +71,22 @@ modpol.org_temp = { -- =================================================================== -- Function: modpol.create_ledger_entry --- Params: strings action_msg, org_name, type +-- Params: strings: action_msg, type, number: org_id -- Outputs: -- returns a ledger entry table, with a timestamp --- This function accepts a message and an optional org_name and type specification +-- This function accepts a message and an optional org_id and type specification -- and returns a valid ledger entry table -modpol.create_ledger_entry = function(action_msg, org_name, entry_type) +modpol.create_ledger_entry = function(action_msg, org_id, entry_type) local entry = modpol.ledger_entry_temp if action_msg and type(action_msg) == 'string' then entry.action_msg = action_msg end - if org_name and type(org_name) == 'string' and modpol.orgs [org_name] then - entry.org_name = org_name + if org_id and type(org_id) == 'number' and modpol.orgs [org_id] then + entry.org_id = org_id + if modpol.orgs[org_id].name then + entry.org_name = modpol.orgs[org_id].name + end end if entry_type and type(entry_type) == 'string' then entry.entrytype = entry_type @@ -66,35 +98,54 @@ end -- =================================================================== -- Function: modpol.record --- Params: strings msg, org, type +-- Params: strings msg, type, number org_id -- Outputs: -- "msg" specifies an event and/or status message. --- "org" specifies an "org" name. +-- "org" specifies an "org" id. -- "type" -- optional type of legder entry. Could be e.g. 'election_result', 'add_member', etc -- This function adds the message to a global ledger and, if "org" -- specifies a valid "org", to an "org"-specific ledger. Both the mem- -- ory-resident and on-disk copies of the data structures used are up- -- dated. -modpol.record = function (org_name, msg, type) +modpol.record = function (org_id, msg, type) - local entry = modpol.create_ledger_entry(msg,org_name,type) + local entry = modpol.create_ledger_entry(msg, org_id, type) -- Record in global ledger table.insert (modpol.ledger, entry) -- Record in "org"-specific ledger - if modpol.orgs [org_name] ~= nil then - local org_ledger = modpol.orgs [org_name]["ledger"] + if modpol.orgs [org_id] ~= nil then + local org_ledger = modpol.orgs [org_id]["ledger"] if org_ledger == nil then - modpol.orgs [org_name]["ledger"] = { entry } + modpol.orgs [org_id]["ledger"] = { entry } else - modpol.orgs [org_name]["ledger"] = - table.insert (org_ledger, entry) + modpol.orgs [org_id]["ledger"] = table.insert (org_ledger, entry) end end modpol.store_data() -- Copy data to disk end +-- =================================================================== +-- Function: modpol.get_org_id_by_name(org_name) +-- Params: org_name + +-- Output: an org id or nil +-- +modpol.get_org_id_by_name = function(org_name) + local id = nil + for org_id,org in pairs(modpol.orgs) do + if org.name == org_name then + id = org_id + end + end + return id +end + + + + + -- =================================================================== -- Function: modpol.add_org -- Params: string name, table members, string parent, table properties @@ -115,54 +166,78 @@ end -- properties defaults to an empty table. Use it to initialize the org -- with arbitrary properties -modpol.add_org = function(org_name, members, parent, properties) +modpol.add_org = function(org_name, members, parent_id, properties) local str if modpol.ocutil.str_empty (org_name) then return false,"Error: Org needs a name" end - if parent and not modpol.orgs[parent] then - return false,"Error: Parent must be a valid org" + if parent_id and not modpol.orgs[parent_id] then + return false,"Error: Parent_id must be a valid existing org id" end if properties and not type(properties) == 'table' then return false,"Error: Properties must be a table" end + - modpol.ocutil.log ("Adding org " .. org_name) - if modpol.orgs [org_name] ~= nil then + modpol.ocutil.log ("Attempting to add new org " .. org_name) + + if modpol.get_org_id_by_name(org_name) ~= nil then str = "Error: Org " .. org_name .. " already exists" modpol.ocutil.log (str) return false,str end - local parent_org = parent or 'instance' - local props = properties or {} + local org_id = modpol.id_counter + modpol.id_counter = modpol.id_counter + 1 - - -- actually add the org - local org = modpol.org_temp - local default_policies = modpol.default_org_policies or {} - org.name = org_name -- do not change this without the proper api function. This is only a reference, not the only place this is recorded. - org.members = members - org.parent = parent_org - org.properties = props - org.policies = default_policies - modpol.orgs [org_name] = org + -- the instance will have a parent of nil if it is the instance. + -- otherwise, it will have a parent of instance's id if not otherwise defined + local parent_org_id = nil + - --record the child org in the parent's children table - if modpol.orgs[parent_org].children then - table.insert(modpol.orgs[parent_org].children, org_name) - else - modpol.orgs[parent].children = {org_name} + if parent_id and not(modpol.get_org_id_by_name('instance') == org_id) then + parent_org_id = parent_id end - local msg = "New org: " .. org_name .. - " (" .. table.concat (members, ", ") .. ")" + if not parent_id and not(modpol.get_org_id_by_name('instance') == org_id) then + parent_org_id = modpol.get_org_id_by_name('instance') + end - modpol.record (org_name, msg, 'org_init') + + + local props = properties or {} + + + -- actually add the org + local org = modpol.org_temp + local default_policies = modpol.default_org_policies or {} + org.id = org_id + org.name = org_name -- do not change this without the proper api function. This is only a reference, not the only place this is recorded. + org.members = members + org.parent = parent_org_id + org.properties = props + org.policies = default_policies + + modpol.orgs [org_id] = org + + --record the child org in the parent's children table + if parent_org_id then + + if modpol.orgs[parent_org_id].children then + table.insert(modpol.orgs[parent_org_id].children, org_id) + else + modpol.orgs[parent_org_id].children = {org_id} + end + end + + local msg = "New org: " .. org_name .. " ["..org_id.."], parent = ".. dump(parent_org_id)..", members = ".. + " (" .. table.concat (members, ", ") .. ")" + + modpol.record (org_id, msg, 'org_init') return true, msg end @@ -171,7 +246,7 @@ end -- =================================================================== -- Function: modpol.remove_org --- Params: string name, opt string reason +-- Params: number id, opt string reason -- Output: -- -- This function removes an "org". It returns a boolean @@ -179,51 +254,58 @@ end -- starting with "Error:" or a success message. It also recursively -- removes all child orgs, with 'remove parent org' as reason. If -- preserve_records is enabled, it logs the removal in the org ledger, --- and stores the ledger in modpol.old_legders +-- and stores the ledger in modpol.old_ledgers --- The string parameter specifies the "org" name. +-- The number parameter specifies the "org" id. -- -- The reason is an optional string to additionally include in the -- log as reason for removal -modpol.remove_org = function (org_name, reason) +modpol.remove_org = function (org_id, reason) local str if not reason then reason = '' end - if modpol.ocutil.str_empty (org_name) then - return false,"Error: Specify an org name to remove" + if not type(org_id) == 'number' or not modpol.orgs[org_id] then + str = "Error: Specify an existing org id to remove" + modpol.ocutil.log (str) + return false,str end - + local org_name = modpol.orgs[org_id] if org_name == 'instance' then return false,"Error: You cannot remove instance" end - modpol.ocutil.log ("Removing org " .. org_name) - if modpol.orgs [org_name] == nil then - str = "Error: Cannot remove non-existant org " .. org_name - modpol.ocutil.log (str) - return false,str - end - --log msg - local msg = 'Removing org '..org_name ..', reason: '.. reason + local msg = 'Removing org '..org_name ..' ['..org_id..'], reason: '.. reason + modpol.ocutil.log (msg) + + -- actually remove the org - modpol.record (org_name, msg, 'org_remove') -- TODO: if callbacks are implemented, do so here -- + if preserve_records then - modpol.old_ledgers = modpol.orgs[org_name].ledger + modpol.old_ledgers[org_id] = modpol.orgs[org_id].ledger end -- also remove all children - if modpol.orgs[org_name].children and #modpol.orgs[org_name].children > 0 then - for _,child_name in pairs(modpol.orgs[org_name].children) do - modpol.remove_org(child_name, 'remove parent org') --this is recursion. If it gets to be a problem, we will need a separate function + if modpol.orgs[org_id].children and #modpol.orgs[org_id].children > 0 then + for _,child_name in pairs(modpol.orgs[org_id].children) do + --this is recursion. If it gets to be a problem, we will need a separate function + modpol.remove_org(child_name, 'remove parent org') end end - modpol.orgs[org_name] = nil + --also remove references to this org in parent orgs + if modpol.orgs[org_id].parent then + local parent_id = modpol.orgs[org_id].parent + modpol.orgs[parent_id].children[org_id] = nil + end + + modpol.orgs[org_id] = nil + + modpol.record (org_id, msg, 'org_remove') return true,msg @@ -247,10 +329,11 @@ end modpol.list_orgs = function() local outbuf = "" local str - for org_name, org_data in pairs (modpol.orgs) do + for org_id, org_data in pairs (modpol.orgs) do -- Process next "org" -- Build string version of member list local memcat = org_data ["members"] + local org_name = org_data ["name"].."["..org_id.."]" if modpol.ocutil.str_empty (memcat) then memcat = "(empty)" else @@ -273,10 +356,10 @@ modpol.reset_orgs = function() local users = modpol.list_users() --store the ledgers in modpol.old_ledgers, and note that each org was closed in each record. if preserve_records then - for name, org in pairs(modpol.orgs) do + for id, org in pairs(modpol.orgs) do local old_ledger = org.ledger - table.insert(old_ledger,modpol.create_ledger_entry('Removing org '.. name, name, 'org_purge')) - table.insert(modpol.old_ledgers, org.ledger) + table.insert(old_ledger,modpol.create_ledger_entry('Removing org '.. id, id, 'org_purge')) + modpol.old_ledgers[id] = old_ledger end end modpol.orgs = {} @@ -288,7 +371,7 @@ end -- =================================================================== -- Function: modpol.add_member --- Params: org (string), member (string) +-- Params: org_id (number), member (string) -- Output: -- Adds the specified member to the specified org -- Returns a boolean success indicator and @@ -297,18 +380,20 @@ end -- TODO, check that member is a user, if the org_name is not instance -modpol.add_member = function(org_name, member) - if (modpol.orgs[org_name] == nil) then +modpol.add_member = function(org_id, member) + + if (modpol.orgs[org_id] == nil) then return false,"Error: No such org" elseif type(member) ~= 'string' then return false,"Error: member is wrong type" else - if modpol.is_member(org_name,member) then + local org_name = modpol.orgs [org_id].name + if modpol.is_member(org_id,member) then return false,"Error: " .. member .. " is already a member of " .. org_name else - table.insert(modpol.orgs[org_name]["members"], member) - local message = member .. " added to org " .. org_name - modpol.record(org_name, message, 'add_member') + table.insert(modpol.orgs[org_id]["members"], member) + local message = member .. " added to org " .. org_name .. " ["..org_id.."]" + modpol.record(org_id, message, 'add_member') return true,message end end @@ -316,7 +401,7 @@ end -- =================================================================== -- Function: modpol.is_member --- Params: org (string), member (string) +-- Params: org (number), member (string) -- Output: Boolean depending on membership or nil/error message modpol.is_member = function(org, member) @@ -340,7 +425,7 @@ end -- =================================================================== -- Function: modpol.remove_member --- Params: org (string), member (string) +-- Params: org (number), member (string) -- Output: -- Removes the specified member from the specified org -- Returns confirmation or error message @@ -358,9 +443,10 @@ function modpol.remove_member(org, member) modpol.orgs[org]["members"][value] = nil - -- TODO: add callbacks here -- + -- TODO: add callbacks here, for such as revoking privs, etc -- + message = member .. " removed from org " .. org - modpol.record(org_name, message, 'remove_member') + modpol.record(org, message, 'remove_member') return true, message end end diff --git a/modpol/storage/storage-local.lua b/modpol/storage/storage-local.lua index 20f8544..87c7f0b 100644 --- a/modpol/storage/storage-local.lua +++ b/modpol/storage/storage-local.lua @@ -9,6 +9,7 @@ modpol.datadir = modpol.topdir .. "/data" modpol.file_ledger = modpol.datadir .. "/ledger.dat" modpol.file_orgs = modpol.datadir .. "/orgs.dat" +modpol.file_old_ledgers = modpol.datadir .. "/old_ledgers.dat" os.execute ("mkdir -p " .. modpol.datadir) @@ -43,8 +44,7 @@ end local store_orgs = function() local ok = modpol.ocutil.file_write (modpol.file_orgs, -modpol.serpent.dump (modpol.orgs)) - + modpol.serpent.dump (modpol.orgs)) if ok ~= true then modpol.ocutil.fatal_error ("store_data: orgs") end @@ -55,12 +55,32 @@ modpol.serpent.dump (modpol.orgs)) modpol.ocutil.log (nn .. " orgs stored to disk") end +-- =================================================================== +-- This function stores "old_ledgers" data to disk. + +local store_old_ledgers = function() + + local ok = modpol.ocutil.file_write (modpol.file_old_ledgers, + modpol.serpent.dump (modpol.old_ledgers)) + + + if ok ~= true then + modpol.ocutil.fatal_error ("store_data: orgs") + end + + local nn = modpol.ocutil.table_length (modpol.old_ledgers) + local str = "entries" + if nn == 1 then str = "entry" end + modpol.ocutil.log (nn .. " orgs stored to disk") +end + -- =================================================================== -- This function stores data to disk. modpol.store_data = function() store_ledger() store_orgs() + store_old_ledgers() end -- =================================================================== @@ -105,12 +125,34 @@ local load_orgs = function() end end +-- =================================================================== +-- This function loads "old_ledgers" data from disk. + +local load_old_ledgers = function() + local obj = modpol.ocutil.file_read (modpol.file_old_ledgers ) + if obj ~= nil then + local func, err = load (obj) + if err then + modpol.ocutil.fatal_error ("load_data: orgs" ) + end + modpol.orgs = func() + + local nn = modpol.ocutil.table_length (modpol.file_old_ledgers) + local str = "entries" + if nn == 1 then str = "entry" end + modpol.ocutil.log (nn .. " orgs loaded from disk") + else + modpol.ocutil.log ("No stored old ledgers data found") + end +end + -- =================================================================== -- This function loads stored data from disk. modpol.load_storage = function() load_ledger() load_orgs() + load_old_ledgers() end -- =================================================================== diff --git a/modpol_minetest/chatcommands/chatcommands.lua b/modpol_minetest/chatcommands/chatcommands.lua index 8f82d5e..4c848e4 100644 --- a/modpol_minetest/chatcommands/chatcommands.lua +++ b/modpol_minetest/chatcommands/chatcommands.lua @@ -59,7 +59,8 @@ minetest.register_chatcommand( "joinorg", { privs = {}, func = function(user, param) - local success, result = modpol.add_member(param, user) + local org_id = modpol.get_org_id_by_name(param) + local success, result = modpol.add_member(org_id, user) return true, result end, }) diff --git a/modpol_minetest/storage/storage-mod_storage.lua b/modpol_minetest/storage/storage-mod_storage.lua index be890eb..5c4e476 100644 --- a/modpol_minetest/storage/storage-mod_storage.lua +++ b/modpol_minetest/storage/storage-mod_storage.lua @@ -18,11 +18,16 @@ modpol.load_storage = function() if (stored_orgs ~= nil) then modpol.orgs = stored_orgs end - -- load orgs + -- load ledger local stored_ledger = minetest.deserialize(mod_storage:get_string("ledger")) if (stored_ledger ~= nil) then modpol.ledger = stored_ledger end + -- load old_ledgers + local old_stored_ledgers = minetest.deserialize(mod_storage:get_string("old_ledgers")) + if (stored_ledger ~= nil) then + modpol.old_ledgers = old_stored_ledgers + end end -- Stores content of current orgs and ledger to mod_storage @@ -31,4 +36,5 @@ modpol.store_data = function() -- write to storage mod_storage:set_string("orgs", minetest.serialize(modpol.orgs)) mod_storage:set_string("ledger", minetest.serialize(modpol.ledger)) + mod_storage:set_string("old_ledgers", minetest.serialize(modpol.old_ledgers)) end