--- Process functions for orgs -- @module modpol.orgs.process --- Call modules -- @function modpol.orgs.call_module -- @param module_slug Same as module name (or false to run result) -- @param intiator Initiator for module -- @param config Config for module -- @param result function modpol.orgs:call_module(module_slug, initiator, config, result, parent_id) -- first, if no slug, just run result -- may not be necessary if we use false as default approval_module if not module_slug and result() then result() return elseif not modpol.modules[module_slug] then -- if module doesn't exist, abort modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. tostring(module_slug) .. '" not found') return end local index = #self.processes + 1 local module = modpol.modules[module_slug] -- first applies any relevant org policies -- then overrides with the config values given on input local new_config = {} if modpol.util.num_pairs(module.config) > 0 then for k, v in pairs(module.config) do new_config[k] = v -- overrides with org policies if self.policies[module_slug] and self.policies[module_slug][k] then new_config[k] = self.policies[module_slug][k] end -- overrides with input settings if config and config[k] then new_config[k] = config[k] end end end -- setting default params local new_process = { metatable = {__index = module}, initiator = initiator, org = self, id = index, parent_id = parent_id, children = {}, config = modpol.util.copy_table(new_config), data = modpol.util.copy_table(module.data), slug = module_slug } -- call module wrapper for modules, passes its id to child process when called function new_process:call_module(module_slug, initiator, config, result) local child_id = self.org:call_module(module_slug, initiator, config, result, self.id) table.insert(self.children, child_id) end setmetatable(new_process, new_process.metatable) self.processes[index] = new_process self.processes[index]:initiate(result) local msg = "Initiating "..module_slug.. " process id "..index.." in org "..self.name return index end --- Get the root process of the given id -- @function modpol.orgs.get_root_process -- @param id -- @return root process function modpol.orgs:get_root_process(id) local process = self.processes[id] while (process.parent_id) do process = self.processes[process.parent_id] end return process end --- Delete the process given id, return to dashboard -- @function modpol.orgs.delete_process -- @param id function modpol.orgs:delete_process(id) local process = self.processes[id] if process and process ~= "deleted" then -- recursively deletes any children if #process.children > 0 then for i, child_id in pairs(process.children) do self:delete_process(child_id) end end local msg = "Deleting " .. self.processes[id].slug .. " process id "..id.." in org "..self.name modpol.ocutil.log(msg) self:record(msg, self.processes[id].slug) self:wipe_pending_actions(id) -- sets process to 'deleted' in process table self.processes[id] = 'deleted' end end --- Delete process tree by id -- @function modpol.orgs:delete_process_tree -- @param id Id of process tree function modpol.orgs:delete_process_tree(id) self:delete_process(self:get_root_process(id).id) end --- Add a new pending action -- @function modpol.orgs:add_pending_action -- @param process_id Process id -- @param user User adding the action -- @param callback function modpol.orgs:add_pending_action(process_id, user, callback) self.pending[user] = self.pending[user] or {} self.pending[user][process_id] = callback modpol.interactions.message( user, "New pending action in org "..self.name) end --- Remove a pending action -- @function modpol.orgs:remove_pending_action -- @param process_id Process id to be removed -- @param user function modpol.orgs:remove_pending_action(process_id, user) if self.pending[user] then self.pending[user][process_id] = nil end end --- Wipe all pending actions for process -- @function modpol.orgs:wipe_pending_actions -- @param process_id function modpol.orgs:wipe_pending_actions(process_id) for user in pairs(self.pending) do self.pending[user][process_id] = nil end end --- Check if there are pending actions for user -- @function modpol.orgs:has_pending_actions -- @param user User -- @return True if there are pending actions for a user, false if not function modpol.orgs:has_pending_actions(user) -- next() will return the next pair in a table -- if next() returns nil, the table is empty if not self.pending[user] then return false else if not next(self.pending[user]) then return false else return true end end end --- Create user interaction with given process -- @function modpol.orgs:interact -- @param process_id -- @param user function modpol.orgs:interact(process_id, user) local process = self.processes[process_id] if self.pending[user] then local callback = self.pending[user][process_id] if callback and process ~= "deleted" then -- get data in case callback ends process local slug = self.processes[process_id].slug -- run callback process[callback](process, user) -- record org data local msg = "Updating "..slug.. " process id "..process_id.." in org "..self.name self:record(msg, slug) end end end