interactions.lua 7.8 KB

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