123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- -- ===================================================================
- -- /orgs.lua
- -- Org-related functions for Modular Politics
- -- Called by modpol/modpol/api.lua
- -- ===================================================================
- -- 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, if it doesnt already exist from storage!
- modpol.orgs = modpol.orgs or {}
- if preserve_records then
- 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 = {},
- ledger = {},
- parent = nil,
- children = {},
- properties = {},
- old_names = {},
- }
- -- ===================================================================
- -- Function: modpol.create_ledger_entry
- -- 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_id and type specification
- -- and returns a valid ledger entry table
- 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_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
- end
- entry.timestamp = os.time()
- return entry
- end
- -- ===================================================================
- -- Function: modpol.record
- -- Params: strings msg, type, number org_id
- -- Outputs:
- -- "msg" specifies an event and/or status message.
- -- "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_id, msg, 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_id] ~= nil then
- local org_ledger = modpol.orgs [org_id]["ledger"]
- if org_ledger == nil then
- modpol.orgs [org_id]["ledger"] = { entry }
- else
- 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
- -- Output:
- --
- -- This function creates an "org". It returns a boolean success indicator and
- -- either an error message starting with "Error:" or a success message.
- --
- -- The string parameter specifies the "org" name.
- --
- -- The members table should be an integer-indexed array of member
- -- names.
- -- parent should be nil or a valid existing org name. If nil, defaults to
- -- 'instance'
- -- properties defaults to an empty table. Use it to initialize the org
- -- with arbitrary 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_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 ("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 org_id = modpol.id_counter
- modpol.id_counter = modpol.id_counter + 1
- -- 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
-
- if parent_id and not(modpol.get_org_id_by_name('instance') == org_id) then
- parent_org_id = parent_id
- end
- 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
- 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 parent_id_str = "none"
- if parent_org_id then
- parent_id_str = tostring(parent_org_id)
- end
- local msg = "New org: " .. org_name .. " ["..org_id.."], parent = ".. parent_id_str ..", members = "..
- " (" .. table.concat (members, ", ") .. ")"
- modpol.record (org_id, msg, 'org_init')
- return true, msg
- end
- -- ===================================================================
- -- Function: modpol.remove_org
- -- Params: number id, opt string reason
- -- Output:
- --
- -- This function removes an "org". It returns a boolean
- -- success indicator and either an error message
- -- 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_ledgers
- -- 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_id, reason)
- local str
- if not reason then reason = '' end
- 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
- --log msg
- local msg = 'Removing org '..org_name ..' ['..org_id..'], reason: '.. reason
- modpol.ocutil.log (msg)
-
- -- actually remove the org
- -- TODO: if callbacks are implemented, do so here --
- if preserve_records then
- modpol.old_ledgers[org_id] = modpol.orgs[org_id].ledger
- end
- -- also remove all children
- 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
- --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
- end
- -- ===================================================================
- -- Function: modpol.list_orgs
- -- Params: None
- -- Output:
- -- This function returns a text-format list of "orgs". The list shows
- -- one "org" per line in the following format:
- -- org_name (member, member, ...)
- -- If there are no "orgs", the output is an empty string.
- modpol.list_orgs = function()
- local outbuf = ""
- local str
- 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
- memcat = "(" .. table.concat (memcat, ", ") .. ")"
- end
- -- Build output string
- outbuf = outbuf .. org_name .. " " .. memcat .. "\n"
- end
- return outbuf
- end
- -- ===================================================================
- -- Function: modpol.reset_orgs
- -- Params: None
- -- Removes all orgs and recreates blank org "instance" with all
- -- current users
- -- returns confirmation message
- 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 id, org in pairs(modpol.orgs) do
- local old_ledger = org.ledger
- local entry = modpol.create_ledger_entry('Removing org '.. id, id, 'org_purge')
- if old_ledger == nil then
- old_ledger = { entry }
- else
- table.insert(old_ledger, entry)
- end
- modpol.old_ledgers[id] = old_ledger
- end
- end
- modpol.orgs = {}
- local message = "Orgs purged"
- modpol.record(nil, message, 'org_purge')
- modpol.add_org("instance", users)
- return message
- end
- -- ===================================================================
- -- Function: modpol.add_member
- -- Params: org_id (number), member (string)
- -- Output:
- -- Adds the specified member to the specified org
- -- Returns a boolean success indicator and
- -- either a confirmation or error message
- -- TODO, check that member is a user, if the org_name is not instance
- 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
- 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_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
- end
- -- ===================================================================
- -- Function: modpol.is_member
- -- Params: org (number), member (string)
- -- Output: Boolean depending on membership or nil/error message
- modpol.is_member = function(org, member)
- if (modpol.orgs[org] == nil) then
- return nil, "Error: No such org"
- else
- local member_table = modpol.orgs[org]["members"]
- if member_table then
- for index, value in pairs(member_table) do
- if value == member then
- -- match found
- return true
- end
- end
- -- no match found
- return false
- end
- return false
- end
- end
- -- ===================================================================
- -- Function: modpol.remove_member
- -- Params: org (number), member (string)
- -- Output:
- -- Removes the specified member from the specified org
- -- Returns confirmation or error message
- function modpol.remove_member(org, member)
- local message = "Error: No such org"
- if (modpol.orgs[org] == nil) then
- return false, message
- else
- local member_table = modpol.orgs[org]["members"]
- if member_table then
- for index, value in pairs(member_table) do
- if value == member then
- -- match found, set to nil
-
- modpol.orgs[org]["members"][value] = nil
-
- -- TODO: add callbacks here, for such as revoking privs, etc --
- message = member .. " removed from org " .. org
- modpol.record(org, message, 'remove_member')
- return true, message
- end
- end
- end
- -- no match found (or org has no members)
- message = member .. " not found in org " .. org
- return false, message
- end
- end
- -- ===================================================================
- -- TKTK
- -- rename_org(old_name, new_name)
- -- Renames an org
-
- -- ===================================================================
- -- POLICIES
- -- Each policy is a table with a string for a key. Contents:
- -- KEY - name of the policy (string)
- -- [member orgs]: external orgs allowed to call policy
- -- [function]: the function that initiates the policy
- -- ===================================================================
- -- ===================================================================
- -- modpol.add_policy
- -- Adds a policy to an org's [org].policies table
- -- Params: org_name (string),
- -- policy_name (string),
- -- policy_table (table)
- -- Output: true if successful, nil if error
- -- TKTK NEEDS TO BE REWRITTEN
- modpol.add_policy = function(org_name, policy_name, policy_table)
- -- first, basic checks
- local message = "Error: No such org"
- if (modpol.orgs[org_name] == nil) then
- return nil, message
- elseif (modpol[target_function] == nil) then
- message = "Error: No such target function"
- return nil, message
- elseif (modpol[policy_function]) then
- message = "Error: No such policy function"
- return nil, message
- else
- -- okay, proceed
- modpol.orgs[org_name].policies[target_function] = policy_function
- message = "In org " .. org_name .. ", policy for " .. target_function
- .. " set to " .. policy_function
- record(org_name, message)
- return true, message
- end
- end
- -- ===================================================================
- -- End of file.
|