Browse Source

Adding and fixing basic modules for renaming, removing, and adding orgs

Nathan Schneider 2 years ago
parent
commit
53d2a25f42

+ 3 - 1
README.md

@@ -10,7 +10,9 @@ For background information, documentation, and the project roadmap, see [the wik
 
 To use this in Minetest, simply install it in your `mods/` or `worldmods/` folder. Minetest will load `init.lua`.
 
-In the game, open the Modular Politics interface with the command `/modpol`.
+In the game, open the Modular Politics dashboard with the command `/mp`.
+
+For testing purposes, players with the `privs` privilege (generally admins) can use the `/mp` command, which resets all the orgs and opens a dashboard.
 
 
 ## Standalone Version on the Command Line

+ 4 - 1
modpol_core/api.lua

@@ -11,9 +11,12 @@ dofile (localdir .. "/interactions/interactions.lua")
 
 --modules
 --TODO make this automatic and directory-based
-dofile (localdir .. "/modules/add_child_org.lua")
+dofile (localdir .. "/modules/add_child_org_consent.lua")
 dofile (localdir .. "/modules/consent.lua")
 dofile (localdir .. "/modules/join_org_consent.lua")
 dofile (localdir .. "/modules/leave_org.lua")
+dofile (localdir .. "/modules/remove_child_consent.lua")
+dofile (localdir .. "/modules/remove_member_consent.lua")
 dofile (localdir .. "/modules/remove_org_consent.lua")
 dofile (localdir .. "/modules/remove_org.lua")
+dofile (localdir .. "/modules/rename_org_consent.lua")

+ 13 - 11
modpol_core/interactions/interactions.lua

@@ -48,10 +48,10 @@ end
 
 
 -- Function: modpol.interactions.org_dashboard
--- Params: user (string), org_name (string)
+-- 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_name)
-   local org = modpol.orgs.get_org(org_name)
+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
@@ -72,11 +72,13 @@ function modpol.interactions.org_dashboard(user, org_name)
    -- list available modules
    local org_modules = {}
    for k,v in pairs(org.modules) do
-      table.insert(org_modules, v.slug)
+      if not v.hide then
+         table.insert(org_modules, v.slug)
+      end
    end
 
-   -- list pending actions
-   local process_msg = #org.processes .. " total actions"
+   -- list pending
+   local process_msg = #org.processes .. " total processes"
    if org.pending[user] then
       process_msg = process_msg .. " (" .. #org.pending[user] .. " pending)"
    else
@@ -84,14 +86,14 @@ function modpol.interactions.org_dashboard(user, org_name)
    end
    
    -- set up output
-   print("Org: " .. org_name)
+   print("Org: " .. org.name)
    print("Parent: " .. parent)
    print("Members: " .. table.concat(org.members, ", "))
    print("Children: " .. table.concat(children, ", "))
    print("Modules: " .. table.concat(org_modules, ", "))
-   print("Actions: " .. process_msg)
+   print("Pending: " .. process_msg)
    print()
-   print("Commands: (M)odules, (A)ctions")
+   print("Commands: (M)odules, (P)ending")
    
    local sel = io.read()
    print()
@@ -114,7 +116,7 @@ function modpol.interactions.org_dashboard(user, org_name)
    
    elseif sel == 'a' or sel == 'A' then
       local processes = {}
-      print("All processes: (* indicates pending action)")
+      print("All processes: (* indicates pending)")
       for k,v in ipairs(org.processes) do
          local active = ''
          if org.pending[user] then
@@ -135,7 +137,7 @@ function modpol.interactions.org_dashboard(user, org_name)
       end
    else
       print("Command not found")
-      modpol.interactions.org_dashboard(user, org_name)
+      modpol.interactions.org_dashboard(user, org.name)
    end
 end
 

+ 27 - 12
modpol_core/modules/add_child_org.lua → modpol_core/modules/add_child_org_consent.lua

@@ -1,20 +1,21 @@
---- @module add_child_org
+--- @module add_child_org_consent
 -- Adds a child org
 -- Depends on `consent`
 
-local add_child_org = {
-    name = "Add child org",
-    slug = "add_child_org",
-    desc = "Create a child org within the current one with consent"
+local add_child_org_consent = {
+    name = "Add child org (consent)",
+    slug = "add_child_org_consent",
+    desc = "Create a child org in the current one with member consent"
 }
-add_child_org.data = {
-   child_name = ""
+add_child_org_consent.data = {
+   child_name = "",
+   result = nil
 }
-add_child_org.config = {
+add_child_org_consent.config = {
 }
 
 -- @function initiate
-function add_child_org:initiate(config, result)
+function add_child_org_consent:initiate(result)
    modpol.interactions.text_query(
       self.initiator,"Child org name: ",
       function(input)
@@ -22,8 +23,21 @@ function add_child_org:initiate(config, result)
             modpol.interactions.message(
                self.initiator,
                "No name entered for child org")
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.name)
+            self.org:delete_process(self.id)            
+            if result then result() end
+            return
+         elseif modpol.orgs.get_org(input) then
+            modpol.interactions.message(
+               self.initiator,
+               "Org name already in use")
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.name)
             self.org:delete_process(self.id)
-            return end
+            if result then result() end
+            return
+         end
          self.data.child_name = input
          modpol.interactions.message(
                self.initiator,
@@ -47,14 +61,15 @@ function add_child_org:initiate(config, result)
    )
 end
 
-function add_child_org:create_child_org()
+function add_child_org_consent:create_child_org()
    self.org:add_org(self.data.child_name, self.initiator)
    modpol.interactions.message_org(
       self.initiator,
       self.org.name,
       "Child org created: "..self.data.child_name)
+   if self.data.result then self.data.result() end
    self.org:delete_process(self.id)
 end
       
 --- (Required) Add to module table
-modpol.modules.add_child_org = add_child_org
+modpol.modules.add_child_org_consent = add_child_org_consent

+ 5 - 2
modpol_core/modules/consent.lua

@@ -2,9 +2,10 @@
 -- A utility module for checking consent
 
 local consent = {
-    name = "Consent",
+    name = "Consent process utility",
     slug = "consent",
-    desc = "Other modules can use to implement consent based decision making",
+    desc = "A module other modules use for consent decisions",
+    hide = true
 }
 
 consent.data = {
@@ -46,6 +47,8 @@ function consent:callback(member)
               self.org:wipe_pending_actions(self.id)
               self.org:delete_process(self.id)
            end
+           modpol.interactions.org_dashboard(
+              member, self.org.name)
         end
     )
 end

+ 23 - 9
modpol_core/modules/join_org_consent.lua

@@ -3,21 +3,30 @@
 -- Depends on the Consent module.
 
 local join_org_consent = {
-    name = "Join this org",
+    name = "Join this org (consent)",
     slug = "join_org_consent",
-    desc = "Adds member with consent of all members."
+    desc = "Adds member with consent of all members"
 }
 
 join_org_consent.data = {
+   result = nil
 }
 
 join_org_consent.config = {
 }
 
-function join_org_consent:initiate(result) 
-    self.org:call_module(
-        "consent", 
-        self.initiator, 
+function join_org_consent:initiate(result)
+   if self.org:has_member(self.initiator) then
+      modpol.interactions.message(
+         self.initiator,
+         "You are already a member of this org")
+      if result then result() end
+      self.org:delete_process(self.id)
+   else
+      self.data.result = result
+      self.org:call_module(
+         "consent", 
+         self.initiator, 
         {
             prompt = "Allow " .. self.initiator .. " to join?",
             votes_required = #self.org.members
@@ -26,12 +35,17 @@ function join_org_consent:initiate(result)
             self:complete()
         end
     )
-    if result then result() end
+   end
 end
 
 function join_org_consent:complete()
-    self.org:add_member(self.initiator)
-    print("Added " .. self.initiator .. " to the org.")
+   self.org:add_member(self.initiator)
+   modpol.interactions.message_org(
+      self.initiator,self.org.name,
+      "Consent reached: " .. self.initiator ..
+      " joined org " .. self.org.name)
+   if self.data.result then self.data.result() end
+   self.org:delete_process(self.id)
 end
 
 modpol.modules.join_org_consent = join_org_consent

+ 5 - 4
modpol_core/modules/leave_org.lua

@@ -4,7 +4,7 @@
 local leave_org = {
     name = "Leave org",
     slug = "leave_org",
-    desc = "Leave this org"
+    desc = "Remove yourself from the current org"
 }
 
 leave_org.data = {
@@ -19,9 +19,9 @@ leave_org.config = {
 -- @function initiate
 function leave_org:initiate(result)
    if self.org == modpol.instance then
-   modpol.interactions.message(
-      self.initiator,
-      "You cannot leave the root org")
+      modpol.interactions.message(
+         self.initiator,
+         "You cannot leave the root org")
    else
       self.org:remove_member(self.initiator)
       modpol.interactions.message_org(
@@ -32,6 +32,7 @@ function leave_org:initiate(result)
          "You have left org " .. self.org.name)
    end
    if result then result() end
+   self.org:delete_process(self.id)
 end
 
 --- (Required) Add to module table

+ 71 - 0
modpol_core/modules/remove_child_consent.lua

@@ -0,0 +1,71 @@
+--- Remove child (consent)
+-- A simple module that calls a consent process on an org to remove its child
+-- Depends on the Consent module.
+
+local remove_child_consent = {
+    name = "Remove child (consent)",
+    slug = "remove_child_consent",
+    desc = "Removes a child org if all members of this org consent."
+}
+
+remove_child_consent.data = {
+   result = nil,
+   child_to_remove = nil
+}
+
+remove_child_consent.config = {
+}
+
+function remove_child_consent:initiate(result)
+   local children = {}
+   for i,v in ipairs(self.org.children) do
+      local child = modpol.orgs.get_org(v)
+      if child then table.insert(children, child.name) end
+   end
+   -- Abort if no child orgs
+   if #children == 0 then
+      modpol.interactions.message(
+         self.initiator,
+         "Org has no children")
+      if result then result() end
+      self.org:delete_process(self.id)
+   else
+      self.data.result = result
+      modpol.interactions.dropdown_query(
+         self.initiator,
+         "Which child of org "..self.org.name..
+         " do you want to remove?",
+         children,
+         function(input)
+            self.data.child_to_remove = modpol.orgs.get_org(input)
+            self.org:call_module(
+               "consent",
+               self.initiator,
+               {
+                  prompt = "Remove child org "..input.."?",
+                  votes_required = #self.org.members
+               },
+               function()
+                  self:complete()
+            end)
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.name)
+      end)
+   end
+end
+
+function remove_child_consent:complete()
+   modpol.interactions.message_org(
+      self.initiator, self.data.child_to_remove.id,
+      "Removing org " .. self.data.child_to_remove.name ..
+      " by parent org consent")
+   modpol.interactions.message_org(
+      self.initiator, self.org.id,
+      "Consent reached: removing org " ..
+      self.data.child_to_remove.name)
+   self.data.child_to_remove:delete()
+   if self.data.result then self.data.result() end
+   self.org:delete_process(self.id)
+end
+
+modpol.modules.remove_child_consent = remove_child_consent

+ 64 - 0
modpol_core/modules/remove_member_consent.lua

@@ -0,0 +1,64 @@
+--- remove_member_consent
+-- @module remove_member_consent
+
+local remove_member_consent = {
+    name = "Remove a member (consent)",
+    slug = "remove_member_consent",
+    desc = "Removes org member with consent of other members"
+}
+
+remove_member_consent.data = {
+   member_to_remove = "",
+   result = nil
+}
+
+remove_member_consent.config = {
+}
+
+function remove_member_consent:initiate(result)
+   -- Abort if in root org
+   if self.org == modpol.instance then
+      modpol.interactions.message(
+         self.initiator,
+         "Members cannot be removed from the root org")
+      if result then result() end
+      self.org:delete_process(self.id)
+   else -- proceed if not root
+      self.data.result = result
+      modpol.interactions.dropdown_query(
+         self.initiator,
+         "Which member of org "..self.org.name..
+         " do you want to remove?",
+         self.org.members,
+         function(input)
+            self.data.member_to_remove = input
+            self.org:call_module(
+               "consent",
+               self.initiator,
+               {
+                  prompt = "Remove "..input..
+                     " from org "..self.org.name.."?",
+                  votes_required = #self.org.members - 1
+               },
+               function()
+                  self:complete()
+            end)
+            modpol.interactions.org_dashboard(
+         self.initiator, self.org.name)
+      end)
+   end
+end
+
+function remove_member_consent:complete()
+   modpol.interactions.message_org(
+      self.initiator, self.org.id,
+      "Consent reached: removing "..
+      self.data.member_to_remove..
+      " from org "..self.org.name)
+   self.org:remove_member(self.data.member_to_remove)
+   self.org:delete_process(self.id)
+   if self.data.result then self.data.result() end
+end
+
+--- (Required) Add to module table
+modpol.modules.remove_member_consent = remove_member_consent

+ 1 - 1
modpol_core/modules/remove_org.lua

@@ -18,7 +18,7 @@ function remove_org:initiate(result)
    if self.org == modpol.instance then
    modpol.interactions.message(
       self.initiator,
-      "You cannot remove the root org")
+      "Cannot remove the root org")
    else
       modpol.interactions.message_org(
          self.initiator,self.org.id,

+ 20 - 9
modpol_core/modules/remove_org_consent.lua

@@ -3,19 +3,28 @@
 -- Depends on the Consent module.
 
 local remove_org_consent = {
-    name = "Remove this org",
+    name = "Remove this org (consent)",
     slug = "remove_org_consent",
     desc = "Removes an org if all members consent."
 }
 
 remove_org_consent.data = {
+   result = nil
 }
 
 remove_org_consent.config = {
 }
 
-function remove_org_consent:initiate(result) 
-    self.org:call_module(
+function remove_org_consent:initiate(result)
+   if self.org == modpol.instance then
+      modpol.interactions.message(
+         self.initiator,
+         "Cannot remove root org")
+      if result then result() end
+      self.org:delete_process(self.id)
+   else
+      self.data.result = result
+      self.org:call_module(
         "consent", 
         self.initiator, 
         {
@@ -25,17 +34,19 @@ function remove_org_consent:initiate(result)
         function ()
            self:complete()
         end
-    )
-    modpol.interactions.org_dashboard(
-       self.initiator, self.org.name)
-    if result then result() end
+      )
+      modpol.interactions.org_dashboard(
+         self.initiator, self.org.name)
+   end
 end
 
 function remove_org_consent:complete()
    modpol.interactions.message_org(
       self.initiator, self.org.id,
-      "Removing org: " .. self.org.name)
-   self.org:delete()
+      "Consent reached: removing org " .. self.org.name)
+   if self.data.result then self.data.result() end
+   self.org:delete_process(self.id)
+   self.org:delete()   
 end
 
 modpol.modules.remove_org_consent = remove_org_consent

+ 77 - 0
modpol_core/modules/rename_org_consent.lua

@@ -0,0 +1,77 @@
+--- Rename org (consent)
+-- A simple module that calls a consent process on an org to rename it.
+-- Depends on the Consent module.
+
+local rename_org_consent = {
+    name = "Rename this org (consent)",
+    slug = "rename_org_consent",
+    desc = "Renames an org if all members consent."
+}
+
+rename_org_consent.data = {
+   result = nil,
+   new_name = nil
+}
+
+rename_org_consent.config = {
+}
+
+function rename_org_consent:initiate(result)
+   modpol.interactions.text_query(
+      self.initiator,"New org name: ",
+      function(input)
+         if input == "" then
+            modpol.interactions.message(
+               self.initiator,
+               "No name entered for child org")
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.name)
+            self.org:delete_process(self.id)            
+            if result then result() end
+            return
+         elseif modpol.orgs.get_org(input) then
+            modpol.interactions.message(
+               self.initiator,
+               "Org name already in use")
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.name)
+            self.org:delete_process(self.id)
+            if result then result() end
+            return
+         end
+         self.data.new_name = input
+         modpol.interactions.message(
+               self.initiator,
+               "Proposed to change name of org " ..
+               self.org.name .. " to " .. input)
+         -- initiate consent process
+         self.org:call_module(
+            "consent",
+            self.initiator, 
+            {
+               prompt = "Change name of org " ..
+                  self.org.name .. " to " .. input .. "?",
+               votes_required = #self.org.members
+            },
+            function()
+               self:complete()
+            end
+         )
+         modpol.interactions.org_dashboard(
+            self.initiator, self.org.name)
+      end
+   )
+end
+
+function rename_org_consent:complete()
+   modpol.interactions.message_org(
+      self.initiator,
+      self.org.name,
+      "Changing name of org " .. self.org.name ..
+      " to " .. self.data.new_name)
+   self.org.name = self.data.new_name
+   if self.data.result then self.data.result() end
+   self.org:delete_process(self.id)
+end
+
+modpol.modules.rename_org_consent = rename_org_consent

+ 17 - 11
modpol_core/modules/template.lua

@@ -1,20 +1,22 @@
---- module_template
--- @module module_template
+--- change_modules
+-- @module change_modules
 
 --- (Required): data table containing name and description of the module
 -- @field name "Human-readable name"
 -- @field slug "Same as module class name"
 -- @field desc "Description of the module"
-local module_template = {
+-- @field hide "Whether this is a hidden utility module"
+local change_modules = {
     name = "Module Human-Readable Name",
     slug = "template",
-    desc = "Description of the module"
+    desc = "Description of the module",
+    hide = false;
 }
 
 --- (Required) Data for module
 -- Variables that module uses during the course of a process
 -- Can be blank
-module_template.data = {
+change_modules.data = {
 }
 
 --- (Required): config for module 
@@ -25,7 +27,7 @@ module_template.data = {
 -- Default values set in config can be overridden
 -- @field field_1 ex: votes_required, default = 5
 -- @field field_2 ex: voting_type, default = "majority"
-module_template.config = {
+change_modules.config = {
     field_1 = 5
     field_2 = "majority"
 }
@@ -37,12 +39,16 @@ module_template.config = {
 -- <li><code>self.id</code> (the process id of the module instance)</li>
 -- @param result (optional) Callback if this module is embedded in other modules
 -- @function initiate
-function module_template:initiate(result)
-    -- call interaction functions here!
+function change_modules:initiate(result)
+   -- call interaction functions here!
 
-    -- call result function 
-    if result then result() end
+   -- concluding functions:
+   -- call these wherever process might end;
+   -- may need to put result in self.data.result
+   --  if process ends in another function
+   if result then result() end
+   self.org:delete_process(self.id)
 end
 
 --- (Required) Add to module table
-modpol.modules.module_template = module_template
+modpol.modules.change_modules = change_modules

+ 10 - 42
modpol_minetest/chatcommands.lua

@@ -15,10 +15,10 @@ regchat = function(name, command_table)
 end
 
 -- ===================================================================
--- /modpol
+-- /mp
 -- Presents a menu of options to users
 regchat(
-   "modpol", {
+   "mp", {
       privs = {},
       func = function(user)
          modpol.interactions.dashboard(user)
@@ -26,14 +26,17 @@ regchat(
 })
 
 -- ===================================================================
--- /reset
--- For testing only
+-- /mptest
+-- For testing only, accessible to admin users
 -- Clears the system and recreates instance with all players
+-- opens dashboard too for fun.
 regchat(
-   "reset", {
-      privs = {},
+   "mptest", {
+      privs = {privs=true},
       func = function(user)
-         modpol.orgs.reset();
+         modpol.orgs.reset()
+         modpol.instance:add_member(user)
+         modpol.interactions.dashboard(user)
          return true, "Reset orgs"
       end,
 })
@@ -71,38 +74,3 @@ regchat(
       end
 })
 
--- ===================================================================
--- /listplayers
-regchat(
-   "listplayers", {
-      privs = {},
-      func = function(user)
-         local result = table.concat(modpol.list_users(),", ")
-         return true, "All players: " .. result
-      end,
-})
-
--- ===================================================================
--- /joinorg
-regchat(
-   "joinorg", {
-      privs = {},
-      func = function(user, param)
-         local org = modpol.orgs.get_org(param)
-         local success, result = org:add_member(user)
-         return true, result
-      end,
-})
-
-
--- ===================================================================
--- /pollself [question]
--- asks the user a question specified in param
-regchat(
-   "pollself", {
-      privs = {},
-      func = function(user, param)
-         modpol.interactions.binary_poll_user(user, param)
-         return true, result
-      end,
-})

+ 31 - 27
modpol_minetest/overrides/interactions.lua

@@ -51,15 +51,15 @@ function modpol.interactions.dashboard(user)
    -- set up formspec
     local formspec = {
        "formspec_version[4]",
-       "size[10,8]",
-       "label[0.5,0.5;MODPOL DASHBOARD]",
+       "size[10,6]",
+       "label[0.5,0.5;M O D U L A R   P O L I T I C S]",
        "label[0.5,2;All orgs:]",
        "dropdown[2,1.5;5,0.8;all_orgs;"..formspec_list(all_orgs)..";;]",
        "label[0.5,3;Your orgs:]",
        "dropdown[2,2.5;5,0.8;user_orgs;"..formspec_list(user_orgs)..";;]",
        "label[0.5,4;All users:]",
        "dropdown[2,3.5;5,0.8;all_users;"..formspec_list(all_users)..";;]",
-       "button_exit[8.5,7;1,0.8;close;Close]",
+       "button_exit[8.5,5;1,0.8;close;Close]",
     }
     local formspec_string = table.concat(formspec, "")
     -- present to player
@@ -85,11 +85,11 @@ end)
 
 
 -- Function: modpol.interactions.org_dashboard
--- Params: user (string), org_name (string)
+-- Params: user (string), org_string (string or num)
 -- Output: Displays a menu of org-specific commands to the user
-function modpol.interactions.org_dashboard(user, org_name)
+function modpol.interactions.org_dashboard(user, org_string)
    -- prepare data
-   local org = modpol.orgs.get_org(org_name)
+   local org = modpol.orgs.get_org(org_string)
    if not org then return nil end
 
    local function membership_toggle(org_display)
@@ -98,9 +98,8 @@ function modpol.interactions.org_dashboard(user, org_name)
          if current_org:has_member(user) then
             return " (member)"
          end
-      else
-         return ""
       end
+      return ""
    end
    
    -- identify parent
@@ -119,32 +118,36 @@ function modpol.interactions.org_dashboard(user, org_name)
    local modules = {"View..."}
    if org.modules then
       for k,v in pairs(org.modules) do
-         table.insert(modules, v.slug)
+         if not v.hide then -- hide utility modules
+            local module_entry = v.name..
+               " ["..v.slug.."]"
+            table.insert(modules, module_entry)
+         end
       end
    end
 
-   -- prepare actions menu
-   local actions = {"View..."}
-   local num_actions = 0
+   -- prepare pending menu
+   local pending = {"View..."}
+   local num_pending = 0
    if org.pending[user] then
       for k,v in pairs(org.pending[user]) do
-         local action_string = "[" .. k .. "] " ..
-            org.processes[k].name
-         table.insert(actions, action_string)
-         num_actions = num_actions + 1
+         local pending_string = org.processes[k].name
+            .." ["..k.."]"
+         table.insert(pending, pending_string)
+         num_pending = num_pending + 1
       end
    end
 
    -- set player context
    local user_context = {}
-   user_context["current_org"] = org_name
+   user_context["current_org"] = org.name
    _contexts[user] = user_context
    -- set up formspec
     local formspec = {
        "formspec_version[4]",
        "size[10,8]",
        "label[0.5,0.5;Org: "..
-          minetest.formspec_escape(org_name)..membership_toggle(org_name).."]",
+          minetest.formspec_escape(org.name)..membership_toggle(org.name).."]",
        "label[0.5,1;Parent: "..parent..membership_toggle(parent).."]",
        "label[0.5,2;Members:]",
        "dropdown[2,1.5;5,0.8;user_orgs;"..formspec_list(org.members)..";;]",
@@ -152,8 +155,8 @@ function modpol.interactions.org_dashboard(user, org_name)
        "dropdown[2,2.5;5,0.8;children;"..formspec_list(children)..";;]",
        "label[0.5,4;Modules:]",
        "dropdown[2,3.5;5,0.8;modules;"..formspec_list(modules)..";;]",
-       "label[0.5,5;Actions ("..num_actions.."):]",
-       "dropdown[2,4.5;5,0.8;actions;"..formspec_list(actions)..";;]",
+       "label[0.5,5;Pending ("..num_pending.."):]",
+       "dropdown[2,4.5;5,0.8;pending;"..formspec_list(pending)..";;]",
        "button[8.5,7;1,0.8;back;Back]",
     }
     local formspec_string = table.concat(formspec, "")
@@ -179,7 +182,8 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          -- Receiving modules
          elseif fields.modules
             and fields.modules ~= "View..." then
-            local module = fields.modules
+            local module = string.match(
+               fields.modules,"%[(.*)%]")
             modpol.interactions.binary_poll_user(
                pname,
                modpol.modules[module].name.."\n"..
@@ -191,12 +195,12 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
                   end
             end)
             
-         -- Receiving actions
-         elseif fields.actions
-            and fields.actions ~= "View..." then
-            local action = string.match(
-               fields.actions,"%[(%d)%]")
-            local process = org.processes[tonumber(action)]
+         -- Receiving pending
+         elseif fields.pending
+            and fields.pending ~= "View..." then
+            local pending = string.match(
+               fields.pending,"%[(%d)%]")
+            local process = org.processes[tonumber(pending)]
             if process then
                org:interact(process.id, pname)
             end