--- Orgs: Base -- Basic functions for orgs modpol.orgs = modpol.orgs or { count = 1, array = {} } -- sets modpol.orgs as its own fallback modpol.orgs.__index = modpol.orgs function temp_org() return { id = nil, name = nil, modules = modpol.util.copy_table(modpol.modules), processes = {}, pending = {}, members = {}, parent = nil, children = {} } end -- ================================================== -- returns org when given its id or name function modpol.orgs.get_org(arg) if type(arg) == 'string' then for id, org in ipairs(modpol.orgs.array) do if org.name == arg then return org end end elseif type(arg) == 'number' then return modpol.orgs.array[arg] end return nil end -- =============================================== -- returns a table list of all org names function modpol.orgs.list_all() local org_table for k, v in ipairs(modpol.orgs.array) do if type(v) == 'table' then if org_table then table.insert(org_table, v.name) else org_table = {v.name} end end end return org_table end -- Function: modpol.orgs.user_orgs(user) -- input: user (string) -- output: table of strings of org names function modpol.orgs.user_orgs(user) local all_orgs = modpol.orgs.list_all() local user_orgs = {} for i,v in ipairs(all_orgs) do local this_table = modpol.orgs.get_org(v) if this_table:has_member(user) then table.insert(user_orgs,v) end end return user_orgs end -- =========================================== -- deletes all orgs except for the instance function modpol.orgs.reset() local instance_members = modpol.util.copy_table(modpol.instance.members) for id, org in ipairs(modpol.orgs.array) do if id > 1 then modpol.orgs.array[id] = "removed" end end modpol.orgs.array[1] = nil modpol.instance = modpol.orgs.init_instance() modpol.instance.members = instance_members modpol.ocutil.log('All orgs reset') modpol.orgs:record('Resetting all orgs', 'org_reset') end -- =================================================== -- initializes the instance (root org) -- can only be run once, as only one instance can exist function modpol.orgs.init_instance() local error_msg if modpol.orgs.array[1] then modpol.ocutil.log('Error in orgs.init_instance -> instance has already been initialized') return false end local instance = temp_org() instance.id = 1 instance.name = "Root" setmetatable(instance, modpol.orgs) -- adding instance to org list modpol.orgs.array[1] = instance modpol.ocutil.log('Initialized the instance root org') modpol.orgs:record('Initialized the instance root org', 'create_instance') return instance end -- FUNCTIONS BEYOND HERE OPERATE ON ORG OBJECTS -- ======================================================= -- records a log message to the modpol ledger function modpol.orgs:record(msg, entry_type) local entry = { timestamp = '', entry_type = nil, action_msg = '', org_name = '', org_id = nil, } if type(msg) == 'string' and not(modpol.ocutil.str_empty(msg)) then entry.action_msg = msg else modpol.ocutil.log('Error in ' .. self.name .. ':record -> msg must be a non empty string') return false end if type(entry_type) == 'string' and not(modpol.ocutil.str_empty(entry_type)) then entry.entry_type = entry_type else modpol.ocutil.log('Error in ' .. self.name .. ':record -> entry_type must be a non empty string') modpol.ocutil.log(msg, entry_type) return false end entry.timestamp = os.time() entry.org_id = self.id entry.org_name = self.name table.insert(modpol.ledger, entry) modpol.store_data() end -- ================================================== -- adds a new sub org to the org it is called on -- input: name (string), user (string) -- ex: instance:add_org('town hall') function modpol.orgs:add_org(name, user) if self.id == nil then modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> add_org can only be called by another org') return false end if modpol.ocutil.str_empty(name) then modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> org name is required') return false end if modpol.orgs.get_org(name) then modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> org name is already being used') return false end -- creating the child sub org modpol.orgs.count = modpol.orgs.count + 1 local child_org = temp_org() child_org.id = modpol.orgs.count child_org.name = name child_org.parent = self.id child_org.processes = {} child_org.modules = modpol.util.copy_table(self.modules) setmetatable(child_org, modpol.orgs) -- adding child id to list of children table.insert(self.children, child_org.id) -- adding child to org list modpol.orgs.array[child_org.id] = child_org -- adding creator of org as the first member child_org:add_member(user) self:record('created sub org ' .. name, 'add_org') modpol.ocutil.log('Created ' .. name .. ' (suborg of ' .. self.name .. ')') return child_org end -- ======================================== -- recursively deletes an org and its suborgs -- leaves entry in modpol.orgs.array as a string "removed" -- note: "reason" param was removed, can be added back function modpol.orgs:delete() if self.id == 1 then modpol.ocutil.log('Error in ' .. self.name .. ':delete -> cannot delete instance') return false end if #self.children > 0 then for i, child_id in pairs(self.children) do local child = modpol.orgs.get_org(child_id) modpol.ocutil.log(child_id, child) child:delete() end end modpol.orgs.array[self.id] = 'removed' modpol.ocutil.log('Deleted org ' .. self.name .. ': ' .. self.id) self:record('Deleted ' .. self.name .. ' and all child orgs', 'del_org') end -- =========================================== -- internal function to get the index of a member name function modpol.orgs:get_member_index(member) for k, v in ipairs(self.members) do if v == member then return k end end end -- =========================================== -- adds a user to an org function modpol.orgs:add_member(user) for id, name in ipairs(self.members) do if user == name then modpol.ocutil.log('Error in ' .. self.name .. ':add_member -> user already in org') return false end end -- trys to fill in empty spots first local empty_index = self:get_member_index('') if empty_index then self.members[empty_index] = user else -- adds to end if no empty spots table.insert(self.members, user) end modpol.ocutil.log('Added member ' .. user .. ' to ' .. self.name) self:record('Added member ' .. user, 'add_member') end -- ======================================= -- removes a user from an org function modpol.orgs:remove_member(user) -- sets the array index to an empty string so that consecutive list is preserved -- empty spots will get filled in by new members local user_index = self:get_member_index(user) if user_index then self.members[user_index] = '' else modpol.ocutil.log('Error in ' .. self.name .. ':remove_member -> user not in org') end modpol.ocutil.log('Removed member ' .. user .. ' from ' .. self.name) self:record('Removed member ' .. user, 'del_member') end -- =========================================== -- boolean check whether user is an org function modpol.orgs:has_member(user) local user_index = self:get_member_index(user) if user_index then return true else return false end end -- ================================== -- Function: modpol.orgs:list_members() -- output: a table of the names (string) of members function modpol.orgs:list_members() local members = {} for k, v in ipairs(self.members) do table.insert(members, v) end return members end -- ============================== -- because member list uses lazy deletion, using #org.members will not show an accurate number function modpol.orgs:get_member_count() local count = 0 for k, v in ipairs(self.members) do -- the empty string represents a deleted member in the members list if v ~= '' then count = count + 1 end end return count end -- ==================================== -- adds a new policy to the policy table -- must define the policy type, process associated with it, and whether the request must be made by an org member function modpol.orgs:set_policy(policy_type, process_type, must_be_member) local new_policy = { process_type = process_type, must_be_member = must_be_member } self.policies[policy_type] = new_policy modpol.ocutil.log('Added policy for ' .. policy_type .. ' in ' .. self.name) self:record('Added policy for ' .. policy_type, 'set_policy') end