Nathan Schneider 2028f1ee85 Refactored policy structure
Previously, all modules in an org were fully copied into that
org. Now, the only copy of the modules is at modpol.modules, and orgs
have a policy table at [org].policies, which overrides the config
table in any given module.
2022-02-09 22:14:26 -07:00

322 lines
8.9 KiB
Lua

--- Basic function for orgs
-- @module modpol.orgs.base
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,
policies = {},
processes = {},
pending = {},
members = {},
parent = nil,
children = {},
}
end
--- Return org when given its id or name
-- @function modpol.orgs.get_org
-- @param arg string for name of org or id of org
-- @return org specified by 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
--- Return a table list of all org names
-- @function modpol.orgs.list_all
-- @return 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
--- Return the orgs of a user
-- @function modpol.orgs.user_orgs
-- @param user string of user name
-- @return 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
-- @function modpol.orgs.reset
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
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"
for i,v in pairs(modpol.modules) do
instance.policies[i] = {}
end
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
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.
-- Ex: instance:add_org('town hall')
-- @function modpol.orgs:add_org
-- @param name (string) name of new org
-- @param user (string)
-- @return child org created
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.policies = modpol.util.copy_table(self.policies)
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
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("Deleting child org...")
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
-- @param member
-- @return index of given member
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
-- @param user
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
-- @param user
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
-- @param user
-- @return true if user is in org, false if not
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()
-- @return 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
-- @return numbers of members
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