interactions.lua 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. -- INTERACTIONS.LUA (CLI)
  2. -- User interaction functions for Modular Politics
  3. -- Called by modpol.lua
  4. modpol.interactions = {}
  5. -- DASHBOARDS
  6. -- ==========
  7. -- Function: modpol.interactions.dashboard(user)
  8. -- Params: user (string)
  9. -- Q: Should this return a menu of commands relevant to the specific user?
  10. -- Output: Displays a menu of commands to the user
  11. -- TKTK currently just prints all of modpol---needs major improvement
  12. function modpol.interactions.dashboard(user)
  13. -- adds user to root org if not already in it
  14. if not modpol.instance:has_member(user) then
  15. modpol.instance:add_member(user)
  16. end
  17. local all_users = modpol.instance:list_members()
  18. print('\n-=< MODPOL DASHBOARD >=-')
  19. print('All orgs: (user orgs indicated by *)')
  20. for id, org in ipairs(modpol.orgs.array) do
  21. if type(org) == "table" then
  22. local indicator = ""
  23. if org:has_member(user) then indicator = "*" end
  24. print('['..id..'] '..indicator..org.name)
  25. end
  26. end
  27. -- pending list
  28. local user_pending = {}
  29. local user_pending_count = 0
  30. for k,v in ipairs(modpol.orgs.array) do
  31. if v.pending and v.pending[user] then
  32. if modpol.util.num_pairs(v.pending[user]) ~= 0 then
  33. table.insert(user_pending, v.name)
  34. user_pending_count = user_pending_count + 1
  35. end
  36. end
  37. end
  38. print('Pending actions in: '..table.concat(user_pending,', '))
  39. print('All users: ' .. table.concat(all_users, ', '))
  40. print()
  41. print('Access which org id?')
  42. local sel = io.read()
  43. print()
  44. if modpol.orgs.array[tonumber(sel)] then
  45. local sel_org = modpol.orgs.array[tonumber(sel)].name
  46. modpol.interactions.org_dashboard(user, sel_org)
  47. else
  48. print("Org id not found.")
  49. end
  50. end
  51. -- Function: modpol.interactions.org_dashboard
  52. -- Params: user (string), org_string (string or id)
  53. -- Output: Displays a menu of org-specific commands to the user
  54. function modpol.interactions.org_dashboard(user, org_string)
  55. local org = modpol.orgs.get_org(org_string)
  56. if not org then return nil end
  57. -- identify parent
  58. local parent = ""
  59. if org.id == 1 then
  60. parent = "none"
  61. else
  62. parent = modpol.orgs.get_org(org.parent).name
  63. end
  64. -- identify children
  65. local children = {}
  66. for k,v in ipairs(org.children) do
  67. local this_child = modpol.orgs.get_org(v)
  68. table.insert(children, this_child.name)
  69. end
  70. -- prepare modules menu
  71. local modules = {}
  72. if org.modules then
  73. for k,v in pairs(org.modules) do
  74. if not v.hide then -- hide utility modules
  75. local module_entry = v.slug
  76. table.insert(modules, module_entry)
  77. end
  78. end
  79. end
  80. table.sort(modules)
  81. -- list pending
  82. local process_msg = #org.processes .. " total processes"
  83. if org.pending[user] then
  84. process_msg = process_msg .. " (" ..
  85. modpol.util.num_pairs(org.pending[user]) .. " pending)"
  86. else
  87. process_msg = process_msg .. " (0 pending)"
  88. end
  89. -- set up output
  90. print('\n-=< ORG DASHBOARD >=-')
  91. print("Org: " .. org.name)
  92. print("Parent: " .. parent)
  93. print("Members: " .. table.concat(org.members, ", "))
  94. print("Child orgs: " .. table.concat(children, ", "))
  95. print("Modules: " .. table.concat(modules, ", "))
  96. print("Pending: " .. process_msg)
  97. print()
  98. print("Commands: (M)odules, (P)ending, (B)ack")
  99. local sel = io.read()
  100. print()
  101. if sel == 'm' or sel == 'M' then
  102. print("Type module name: ")
  103. local module_sel = io.read()
  104. print()
  105. local module_result = false
  106. for k,v in ipairs(modules) do
  107. if v == module_sel then
  108. module_result = true
  109. end
  110. end
  111. if module_result then
  112. org:call_module(module_sel, user)
  113. else
  114. print("Error: Module not found.")
  115. end
  116. elseif sel == 'p' or sel == 'P' then
  117. local processes = {}
  118. print("All processes: (* indicates pending)")
  119. for i,v in ipairs(org.processes) do
  120. local active = ''
  121. if org.pending[user] then
  122. if org.pending[user][v.id] then
  123. active = '*'
  124. end
  125. end
  126. print("["..v.id.."] "..v.slug..active)
  127. end
  128. print()
  129. print("Interact with which one (use [id] number)?")
  130. local to_interact = io.read()
  131. local process = org.processes[tonumber(to_interact)]
  132. if not process then return end
  133. if org:has_pending_actions(user) then
  134. if org.pending[user][process.id] then
  135. org:interact(process.id, user)
  136. end
  137. end
  138. elseif sel == 'b' or sel == 'B' then
  139. modpol.interactions.dashboard(user)
  140. else
  141. print("Command not found")
  142. modpol.interactions.org_dashboard(user, org.name)
  143. end
  144. end
  145. -- Function: modpol.interactions.policy_dashboard
  146. -- input: user (string), org_id (int), policy (string)
  147. -- if policy is nil, enables creating a new policy
  148. -- output: opens a dashboard for viewing/editing policy details
  149. -- TODO
  150. -- Function: modpol.interactions.message
  151. -- input: user (string), message (string)
  152. -- output: prints message to CLI
  153. function modpol.interactions.message(user, message)
  154. print(user .. ": " .. message)
  155. end
  156. -- Function: modpol.interactions.text_query
  157. -- input: User (string), Query (string), func (function)
  158. -- func input: user input (string)
  159. -- output: Applies "func" to user input
  160. function modpol.interactions.text_query(user, query, func)
  161. print(user .. ": " .. query)
  162. answer = io.read()
  163. func(answer)
  164. end
  165. -- Function: dropdown_query
  166. -- input: user (string), label (string), options (table of strings), func(choice) (function)
  167. -- func input: choice (string)
  168. -- output: calls func on choice
  169. function modpol.interactions.dropdown_query(user, label, options, func)
  170. -- set up options
  171. local options_display = ""
  172. local options_number = 0
  173. for k,v in ipairs(options) do
  174. options_display = options_display .. k .. ". " ..
  175. options[k] .. "\n"
  176. options_number = options_number + 1
  177. end
  178. options_display = options_display .. "Select number:"
  179. if options_number == 0 then
  180. print("Error: No options given for dropdown")
  181. return nil
  182. end
  183. -- begin displaying
  184. print(user .. ": " .. label)
  185. print(options_display)
  186. -- read input and produce output
  187. local answer
  188. answer = io.read()
  189. answer = tonumber(answer)
  190. if answer then
  191. if answer >= 1 and answer <= options_number then
  192. print("Selection: " .. options[answer])
  193. func(options[answer])
  194. else
  195. print("Error: Not in dropdown range")
  196. return nil
  197. end
  198. else
  199. print("Error: Must be a number")
  200. return nil
  201. end
  202. end
  203. -- Function: modpol.binary_poll_user(user, question)
  204. -- Params: user (string), question (string), func (function)
  205. -- func input: user input (string: y/n)
  206. -- Output: Applies "func" to user input
  207. function modpol.interactions.binary_poll_user(user, question, func)
  208. local query = "Poll for " .. user .. " (y/n): ".. question
  209. local answer
  210. repeat
  211. print(query)
  212. answer = io.read()
  213. until answer == "y" or answer == "n"
  214. if answer == "y" then
  215. modpol.interactions.message(user, "Response recorded")
  216. func("Yes")
  217. elseif answer == "n" then
  218. modpol.interactions.message(user, "Response recorded")
  219. func("No")
  220. else
  221. modpol.interactions.message(user, "Error: invalid response")
  222. end
  223. end
  224. -- COMPLEX INTERACTIONS
  225. -- ====================
  226. -- Function: modpol.interactions.message_org
  227. -- input: initiator (string), org (number or string), message (string)
  228. -- output: broadcasts message to all org members
  229. function modpol.interactions.message_org(initiator, org, message)
  230. local this_org = modpol.orgs.get_org(org)
  231. local users = this_org:list_members()
  232. for k,v in ipairs(users) do
  233. modpol.interactions.message(v, message)
  234. end
  235. end
  236. -- Function: modpol.interactions.binary_poll_org
  237. -- input: initator (user string), org_id (number)
  238. -- output: gets question from initiator, asks all org members, broadcasts answers