Merge branch 'policy_table' into 'master'
Policy table See merge request medlabboulder/modpol!21
This commit is contained in:
		| @@ -6,10 +6,14 @@ local localdir = modpol.topdir | |||||||
| dofile (localdir .. "/users/users.lua") | dofile (localdir .. "/users/users.lua") | ||||||
|  |  | ||||||
| --orgs | --orgs | ||||||
| dofile (localdir .. "/orgs/orgs.lua") | dofile (localdir .. "/orgs/base.lua") | ||||||
|  | dofile (localdir .. "/orgs/requests.lua") | ||||||
|  |  | ||||||
| --interactions | --interactions | ||||||
| dofile (localdir .. "/interactions/interactions.lua") | dofile (localdir .. "/interactions/interactions.lua") | ||||||
|  |  | ||||||
| -- messaging functions | -- messaging functions | ||||||
| dofile (localdir .. "/processes/processes.lua") | dofile (localdir .. "/processes/processes.lua") | ||||||
|  |  | ||||||
|  | --modules | ||||||
|  | dofile (localdir .. "/modules/consent.lua") | ||||||
| @@ -71,9 +71,17 @@ dofile (topdir .. "/api.lua") | |||||||
|  |  | ||||||
| -- =================================================================== | -- =================================================================== | ||||||
| -- Final checks | -- Final checks | ||||||
| for id, org in ipairs(modpol.orgs.array) do |  | ||||||
|  | -- sets org metatable on load | ||||||
|  | if (modpol.orgs.array) then | ||||||
|  |     for id, org in ipairs(modpol.orgs.array) do | ||||||
|         if type(org) == 'table' then  |         if type(org) == 'table' then  | ||||||
|             setmetatable(org, modpol.orgs) |             setmetatable(org, modpol.orgs) | ||||||
|  |             -- sets process metatable on load | ||||||
|  |             for id, process in ipairs(org.processes) do | ||||||
|  |                 setmetatable(process, modpol.modules[process.type]) | ||||||
|  |             end | ||||||
|  |         end | ||||||
|     end |     end | ||||||
| end | end | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								modpol/modules/consent.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								modpol/modules/consent.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | modpol.modules = modpol.modules or {} | ||||||
|  |  | ||||||
|  | modpol.modules.consent = { | ||||||
|  |     type = "consent", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | -- sets consent to its own callback | ||||||
|  | modpol.modules.consent.__index = modpol.modules.consent | ||||||
|  |  | ||||||
|  | function temp_consent_process() | ||||||
|  |     return { | ||||||
|  |         org_id = nil, | ||||||
|  |         request_id = nil, | ||||||
|  |         total_votes = 0, | ||||||
|  |         majority_to_pass = 0.51, | ||||||
|  |         votes_yes = {}, | ||||||
|  |         votes_no = {} | ||||||
|  |     } | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =============================================== | ||||||
|  | -- function to create a new consent process to resolve a pending process | ||||||
|  | function modpol.modules.consent:new_process(request_id, org_id) | ||||||
|  |     local process = temp_consent_process() | ||||||
|  |     process.request_id = request_id | ||||||
|  |     process.org_id = org_id | ||||||
|  |  | ||||||
|  |     setmetatable(process, modpol.modules.consent) | ||||||
|  |     modpol.ocutil.log('Created new process for request id #' .. request_id) | ||||||
|  |  | ||||||
|  |     return process | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- ====================================================== | ||||||
|  | -- function for users to vote on a pending request | ||||||
|  | function modpol.modules.consent:approve(user, decision) | ||||||
|  |     if not modpol.orgs.get_org(self.org_id):has_member(user) then | ||||||
|  |         modpol.ocutil.log('Error in consent:approve -> user not a member of the org') | ||||||
|  |         return | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     if decision then | ||||||
|  |         table.insert(self.votes_yes, user) | ||||||
|  |         modpol.ocutil.log('User ' .. user .. ' voted yes on request #' .. self.request_id) | ||||||
|  |     else | ||||||
|  |         table.insert(self.votes_no, user) | ||||||
|  |         modpol.ocutil.log('User ' .. user .. ' voted no on request #' .. self.request_id) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     self.total_votes = self.total_votes + 1 | ||||||
|  |  | ||||||
|  |     self:update_status() | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =================================================== | ||||||
|  | -- determines whether process has finished and resolves request if it has (unfinished) | ||||||
|  | function modpol.modules.consent:update_status() | ||||||
|  |     local process_org = modpol.orgs.get_org(self.org_id) | ||||||
|  |     local eligible_voters = process_org:get_member_count() | ||||||
|  |     local votes_needed = math.ceil(self.majority_to_pass * eligible_voters) | ||||||
|  |      | ||||||
|  |     if #self.votes_yes >= votes_needed then | ||||||
|  |         modpol.ocutil.log('Request #' .. self.request_id .. ' passes') | ||||||
|  |         process_org:resolve_request(self.request_id, true) | ||||||
|  |     elseif #self.votes_no >= votes_needed then | ||||||
|  |         modpol.ocutil.log('Request #' .. self.request_id .. ' fails to pass') | ||||||
|  |         process_org:resolve_request(self.request_id, false) | ||||||
|  |     else | ||||||
|  |         modpol.ocutil.log('Waiting for more votes...') | ||||||
|  |     end | ||||||
|  | end | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								modpol/modules/defer_to.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modpol/modules/defer_to.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -14,20 +14,12 @@ function temp_org() | |||||||
|         policies = {}, |         policies = {}, | ||||||
|         processes = {}, |         processes = {}, | ||||||
|         requests = {}, |         requests = {}, | ||||||
|         request_count = 0, |  | ||||||
|         members = {}, |         members = {}, | ||||||
|         parent = nil, |         parent = nil, | ||||||
|         children = {} |         children = {} | ||||||
|     } |     } | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| modpol.orgs.request_params = { |  | ||||||
|     add_org = 1, |  | ||||||
|     delete = 0, |  | ||||||
|     add_member = 1, |  | ||||||
|     remove_member = 1 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| -- ================================================== | -- ================================================== | ||||||
| -- returns org when given its id or name | -- returns org when given its id or name | ||||||
| function modpol.orgs.get_org(arg) | function modpol.orgs.get_org(arg) | ||||||
| @@ -79,10 +71,11 @@ end | |||||||
| function modpol.orgs.reset() | function modpol.orgs.reset() | ||||||
|     for id, org in ipairs(modpol.orgs.array) do |     for id, org in ipairs(modpol.orgs.array) do | ||||||
|         if id > 1 then |         if id > 1 then | ||||||
|             modpol.orgs.array[id] = nil |             modpol.orgs.array[id] = "removed" | ||||||
|         end |         end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |     modpol.ocutil.log('Reset all orgs') | ||||||
|     modpol.orgs:record('Resetting all orgs', 'org_reset') |     modpol.orgs:record('Resetting all orgs', 'org_reset') | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| @@ -92,7 +85,7 @@ end | |||||||
| function modpol.orgs.init_instance() | function modpol.orgs.init_instance() | ||||||
|     local error_msg |     local error_msg | ||||||
|     if modpol.orgs.array[1] then |     if modpol.orgs.array[1] then | ||||||
|         modpol.ocutil.log('Error: instance has already been initialized') |         modpol.ocutil.log('Error in orgs.init_instance -> instance has already been initialized') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
| @@ -105,6 +98,7 @@ function modpol.orgs.init_instance() | |||||||
|     -- adding instance to org list |     -- adding instance to org list | ||||||
|     modpol.orgs.array[1] = instance |     modpol.orgs.array[1] = instance | ||||||
| 
 | 
 | ||||||
|  |     modpol.ocutil.log('Initialized the instance org') | ||||||
|     modpol.orgs:record('Initialized the instance org', 'create_instance') |     modpol.orgs:record('Initialized the instance org', 'create_instance') | ||||||
| 
 | 
 | ||||||
|     return instance |     return instance | ||||||
| @@ -127,15 +121,15 @@ function modpol.orgs:record(msg, entry_type) | |||||||
|     if type(msg) == 'string' and not(modpol.ocutil.str_empty(msg)) then |     if type(msg) == 'string' and not(modpol.ocutil.str_empty(msg)) then | ||||||
|         entry.action_msg = msg |         entry.action_msg = msg | ||||||
|     else |     else | ||||||
|         modpol.ocutil.log('Error: msg must be a non empty string') |         modpol.ocutil.log('Error in ' .. self.name .. ':record -> msg must be a non empty string') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if type(entry_type) == 'string' and not(modpol.ocutil.str_empty(entry_type)) then |     if type(entry_type) == 'string' and not(modpol.ocutil.str_empty(entry_type)) then | ||||||
|         entry.entry_type = entry_type |         entry.entry_type = entry_type | ||||||
|     else |     else | ||||||
|         modpol.ocutil.log('Error: entry_type must be a non empty string') |         modpol.ocutil.log('Error in ' .. self.name .. ':record -> entry_type must be a non empty string') | ||||||
|         print(msg, entry_type) |         modpol.ocutil.log(msg, entry_type) | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
| @@ -152,17 +146,17 @@ end | |||||||
| -- ex: instance:add_org('town hall') | -- ex: instance:add_org('town hall') | ||||||
| function modpol.orgs:add_org(name) | function modpol.orgs:add_org(name) | ||||||
|     if self.id == nil then |     if self.id == nil then | ||||||
|         modpol.ocutil.log('Error: add_org can only be called by another org') |         modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> add_org can only be called by another org') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if modpol.ocutil.str_empty(name) then |     if modpol.ocutil.str_empty(name) then | ||||||
|         modpol.ocutil.log('Error: org name is required') |         modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> org name is required') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     if modpol.orgs.get_org(name) then |     if modpol.orgs.get_org(name) then | ||||||
|         modpol.ocutil.log('Error: org name is already being used') |         modpol.ocutil.log('Error in ' .. self.name .. ':add_org -> org name is already being used') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
| @@ -182,7 +176,7 @@ function modpol.orgs:add_org(name) | |||||||
|     modpol.orgs.array[child_org.id] = child_org |     modpol.orgs.array[child_org.id] = child_org | ||||||
| 
 | 
 | ||||||
|     self:record('created sub org ' .. name, 'add_org') |     self:record('created sub org ' .. name, 'add_org') | ||||||
|     modpol.ocutil.log('Created sub org ' .. name) |     modpol.ocutil.log('Created ' .. name .. ' (suborg of ' .. self.name .. ')') | ||||||
| 
 | 
 | ||||||
|     return child_org |     return child_org | ||||||
| end | end | ||||||
| @@ -193,20 +187,20 @@ end | |||||||
| -- note: "reason" param was removed, can be added back | -- note: "reason" param was removed, can be added back | ||||||
| function modpol.orgs:delete() | function modpol.orgs:delete() | ||||||
|     if self.id == 1 then |     if self.id == 1 then | ||||||
|         modpol.ocutil.log('Error: cannot delete instance') |         modpol.ocutil.log('Error in ' .. self.name .. ':delete -> cannot delete instance') | ||||||
|         return false |         return false | ||||||
|     end |     end | ||||||
|      |      | ||||||
|     if #self.children > 0 then |     if #self.children > 0 then | ||||||
|         for i, child_id in pairs(self.children) do |         for i, child_id in pairs(self.children) do | ||||||
|             local child = modpol.orgs.get_org(child_id) |             local child = modpol.orgs.get_org(child_id) | ||||||
|             print(child_id, child) |             modpol.ocutil.log(child_id, child) | ||||||
|             child:delete() |             child:delete() | ||||||
|         end |         end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     modpol.orgs.array[self.id] = 'removed' |     modpol.orgs.array[self.id] = 'removed' | ||||||
|     modpol.ocutil.log('Removed ' .. self.name .. ': ' .. self.id) |     modpol.ocutil.log('Deleted org ' .. self.name .. ': ' .. self.id) | ||||||
| 
 | 
 | ||||||
|     self:record('Deleted ' .. self.name .. ' and all child orgs', 'del_org') |     self:record('Deleted ' .. self.name .. ' and all child orgs', 'del_org') | ||||||
| 
 | 
 | ||||||
| @@ -226,6 +220,12 @@ end | |||||||
| -- =========================================== | -- =========================================== | ||||||
| -- adds a user to an org | -- adds a user to an org | ||||||
| function modpol.orgs:add_member(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 |     -- trys to fill in empty spots first | ||||||
|     local empty_index = self:get_member_index('') |     local empty_index = self:get_member_index('') | ||||||
|     if empty_index then |     if empty_index then | ||||||
| @@ -234,6 +234,8 @@ function modpol.orgs:add_member(user) | |||||||
|         -- adds to end if no empty spots |         -- adds to end if no empty spots | ||||||
|         table.insert(self.members, user) |         table.insert(self.members, user) | ||||||
|     end |     end | ||||||
|  |      | ||||||
|  |     modpol.ocutil.log('Added member ' .. user .. ' to ' .. self.name) | ||||||
|     self:record('Added member ' .. user, 'add_member') |     self:record('Added member ' .. user, 'add_member') | ||||||
| 
 | 
 | ||||||
| end | end | ||||||
| @@ -246,7 +248,10 @@ function modpol.orgs:remove_member(user) | |||||||
|     user_index = self:get_member_index(user) |     user_index = self:get_member_index(user) | ||||||
|     if user_index then |     if user_index then | ||||||
|         self.members[user_index] = '' |         self.members[user_index] = '' | ||||||
|  |     else | ||||||
|  |         modpol.ocutil.log('Error in ' .. self.name .. ':remove_member -> user not in org') | ||||||
|     end |     end | ||||||
|  |     modpol.ocutil.log('Removed member ' .. user .. ' from ' .. self.name) | ||||||
|     self:record('Removed member ' .. user, 'del_member') |     self:record('Removed member ' .. user, 'del_member') | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| @@ -266,7 +271,8 @@ end | |||||||
| function modpol.orgs:list_member() | function modpol.orgs:list_member() | ||||||
|     local str |     local str | ||||||
|     for k, v in ipairs(self.members) do |     for k, v in ipairs(self.members) do | ||||||
|         if str then  |         -- checking to see if member name is valid | ||||||
|  |         if str and str ~= '' then  | ||||||
|             str = str .. '\n' .. v |             str = str .. '\n' .. v | ||||||
|         else  |         else  | ||||||
|             str = v |             str = v | ||||||
| @@ -275,56 +281,28 @@ function modpol.orgs:list_member() | |||||||
|     return str |     return str | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- =========================== | -- ============================== | ||||||
| -- compares to requests to see if they are identical | -- because member list uses lazy deletion, using #org.members will not show an accurate number | ||||||
| function modpol.orgs.comp_req(req1, req2) | function modpol.orgs:get_member_count() | ||||||
|     -- compares request type |     local count = 0 | ||||||
|     if req1.type ~= req2.type then |     for k, v in ipairs(self.members) do | ||||||
|         return false |         -- the empty string represents a deleted member in the members list | ||||||
|     else |         if v ~= '' then | ||||||
|         -- comparing parameters |             count = count + 1 | ||||||
|         -- we can assume the number of params is the same as this is checked in the make_request func |  | ||||||
|         for k, v in ipairs(req1.params) do |  | ||||||
|             if v ~= req2.params[k] then |  | ||||||
|                 return false |  | ||||||
|         end |         end | ||||||
|     end |     end | ||||||
|     end |     return count | ||||||
|     return true | 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) | ||||||
| end | end | ||||||
| 
 | 
 | ||||||
| -- ================================ |  | ||||||
| -- tries to make a request to the org |  | ||||||
| function modpol.orgs:make_request(request) |  | ||||||
|     -- makes sure the request has the valid number of parameters |  | ||||||
|     local num_params = modpol.orgs.request_params[request.type] |  | ||||||
| 
 | 
 | ||||||
|     if num_params == nil then  |  | ||||||
|         modpol.ocutil.log("Error: request type is invalid") |  | ||||||
|         return false  |  | ||||||
|     end |  | ||||||
|     |  | ||||||
|     for k, v in ipairs(request.params) do |  | ||||||
|         num_params = num_params - 1 |  | ||||||
|     end  |  | ||||||
| 
 |  | ||||||
|     if num_params ~= 0 then |  | ||||||
|         modpol.ocutil.log("Error: request has invalid number of parameters")  |  | ||||||
|         return false  |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     -- checking to see if identical request already exists |  | ||||||
|     for k, v in ipairs(self.requests) do |  | ||||||
|         if self.comp_req(request, v) == true then |  | ||||||
|             modpol.ocutil.log("Error: request has already been made") |  | ||||||
|             return false |  | ||||||
|         end |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     -- use lazy deletion here, not very clean |  | ||||||
|     -- table.insert(self.requests, request) |  | ||||||
|     self.request_count = self.request_count + 1 |  | ||||||
|     self.requests[self.request_count] = request |  | ||||||
|     return self.request_count |  | ||||||
| 
 |  | ||||||
| end |  | ||||||
							
								
								
									
										179
									
								
								modpol/orgs/requests.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								modpol/orgs/requests.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,179 @@ | |||||||
|  | modpol.orgs.request_params = { | ||||||
|  |     add_org = 1, | ||||||
|  |     delete = 0, | ||||||
|  |     add_member = 1, | ||||||
|  |     remove_member = 1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | -- ================================ | ||||||
|  | -- creates a new process linked to a request id | ||||||
|  | function modpol.orgs:create_process(process_type, request_id) | ||||||
|  |     if not modpol.modules[process_type] then | ||||||
|  |         modpol.ocutil.log('Process type "' .. process_type .. '" does not exist') | ||||||
|  |         return | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- retrieving requested module | ||||||
|  |     local module = modpol.modules[process_type] | ||||||
|  |     local new_process = module:new_process(request_id, self.id) | ||||||
|  |  | ||||||
|  |     -- linear search for empty process slots (lazy deletion) | ||||||
|  |     for k, v in ipairs(self.processes) do | ||||||
|  |         if v == 'deleted' then | ||||||
|  |             local empty_index = k | ||||||
|  |             break | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- attempts to fill empty spots in list, otherwise appends to end | ||||||
|  |     if empty_index then | ||||||
|  |         self.processes[empty_index] = new_process | ||||||
|  |         return empty_index | ||||||
|  |     else | ||||||
|  |         table.insert(self.processes, new_process) | ||||||
|  |         return #self.processes | ||||||
|  |     end | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =========================== | ||||||
|  | -- compares to requests to see if they are identical | ||||||
|  | function modpol.orgs.comp_req(req1, req2) | ||||||
|  |     -- compares request type | ||||||
|  |     if req1.type ~= req2.type then | ||||||
|  |         return false | ||||||
|  |     else | ||||||
|  |         -- comparing parameters | ||||||
|  |         -- we can assume the number of params is the same as this is checked in the make_request func | ||||||
|  |         for k, v in ipairs(req1.params) do | ||||||
|  |             if v ~= req2.params[k] then | ||||||
|  |                 return false | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |     return true | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =============================== | ||||||
|  | -- returns string of all active requests | ||||||
|  | function modpol.orgs:list_request() | ||||||
|  |     local str | ||||||
|  |     for id, req in ipairs(self.requests) do | ||||||
|  |         if req ~= "deleted" then | ||||||
|  |             if str then  | ||||||
|  |                 str = str .. '\n' .. req.type .. ' (' .. req.user .. ') ' | ||||||
|  |             else  | ||||||
|  |                 str = req.type .. ' (' .. req.user .. ') ' | ||||||
|  |             end | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |     return str | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- =============================== | ||||||
|  | -- if the request was approved, the associated function is called, otherwise it is deleted | ||||||
|  | function modpol.orgs:resolve_request(request_id, approve) | ||||||
|  |     if approve then | ||||||
|  |         local request = self.requests[request_id] | ||||||
|  |         local p = request.params | ||||||
|  |  | ||||||
|  |         -- there's probably a way to clean this up, the issue is the varying number of commands | ||||||
|  |         -- ex: self['add_member'](self, 'member_name') | ||||||
|  |         -- not sure if this is safe, more testing to do | ||||||
|  |         self[request.type](self, p[1], p[2], p[3]) | ||||||
|  |          | ||||||
|  |         -- if request.type == "add_org" then | ||||||
|  |         --     self:add_org(p[1]) | ||||||
|  |         -- elseif request.type == "delete" then | ||||||
|  |         --     self:delete() | ||||||
|  |         -- elseif request.type == "add_member" then | ||||||
|  |         --     self:add_member(p[1]) | ||||||
|  |         -- elseif request.type == "remove_member" then | ||||||
|  |         --     self:remove_member(p[1]) | ||||||
|  |         -- end | ||||||
|  |          | ||||||
|  |     end | ||||||
|  |      | ||||||
|  |     self.requests[request_id] = "deleted" | ||||||
|  | end | ||||||
|  |  | ||||||
|  | -- ================================ | ||||||
|  | -- tries to make a request to the org | ||||||
|  | function modpol.orgs:make_request(request) | ||||||
|  |     -- makes sure the request has the valid number of parameters | ||||||
|  |     local num_params = modpol.orgs.request_params[request.type] | ||||||
|  |  | ||||||
|  |     if num_params == nil then  | ||||||
|  |         modpol.ocutil.log('Error in ' .. self.name .. ':make_request -> request type is invalid') | ||||||
|  |         return false  | ||||||
|  |     end | ||||||
|  |      | ||||||
|  |     -- num_params should equal zero at the end if request.params matches the num of params for that type | ||||||
|  |     for k, v in ipairs(request.params) do | ||||||
|  |         num_params = num_params - 1 | ||||||
|  |     end  | ||||||
|  |  | ||||||
|  |     if num_params ~= 0 then | ||||||
|  |         modpol.ocutil.log('Error in ' .. self.name .. ':make_request -> request has invalid number of parameters')  | ||||||
|  |         return false  | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- checking to see if identical request already exists | ||||||
|  |     for k, v in ipairs(self.requests) do | ||||||
|  |         if self.comp_req(request, v) == true then | ||||||
|  |             modpol.ocutil.log('Error in ' .. self.name .. ':make_request -> request has already been made') | ||||||
|  |             return false | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- checking to see if user is able to make request | ||||||
|  |     local requested_policy = self.policies[request.type] | ||||||
|  |     local parent_policy = modpol.orgs.get_org(self.parent).policies[request.type] | ||||||
|  |  | ||||||
|  |     -- tries to use org's policy table, defers to parent otherwise | ||||||
|  |     if not requested_policy then | ||||||
|  |         modpol.ocutil.log(request.type .. ' policy not found, deferring to parent org') | ||||||
|  |         requested_policy = parent_policy | ||||||
|  |  | ||||||
|  |         if not parent_policy then | ||||||
|  |             modpol.ocutil.log('Error in ' .. self.name .. ':make_request -> parent policy undefined') | ||||||
|  |             return false | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- make sure user is allowed to make request | ||||||
|  |     if requested_policy.must_be_member and not self:has_member(request.user) then | ||||||
|  |         modpol.ocutil.log('Error in ' .. self.name .. ':make_request -> user must be org member to make this request') | ||||||
|  |         return false | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- linear search for empty process slots (lazy deletion) | ||||||
|  |     for k, v in ipairs(self.requests) do | ||||||
|  |         if v == 'deleted' then | ||||||
|  |             local empty_index = k | ||||||
|  |             break | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     -- attempts to fill empty spots in list, otherwise appends to end | ||||||
|  |     local request_id = nil | ||||||
|  |     if empty_index then | ||||||
|  |         self.requests[empty_index] = request | ||||||
|  |         request_id = empty_index | ||||||
|  |     else | ||||||
|  |         table.insert(self.requests, request) | ||||||
|  |         -- finds end of list to return current request's id | ||||||
|  |         local count = 0 | ||||||
|  |         for k, v in ipairs(self.requests) do  | ||||||
|  |             count = count + 1  | ||||||
|  |         end | ||||||
|  |         request_id = count | ||||||
|  |     end | ||||||
|  |     modpol.ocutil.log("Request made by " .. request.user .. " to " .. request.type) | ||||||
|  |  | ||||||
|  |     -- launching process tied to this request | ||||||
|  |     local process_id = self:create_process(requested_policy.process_type, request_id) | ||||||
|  |  | ||||||
|  |     -- returns process id of processes launched by this request | ||||||
|  |     return process_id | ||||||
|  | end | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								modpol/tests/org_basic_test.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								modpol/tests/org_basic_test.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | dofile("../modpol.lua") | ||||||
|  |  | ||||||
|  | print('\nRemoving existing orgs') | ||||||
|  | modpol.orgs.reset() | ||||||
|  |  | ||||||
|  | print('\nCreating an org called "test_org"') | ||||||
|  | test_org = modpol.instance:add_org('test_org') | ||||||
|  |  | ||||||
|  | print('\nTrying to create an org with the same name') | ||||||
|  | duplicate = modpol.instance:add_org('test_org') | ||||||
|  |  | ||||||
|  | print('\nAdding user "luke" to test_org') | ||||||
|  | test_org:add_member('luke') | ||||||
|  |  | ||||||
|  | print('\nTrying to add duplicate user to test_org') | ||||||
|  | test_org:add_member('luke') | ||||||
|  |  | ||||||
|  | print('\nRemoving user "luke" from test_org') | ||||||
|  | test_org:remove_member('luke') | ||||||
|  |  | ||||||
|  | print('\nTrying to remove user "luke" from empty member list') | ||||||
|  | test_org:remove_member('luke') | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								modpol/tests/org_req_test.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modpol/tests/org_req_test.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | dofile('../modpol.lua'); | ||||||
|  |  | ||||||
|  | modpol.orgs.reset() | ||||||
|  |  | ||||||
|  | test_org = modpol.instance:add_org('test_org') | ||||||
|  | test_org:add_member('luke') | ||||||
|  | test_org:add_member('nathan') | ||||||
|  |  | ||||||
|  | test_org:set_policy("add_member", "consent", false); | ||||||
|  |  | ||||||
|  | new_request = { | ||||||
|  |     user = "josh", | ||||||
|  |     type = "add_member", | ||||||
|  |     params = {"josh"} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | request_id = test_org:make_request(new_request) | ||||||
|  |  | ||||||
|  | -- process_id = test_org:create_process("consent", request_id) | ||||||
|  | for id, process in ipairs(test_org.processes) do | ||||||
|  |     process:approve('luke', true) | ||||||
|  |     process:approve('nathan', true) | ||||||
|  | end | ||||||
|  | -- process = test_org.processes[process_id] | ||||||
|  | -- process:approve("luke", true) | ||||||
|  | -- process:approve("nathan", true) | ||||||
		Reference in New Issue
	
	Block a user