-- INTERACTIONS.LUA (CLI) -- User interaction functions for Modular Politics -- Called by modpol.lua modpol.interactions = {} -- DASHBOARDS -- ========== -- Function: modpol.interactions.dashboard(user) -- Params: user (string) -- Q: Should this return a menu of commands relevant to the specific user? -- Output: Displays a menu of commands to the user -- TKTK currently just prints all of modpol---needs major improvement function modpol.interactions.dashboard(user) -- adds user to root org if not already in it if not modpol.instance:has_member(user) then modpol.instance:add_member(user) end local all_users = modpol.instance:list_members() print('\n-=< MODPOL DASHBOARD >=-') print('All orgs: (user orgs indicated by *)') for id, org in ipairs(modpol.orgs.array) do if type(org) == "table" then local indicator = "" if org:has_member(user) then indicator = "*" end print('['..id..'] '..indicator..org.name) end end -- pending list local user_pending = {} local user_pending_count = 0 for k,v in ipairs(modpol.orgs.array) do if v.pending and v.pending[user] then if modpol.util.num_pairs(v.pending[user]) ~= 0 then table.insert(user_pending, v.name) user_pending_count = user_pending_count + 1 end end end print('Pending actions in: '..table.concat(user_pending,', ')) print('All users: ' .. table.concat(all_users, ', ')) print() print('Access which org id?') local sel = io.read() print() if modpol.orgs.array[tonumber(sel)] then local sel_org = modpol.orgs.array[tonumber(sel)].name modpol.interactions.org_dashboard(user, sel_org) else print("Org id not found.") end end -- Function: modpol.interactions.org_dashboard -- Params: user (string), org_string (string or id) -- Output: Displays a menu of org-specific commands to the user function modpol.interactions.org_dashboard(user, org_string) local org = modpol.orgs.get_org(org_string) if not org then return nil end -- identify parent local parent = "" if org.id == 1 then parent = "none" else parent = modpol.orgs.get_org(org.parent).name end -- identify children local children = {} for k,v in ipairs(org.children) do local this_child = modpol.orgs.get_org(v) table.insert(children, this_child.name) end -- prepare modules menu local modules = {} if org.modules then for k,v in pairs(org.modules) do if not v.hide then -- hide utility modules local module_entry = v.slug table.insert(modules, module_entry) end end end table.sort(modules) -- list pending local process_msg = #org.processes .. " total processes" if org.pending[user] then process_msg = process_msg .. " (" .. modpol.util.num_pairs(org.pending[user]) .. " pending)" else process_msg = process_msg .. " (0 pending)" end -- set up output print('\n-=< ORG DASHBOARD >=-') print("Org: " .. org.name) print("Parent: " .. parent) print("Members: " .. table.concat(org.members, ", ")) print("Child orgs: " .. table.concat(children, ", ")) print("Modules: " .. table.concat(modules, ", ")) print("Pending: " .. process_msg) print() print("Commands: (M)odules, (P)ending, (B)ack") local sel = io.read() print() if sel == 'm' or sel == 'M' then print("Type module name: ") local module_sel = io.read() print() local module_result = false for k,v in ipairs(modules) do if v == module_sel then module_result = true end end if module_result then org:call_module(module_sel, user) else print("Error: Module not found.") end elseif sel == 'p' or sel == 'P' then local processes = {} print("All processes: (* indicates pending)") for i,v in ipairs(org.processes) do local active = '' if org.pending[user] then if org.pending[user][v.id] then active = '*' end end print("["..v.id.."] "..v.slug..active) end print() print("Interact with which one (use [id] number)?") local to_interact = io.read() local process = org.processes[tonumber(to_interact)] if not process then return end if org:has_pending_actions(user) then if org.pending[user][process.id] then org:interact(process.id, user) end end elseif sel == 'b' or sel == 'B' then modpol.interactions.dashboard(user) else print("Command not found") modpol.interactions.org_dashboard(user, org.name) end end -- Function: modpol.interactions.policy_dashboard -- input: user (string), org_id (int), policy (string) -- if policy is nil, enables creating a new policy -- output: opens a dashboard for viewing/editing policy details -- TODO -- Function: modpol.interactions.message -- input: user (string), message (string) -- output: prints message to CLI function modpol.interactions.message(user, message) print(user .. ": " .. message) end -- Function: modpol.interactions.text_query -- input: User (string), Query (string), func (function) -- func input: user input (string) -- output: Applies "func" to user input function modpol.interactions.text_query(user, query, func) print(user .. ": " .. query) answer = io.read() func(answer) end -- Function: dropdown_query -- input: user (string), label (string), options (table of strings), func(choice) (function) -- func input: choice (string) -- output: calls func on choice function modpol.interactions.dropdown_query(user, label, options, func) -- set up options local options_display = "" local options_number = 0 for k,v in ipairs(options) do options_display = options_display .. k .. ". " .. options[k] .. "\n" options_number = options_number + 1 end options_display = options_display .. "Select number:" if options_number == 0 then print("Error: No options given for dropdown") return nil end -- begin displaying print(user .. ": " .. label) print(options_display) -- read input and produce output local answer answer = io.read() answer = tonumber(answer) if answer then if answer >= 1 and answer <= options_number then print("Selection: " .. options[answer]) func(options[answer]) else print("Error: Not in dropdown range") return nil end else print("Error: Must be a number") return nil end end -- Function: modpol.binary_poll_user(user, question) -- Params: user (string), question (string), func (function) -- func input: user input (string: y/n) -- Output: Applies "func" to user input function modpol.interactions.binary_poll_user(user, question, func) local query = "Poll for " .. user .. " (y/n): ".. question local answer repeat print(query) answer = io.read() until answer == "y" or answer == "n" if answer == "y" then modpol.interactions.message(user, "Response recorded") func("Yes") elseif answer == "n" then modpol.interactions.message(user, "Response recorded") func("No") else modpol.interactions.message(user, "Error: invalid response") end end -- COMPLEX INTERACTIONS -- ==================== -- Function: modpol.interactions.message_org -- input: initiator (string), org (number or string), message (string) -- output: broadcasts message to all org members function modpol.interactions.message_org(initiator, org, message) local this_org = modpol.orgs.get_org(org) local users = this_org:list_members() for k,v in ipairs(users) do modpol.interactions.message(v, message) end end -- Function: modpol.interactions.binary_poll_org -- input: initator (user string), org_id (number) -- output: gets question from initiator, asks all org members, broadcasts answers