Browse Source

Merge branch 'generic_approval' into 'master'

Major improvements on policy configuration

See merge request medlabboulder/modpol!35
Nathan Schneider 1 year ago
parent
commit
9b27ac145c

+ 1 - 1
README.md

@@ -101,7 +101,7 @@ We are grateful for initial support for this project from a residency with [The
 
 ## Contributing
 
-We'd love to welcome more contributors. Please join the conversation in the [Issues](https://gitlab.com/medlabboulder/modpol/-/issues), our [Matrix.org channel](https://matrix.to/#/#minetest-modpol:matrix.org), and the [Minetest.net forum](https://forum.minetest.net/viewtopic.php?f=47&t=26037).
+We'd love to welcome more contributors. Please join the conversation in the [Issues](https://gitlab.com/medlabboulder/modpol/-/issues), the \#modpol channel at the [Metagovernance Project](https://metagov.org) Slack, and the [Minetest.net forum](https://forum.minetest.net/viewtopic.php?f=47&t=26037).
 
 Learn more about the project and how to develop your own modules in [the wiki](https://gitlab.com/medlabboulder/modpol/-/wikis/home).
 

+ 5 - 7
modpol_core/api.lua

@@ -12,24 +12,22 @@ dofile (localdir .. "/interactions/interactions.lua")
 
 --modules
 --TODO make this automatic and directory-based
-dofile (localdir .. "/modules/add_child_org_consent.lua")
 dofile (localdir .. "/modules/add_child_org.lua")
 dofile (localdir .. "/modules/change_modules.lua")
 dofile (localdir .. "/modules/change_policy.lua")
 dofile (localdir .. "/modules/consent.lua")
 dofile (localdir .. "/modules/create_token.lua")
-dofile (localdir .. "/modules/defer_consent.lua")
+dofile (localdir .. "/modules/defer.lua")
 dofile (localdir .. "/modules/display_policies.lua")
 dofile (localdir .. "/modules/display_processes.lua")
-dofile (localdir .. "/modules/join_org_consent.lua")
+dofile (localdir .. "/modules/join_org.lua")
 dofile (localdir .. "/modules/leave_org.lua")
 dofile (localdir .. "/modules/message_org.lua")
 dofile (localdir .. "/modules/randomizer.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_child_org.lua")
+dofile (localdir .. "/modules/remove_member.lua")
 dofile (localdir .. "/modules/remove_org.lua")
 dofile (localdir .. "/modules/remove_process.lua")
-dofile (localdir .. "/modules/rename_org_consent.lua")
+dofile (localdir .. "/modules/rename_org.lua")
 dofile (localdir .. "/modules/send_token.lua")
 dofile (localdir .. "/modules/tokenomics.lua")

+ 6 - 3
modpol_core/interactions/interactions.lua

@@ -27,7 +27,11 @@ function modpol.interactions.get_policy_string(
             this_policy =
                tostring(this_org.policies[module_slug][k])
          else
-            this_policy = tostring(v)
+            if not v then
+               this_policy = "none"
+            else
+               this_policy = tostring(v)
+            end
          end
          table.insert(output, k.." - "..this_policy)
       end
@@ -207,6 +211,7 @@ function modpol.interactions.org_dashboard(user, org_string)
                org.name, module.slug, "\n")..
             "\n".."Proceed?",
             function(input)
+               print("\n")
                if input == "Yes" then
                   org:call_module(module_sel, user)
                elseif input == "No" then
@@ -468,10 +473,8 @@ function modpol.interactions.binary_poll_user(user, question, func)
       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")

+ 19 - 7
modpol_core/modules/add_child_org.lua

@@ -1,4 +1,4 @@
---- Adds a child org.
+--- Adds a child org
 -- @module add_child_org
 
 local add_child_org = {
@@ -8,9 +8,10 @@ local add_child_org = {
 }
 add_child_org.data = {
    child_name = "",
-   result = nil
+   result = false
 }
 add_child_org.config = {
+   approval_module = false
 }
 
 --- Initiate consent for new child org
@@ -42,23 +43,34 @@ function add_child_org:initiate(result)
          modpol.interactions.message(
                self.initiator,
                "Proposed child org: " .. input)
-         -- create the org
-         self:create_child_org()
+         -- initiate consent process
+         self:call_module(
+            self.config.approval_module,
+            self.initiator, 
+            {
+               prompt = "Create child org " ..
+                  self.data.child_name .. "?",
+               votes_required = #self.org.members
+            },
+            function()
+               self:create_child_org()
+            end
+         )
          modpol.interactions.org_dashboard(
             self.initiator, self.org.name)
       end
    )
 end
 
---- Create a new child orgg
+--- Create a new child org
 -- @function add_child_org:create_child_org
 function add_child_org:create_child_org()
    self.org:add_org(self.data.child_name, self.initiator)
    modpol.interactions.message_org(
       self.initiator,
       self.org.name,
-      "Created child org "
-      ..self.data.child_name)
+      "Created child org in " .. self.org.name .. ": "
+      .. self.data.child_name)
    if self.data.result then self.data.result() end
    self.org:delete_process(self.id)
 end

+ 0 - 78
modpol_core/modules/add_child_org_consent.lua

@@ -1,78 +0,0 @@
---- Adds a child org.
--- Depends on `consent`
--- @module add_child_org_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_consent.data = {
-   child_name = "",
-   result = nil
-}
-add_child_org_consent.config = {
-}
-
---- Initiate consent for new child org
--- @function add_child_org_consent:initiate(result)
--- @param result Callback if this module is embedded in other modules
-function add_child_org_consent:initiate(result)
-   modpol.interactions.text_query(
-      self.initiator,"Child 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)            
-            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.child_name = input
-         modpol.interactions.message(
-               self.initiator,
-               "Proposed child org: " .. input)
-         -- initiate consent process
-         self:call_module(
-            "consent",
-            self.initiator, 
-            {
-               prompt = "Create child org " ..
-                  self.data.child_name .. "?",
-               votes_required = #self.org.members
-            },
-            function()
-               self:create_child_org()
-            end
-         )
-         modpol.interactions.org_dashboard(
-            self.initiator, self.org.name)
-      end
-   )
-end
-
---- Create a new child orgg
--- @function add_child_org_consent: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,
-      "Consent reached: created child org "
-      ..self.data.child_name)
-   if self.data.result then self.data.result() end
-   self.org:delete_process(self.id)
-end
-      
-modpol.modules.add_child_org_consent = add_child_org_consent

+ 6 - 7
modpol_core/modules/change_modules.lua

@@ -1,11 +1,10 @@
 --- change_modules
--- Depends on consent
 -- @module change_modules
 
 local change_modules = {
-    name = "Change modules (consent)",
+    name = "Change modules",
     slug = "change_modules",
-    desc = "Add or remove modules from the org with member consent",
+    desc = "Add or remove modules from the org",
     hide = false;
 }
 
@@ -17,6 +16,7 @@ change_modules.data = {
 }
 
 change_modules.config = {
+   approval_module = false
 }
 
 --- Initiate change in modules.
@@ -68,7 +68,7 @@ function change_modules:initiate(result)
             self.org:delete_process(self.id)
             return
          end
-         -- proceed with consent
+         -- proceed with approval
          local query = "Accept module changes in org "..
             self.org.name.."?"
          self.data.summary = ""
@@ -80,11 +80,10 @@ function change_modules:initiate(result)
                table.concat(self.data.remove_modules,", ")
          end
          self:call_module(
-            "consent",
+            self.config.approval_module,
             self.initiator,
             {
-               prompt = query..self.data.summary,
-               votes_required = #self.org.members
+               prompt = query..self.data.summary
             },
             function()
                self:implement_change()

+ 32 - 18
modpol_core/modules/change_policy.lua

@@ -9,11 +9,11 @@ local change_policy = {
 }
 
 change_policy.data = {
-   result = nil
+   result = false
 }
 
 change_policy.config = {
-   approval = "none"
+   approval_module = false
 }
 
 --- Change modules initiate
@@ -23,8 +23,7 @@ function change_policy:initiate(result)
    -- prepare module options
    local available_modules = {}
    for k,org_mod in pairs(modpol.modules) do
-      if not org_mod.hide and
-         self.org.policies[k] then
+      if self.org.policies[k] then
          available_modules[org_mod.slug] = modpol.util.copy_table(org_mod)
    end end
    local modules_list = {}
@@ -65,16 +64,24 @@ function change_policy:initiate(result)
             self.org:delete_process(self.id)
             return
          end
+         local readable_value =
+            tostring(modpol.modules[mod_choice][policy_choice])
+         if readable_value == "nil" then
+            readable_value = "none"
+         end                     
          modpol.interactions.dropdown_query(
             self.initiator, "Choose a policy to change:",
             policy_list,
             function(policy_choice)
                modpol.interactions.text_query(
                   self.initiator,
-                  "Current " .. policy_choice .. " value: " ..
-                  tostring(modpol.modules[mod_choice][policy_choice])
-                  .. "\nChange value to (be careful!):",
+                  "Current " .. policy_choice .. " value: "
+                  .. readable_value
+                  .. "\nChange value to (or leave blank):",
                   function(policy_input)
+                     if policy_input == "" then
+                        policy_input = false
+                     end
                      self:approve_change(
                         mod_choice,
                         policy_choice,
@@ -94,17 +101,24 @@ end
 -- @param policy (string) policy slug
 -- @param input (string) input content
 function change_policy:approve_change(module_slug, policy, input)
-   -- NEED TO ADD APPROVAL CODE for consent, etc.
-   modpol.interactions.message(
+   self.org:call_module(
+      self.config.approval_module,
       self.initiator,
-      "Updating " .. policy .. " policy on module " ..
-      module_slug .. " with: " .. input)
-   self.org.policies[module_slug][policy] = input
-   modpol.interactions.org_dashboard(
-      self.initiator, self.org.id)
-   if self.data.result then self.data.result() end
-   self.org:delete_process(self.id)
-   return
+      {prompt = "Update " .. policy .. " policy on module " ..
+          module_slug .. " with: " .. input .. " ?"},
+      function()
+         modpol.interactions.message(
+            self.initiator,
+            "Updating " .. policy .. " policy on module " ..
+            module_slug .. " with: " .. input)
+         self.org.policies[module_slug][policy] = input
+         modpol.interactions.org_dashboard(
+            self.initiator, self.org.id)
+         if self.data.result then self.data.result() end
+         self.org:delete_process(self.id)
+      end,
+      self.id
+   )
 end
-   
+
 modpol.modules.change_policy = change_policy

+ 17 - 4
modpol_core/modules/consent.lua

@@ -13,8 +13,8 @@ consent.data = {
 }
 
 consent.config = {
-    prompt = "Do you consent?",
-    votes_required = 1
+   prompt = "Do you consent?",
+    votes_required = false
 }
 
 --- Initiate consent
@@ -22,13 +22,22 @@ consent.config = {
 -- @param result Callback if this module is embedded in other modules
 function consent:initiate(result)
    self.data.result = result
-   -- if org is empty, consent is given automatically
-   if self.org:get_member_count() == 0 then
+   -- if org is empty or no votes required, consent given
+   if self.org:get_member_count() == 0
+      or self.config.votes_required == 0 then
+      modpol.interactions.message_org(
+         self.initiator,
+         self.org.name,
+         "Consent reached: " .. self.config.prompt)
       if self.data.result then
          self.data.result() end
       self.org:delete_process(self.id)
    else
       -- otherwise, create poll
+      -- set default votes_required
+      if not self.config.votes_required then
+         self.config.votes_required = self.org:get_member_count()
+      end
       for id, member in pairs(self.org.members) do
          self.org:add_pending_action(self.id, member, "callback")
       end
@@ -54,6 +63,10 @@ function consent:callback(member)
               "/"..self.config.votes_required..")"
            )
            if self.data.votes >= self.config.votes_required then
+              modpol.interactions.message_org(
+                 self.initiator,
+                 self.org.name,
+                 "Consent reached: " .. self.config.prompt)
               if self.data.result then
                  self.data.result() end
               self.org:delete_process(self.id)

+ 5 - 4
modpol_core/modules/create_token.lua

@@ -3,9 +3,9 @@
 -- @module create_token
 
 local create_token = {
-    name = "Create a token (consent)",
+    name = "Create a token",
     slug = "create_token",
-    desc = "With org consent, creates an org token",
+    desc = "Creates an org token",
     hide = false;
 }
 
@@ -13,7 +13,8 @@ create_token.data = {
 }
 
 create_token.config = {
-   token_name = ""
+   token_name = "token",
+   approval_module = false
 }
 
 --- Initiate function
@@ -29,7 +30,7 @@ function create_token:initiate(result)
             "tokenomics",
             self.initiator,
             {
-               consent = true,
+               approval_module = self.config.approval_module,
                token_slug = self.config.token_name
             },
             function(input2)

+ 14 - 15
modpol_core/modules/defer_consent.lua → modpol_core/modules/defer.lua

@@ -1,30 +1,30 @@
---- Defer consent
--- @module defer_consent
+--- Defer
+-- @module defer
 
-local defer_consent = {
-    name = "Defer consent",
-    slug = "defer_consent",
-    desc = "Defers consent on a decision to another org",
+local defer = {
+    name = "Defer ",
+    slug = "defer",
+    desc = "Defers a decision to another org",
     hide = true;
 }
 
-defer_consent.data = {
+defer.data = {
 }
 
 --- Config for module 
 -- @field defer_org Name or ID of target org
 -- @field votes_required Threshold passed on to `consent`
 -- @field prompt String passed on to `consent`
-defer_consent.config = {
+defer.config = {
+   approval_module = "consent",
    defer_org = "Root",
-    votes_required = 1,
-    prompt = "Do you consent?"
+   prompt = ""
 }
 
 --- Initiate function
 -- @param result Callback if this module is embedded in other modules
--- @function defer_consent:initiate
-function defer_consent:initiate(result)
+-- @function defer:initiate
+function defer:initiate(result)
    local defer_org = modpol.orgs.get_org(self.config.defer_org)
    if not defer_org then
       modpol.interactions.message(
@@ -32,9 +32,8 @@ function defer_consent:initiate(result)
       self.org:delete_process(self.id)
    else
       defer_org:call_module(
-         "consent", self.initiator,
+         self.config.approval_module, self.initiator,
          {
-            votes_required = self.config.votes_required,
             prompt = self.config.prompt
          },
          function()
@@ -46,4 +45,4 @@ function defer_consent:initiate(result)
 end
 
 --- (Required) Add to module table
-modpol.modules.defer_consent = defer_consent
+modpol.modules.defer = defer

+ 5 - 1
modpol_core/modules/display_policies.lua

@@ -29,11 +29,15 @@ function display_policies:initiate(result)
                   v2 = self.org.policies[k][k2]
                end
                local v2_string = ""
-               if type(v2) == "string" then
+               if not v2 then
+                  v2_string = "none"
+               elseif type(v2) == "string" then
                   v2_string = v2
                elseif type(v2) == "table"
                   or type(v2) == "number" then
                   v2_string = tostring(v2)
+               elseif type(v2) == "boolean" then
+                  v2_string = tostring(v2)
                else
                   v2_string = "Could not render"
                end

+ 43 - 32
modpol_core/modules/join_org.lua

@@ -1,44 +1,55 @@
---- Adds a user to org
+--- Join org
+-- Adds initiator to an org
 -- @module join_org
 
-join_org = {}
+local join_org = {
+    name = "Join this org (consent)",
+    slug = "join_org",
+    desc = "Adds member with consent of all members"
+}
+
+join_org.data = {
+   result = nil
+}
 
-join_org.setup = {
-   name = "Join Org",
-   slug = "join_org",
-   desc = "If consent process is passed, initiator joins this org."
+join_org.config = {
+   approval_module = false
 }
 
---- Adds the user to the org
--- @function join_org.initiate
+--- Initiate join org with consent
+-- @function join_org:initiate
 -- @param result Callback if this module is embedded in other modules
-function join_org.initiate(result) 
-    modpol.interactions.binary_poll_user(
-        initiator, 
-        "Would you like to join " .. org.name, 
-        function (resp) 
-            if resp == "Yes" then
-                self.org:add_member(self.initiator)
-            end
+function join_org: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:call_module(
+         self.config.approval_module, 
+         self.initiator, 
+        {
+            prompt = "Allow " .. self.initiator .. " to join?"
+        },
+        function () 
+            self:complete()
         end
     )
+   end
+end
 
-    for i, member in ipairs(self.org.members) do
-        self.org:add_pending_action(
-            member,
-            function () 
-                modpol.interactions.binary_poll_user(
-                    member,
-                    "Let " .. initiator .. " join " .. org.name .. "?",
-                    function (resp)
-                        
-                    end
-                )
-            end
-        )
-    end
-
-    if result then result() end
+--- Adds member to org, notifies org, and deletes process
+-- @function join_org:complete
+function join_org:complete()
+   self.org:add_member(self.initiator)
+   modpol.interactions.message_org(
+      self.initiator,self.org.name,
+      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 = join_org

+ 0 - 57
modpol_core/modules/join_org_consent.lua

@@ -1,57 +0,0 @@
---- Join org (consent).
--- A simple module that calls a consent process on an org to add a member.
--- Depends on the Consent module.
--- @module join_org_consent
-
-local join_org_consent = {
-    name = "Join this org (consent)",
-    slug = "join_org_consent",
-    desc = "Adds member with consent of all members"
-}
-
-join_org_consent.data = {
-   result = nil
-}
-
-join_org_consent.config = {
-}
-
---- Initiate join org with consent
--- @function join_org_consent:initiate
--- @param result Callback if this module is embedded in other modules
-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:call_module(
-         "consent", 
-         self.initiator, 
-        {
-            prompt = "Allow " .. self.initiator .. " to join?",
-            votes_required = #self.org.members
-        },
-        function () 
-            self:complete()
-        end
-    )
-   end
-end
-
---- Adds member to org, notifies org, and deletes process
--- @function join_org_consent:complete
-function join_org_consent:complete()
-   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

+ 19 - 21
modpol_core/modules/remove_child_consent.lua → modpol_core/modules/remove_child_org.lua

@@ -1,26 +1,26 @@
---- Remove child (consent).
--- A simple module that calls a consent process on an org to remove its child.
--- Depends on the Consent module.
--- @module remove_child_consent
+--- Remove child org
+-- A simple module that calls a process on an org to remove its child.
+-- @module remove_child_org
 
-local remove_child_consent = {
-    name = "Remove child (consent)",
-    slug = "remove_child_consent",
-    desc = "Removes a child org if all members of this org consent."
+local remove_child_org = {
+    name = "Remove child org",
+    slug = "remove_child_org",
+    desc = "Removes a child org."
 }
 
-remove_child_consent.data = {
+remove_child_org.data = {
    result = nil,
    child_to_remove = nil
 }
 
-remove_child_consent.config = {
+remove_child_org.config = {
+   approval_module = false
 }
 
 --- Removes a child org with consent
--- @function remove_child_consent:initiate
+-- @function remove_child_org:initiate
 -- @param result Callback if this module is embedded in other modules
-function remove_child_consent:initiate(result)
+function remove_child_org:initiate(result)
    local children = {}
    for i,v in ipairs(self.org.children) do
       local child = modpol.orgs.get_org(v)
@@ -43,11 +43,10 @@ function remove_child_consent:initiate(result)
          function(input)
             self.data.child_to_remove = modpol.orgs.get_org(input)
             self:call_module(
-               "consent",
+               self.config.approval_module,
                self.initiator,
                {
-                  prompt = "Remove child org "..input.."?",
-                  votes_required = #self.org.members
+                  prompt = "Remove child org "..input.."?"
                },
                function()
                   self:complete()
@@ -59,19 +58,18 @@ function remove_child_consent:initiate(result)
 end
 
 --- Complete the remove process
--- @function remove_child_consent:complete
-function remove_child_consent:complete()
+-- @function remove_child_org:complete
+function remove_child_org: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")
+      "Removing this org: " .. self.data.child_to_remove.name)
    modpol.interactions.message_org(
       self.initiator, self.org.id,
-      "Consent reached: removing org " ..
+      "Removing child org of " .. self.org.name .. ": " ..
       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
+modpol.modules.remove_child_org = remove_child_org

+ 19 - 17
modpol_core/modules/remove_member_consent.lua → modpol_core/modules/remove_member.lua

@@ -1,29 +1,32 @@
---- Calls consent to remove member from org
--- @module remove_member_consent
+--- Removes member from org
+-- @module remove_member
 
-local remove_member_consent = {
-    name = "Remove a member (consent)",
-    slug = "remove_member_consent",
-    desc = "Removes org member with consent of other members"
+local remove_member = {
+    name = "Remove a member",
+    slug = "remove_member",
+    desc = "Removes org member"
 }
 
-remove_member_consent.data = {
+remove_member.data = {
    member_to_remove = "",
    result = nil
 }
 
-remove_member_consent.config = {
+remove_member.config = {
+   approval_module = false
 }
 
 --- Removes given member from org
--- @function remove_member_consent:initiate
+-- @function remove_member:initiate
 -- @param result Callback if this module is embedded in other modules
-function remove_member_consent:initiate(result)
+function remove_member: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")
+      modpol.interactions.org_dashboard(
+         self.initiator, self.org.name)
       if result then result() end
       self.org:delete_process(self.id)
    else -- proceed if not root
@@ -36,12 +39,11 @@ function remove_member_consent:initiate(result)
          function(input)
             self.data.member_to_remove = input
             self:call_module(
-               "consent",
+               self.config.approval_module,
                self.initiator,
                {
                   prompt = "Remove "..input..
-                     " from org "..self.org.name.."?",
-                  votes_required = #self.org.members - 1
+                     " from org "..self.org.name.."?"
                },
                function()
                   self:complete()
@@ -53,11 +55,11 @@ function remove_member_consent:initiate(result)
 end
 
 --- Complete after consent
--- @function remove_member_consent:complete
-function remove_member_consent:complete()
+-- @function remove_member:complete
+function remove_member:complete()
    modpol.interactions.message_org(
       self.initiator, self.org.id,
-      "Consent reached: removing "..
+      "Removing "..
       self.data.member_to_remove..
       " from org "..self.org.name)
    self.org:remove_member(self.data.member_to_remove)
@@ -65,4 +67,4 @@ function remove_member_consent:complete()
    if self.data.result then self.data.result() end
 end
 
-modpol.modules.remove_member_consent = remove_member_consent
+modpol.modules.remove_member = remove_member

+ 41 - 16
modpol_core/modules/remove_org.lua

@@ -1,32 +1,57 @@
---- A simple module that removes an org.
+--- Remove org
+-- Removes the current org
 -- @module remove_org
 
-remove_org = {
+local remove_org = {
     name = "Remove this org",
     slug = "remove_org",
-    desc = "Eliminates the org and all child orgs."
+    desc = "Removes this org."
 }
 
-remove_org.config = {}
-remove_org.data = {}
+remove_org.data = {
+   result = nil
+}
+
+remove_org.config = {
+   approval_module = false
+}
 
---- Removes org
+--- Remove org if all members consent
 -- @function remove_org:initiate
 -- @param result Callback if this module is embedded in other modules
 function remove_org:initiate(result)
    if self.org == modpol.instance then
-   modpol.interactions.message(
-      self.initiator,
-      "Cannot remove the root org")
+      modpol.interactions.message(
+         self.initiator,
+         "Cannot remove root org")
+      if result then result() end
+      self.org:delete_process(self.id)
    else
-      modpol.interactions.message_org(
-         self.initiator,self.org.id,
-         "Removing org: "..self.org.name)
-      self.org:delete()
-      modpol.interactions.dashboard(self.initiator)
-      -- call result function 
+      self.data.result = result
+      self:call_module(
+        self.config.approval_module, 
+        self.initiator, 
+        {
+           prompt = "Remove org " .. self.org.name .. "?"
+        },
+        function()
+           self:complete()
+        end
+      )
+      modpol.interactions.org_dashboard(
+         self.initiator, modpol.orgs.get_org(self.org.parent).name)
    end
-   if result then result() end
+end
+
+--- Complete after approval
+-- @function remove_org:complete
+function remove_org:complete()
+   modpol.interactions.message_org(
+      self.initiator, self.org.id,
+      "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 = remove_org

+ 0 - 58
modpol_core/modules/remove_org_consent.lua

@@ -1,58 +0,0 @@
---- Remove org (consent)
--- A simple module that calls a consent process on an org to remove it.
--- Depends on the Consent module.
--- @module remove_org_consent
-
-local remove_org_consent = {
-    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 = {
-}
-
---- Remove org if all members consent
--- @function remove_org_consent:initiate
--- @param result Callback if this module is embedded in other modules
-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:call_module(
-        "consent", 
-        self.initiator, 
-        {
-           prompt = "Remove org " .. self.org.name .. "?",
-           votes_required = #self.org.members
-        },
-        function()
-           self:complete()
-        end
-      )
-      modpol.interactions.org_dashboard(
-         self.initiator, self.org.name)
-   end
-end
-
---- Complete after consent
--- @function remove_org_consent:complete
-function remove_org_consent:complete()
-   modpol.interactions.message_org(
-      self.initiator, self.org.id,
-      "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

+ 18 - 19
modpol_core/modules/rename_org_consent.lua → modpol_core/modules/rename_org.lua

@@ -1,26 +1,26 @@
---- Rename org (consent)
--- A simple module that calls a consent process on an org to rename it.
--- Depends on the Consent module.
--- @module rename_org_consent
+--- Rename org
+-- Calls a process on an org to rename it.
+-- @module rename_org
 
-local rename_org_consent = {
-    name = "Rename this org (consent)",
-    slug = "rename_org_consent",
-    desc = "Renames an org if all members consent."
+local rename_org = {
+    name = "Rename this org",
+    slug = "rename_org",
+    desc = "Renames an org."
 }
 
-rename_org_consent.data = {
+rename_org.data = {
    result = nil,
    new_name = nil
 }
 
-rename_org_consent.config = {
+rename_org.config = {
+   approval_module = false
 }
 
 --- Renames the org after consent is reached
--- @function rename_org_consent:initiate
+-- @function rename_org:initiate
 -- @param result Callback if this module is embedded in other modules
-function rename_org_consent:initiate(result)
+function rename_org:initiate(result)
    modpol.interactions.text_query(
       self.initiator,"New org name: ",
       function(input)
@@ -50,12 +50,11 @@ function rename_org_consent:initiate(result)
                self.org.name .. " to " .. input)
          -- initiate consent process
          self:call_module(
-            "consent",
+            self.config.approval_module,
             self.initiator, 
             {
                prompt = "Change name of org " ..
-                  self.org.name .. " to " .. input .. "?",
-               votes_required = #self.org.members
+                  self.org.name .. " to " .. input .. "?"
             },
             function()
                self:complete()
@@ -67,9 +66,9 @@ function rename_org_consent:initiate(result)
    )
 end
 
---- Changes the name of the org after consent is reached
--- @funciton rename_org_consent
-function rename_org_consent:complete()
+--- Changes the name of the org
+-- @funciton rename_org
+function rename_org:complete()
    modpol.interactions.message_org(
       self.initiator,
       self.org.name,
@@ -80,4 +79,4 @@ function rename_org_consent:complete()
    self.org:delete_process(self.id)
 end
 
-modpol.modules.rename_org_consent = rename_org_consent
+modpol.modules.rename_org = rename_org

+ 2 - 2
modpol_core/modules/send_token.lua

@@ -16,7 +16,7 @@ send_token.data = {
 }
 
 send_token.config = {
-   token_name = ""
+   token_name = nil -- hidden configuration
 }
 
 --- initiate function
@@ -29,7 +29,7 @@ function send_token:initiate(result)
          table.insert(token_list, k)
       end
    end
-   if token_list == {} then
+   if #token_list == 0 then
       modpol.interactions.message(
          self.initiator,
          "No tokens in org")

+ 3 - 0
modpol_core/modules/template.lua

@@ -26,9 +26,12 @@ module_template.data = {
 -- When calling a module from within another module,
 -- variables not defined in config will be ignored.
 -- Default values set in config can be overridden
+-- @field approval_module names a module that must pass before approval; defaults to false
 -- @field field_1 ex: votes_required, default = 5
 -- @field field_2 ex: voting_type, default = "majority"
 module_template.config = {
+    approval_module = false -- visible but empty
+    hidden_config = nil -- not visible to users unless used
     field_1 = 5
     field_2 = "majority"
 }

+ 17 - 23
modpol_core/modules/tokenomics.lua

@@ -1,5 +1,4 @@
 --- Tokenomics.
--- Depends on consent
 -- @module tokenomics
 
 local tokenomics = {
@@ -14,14 +13,13 @@ tokenomics.data = {
 }
 
 --- Config for module 
--- @field consent Require consent to create?
 -- @field token_variables the data that goes into the token
 -- @field token_slug A no-spaces slug for the token
 -- @field initial_treasury Quantity in org treasury
 -- @field negative_spend Boolean: can users spend negative tokens? (for mutual credit)
 -- @field balances Table of user balances
 tokenomics.config = {
-   consent = false,
+   approval_module = false,
    token_slug = "token",
    token_variables = {
       treasury = 0,
@@ -43,29 +41,25 @@ function tokenomics:initiate(result)
          self.initiator, "Token slug taken, aborting")
       self.org:delete_process(self.id)
    else
-      if self.config.consent then
-         self:call_module(
-            "consent",
-            self.initiator,
-            {
-               prompt = "Create token "..
-                  self.config.token_slug.."?",
-               votes_required = #self.org.members
-            },
-            function()
-               modpol.interactions.message_org(
-                  self.initiator, self.org.id,
-                  "Consent reached: creating token "..
-                  self.config.token_slug)
-               self:create_token()
-            end
-         )
-      else
-         self:create_token()
-      end
+      self:call_module(
+         self.config.approval_module,
+         self.initiator,
+         {
+            prompt = "Create token " ..
+               self.config.token_slug .. "?"
+         },
+         function()
+            modpol.interactions.message_org(
+               self.initiator, self.org.id,
+               "Creating token " ..
+               self.config.token_slug)
+            self:create_token()
+         end
+      )
    end
 end
 
+
 --- Create token
 -- @function tokenomics:create_token
 function tokenomics:create_token()

+ 12 - 4
modpol_core/orgs/process.lua

@@ -3,12 +3,17 @@
 
 --- Call modules
 -- @function modpol.orgs.call_module
--- @param module_slug Same as module name
+-- @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)
-    if not modpol.modules[module_slug] then
+   if not module_slug then -- if slug is false then simply run result
+      result()
+      return
+   end
+   
+   if not modpol.modules[module_slug] then
         modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. module_slug .. '" not found')
         return
     end
@@ -64,6 +69,8 @@ function modpol.orgs:call_module(module_slug, initiator, config, result, parent_
     return index
 end
 
+
+
 --- Get the root process of the given id
 -- @function modpol.orgs.get_root_process
 -- @param id
@@ -76,7 +83,7 @@ function modpol.orgs:get_root_process(id)
     return process
 end
 
---- Delete the process given id
+--- Delete the process given id, return to dashboard
 -- @function modpol.orgs.delete_process
 -- @param id
 function modpol.orgs:delete_process(id)
@@ -97,6 +104,7 @@ function modpol.orgs:delete_process(id)
     end
 end
 
+
 --- Delete process tree by id
 -- @function modpol.orgs:delete_process_tree
 -- @param id Id of process tree
@@ -153,7 +161,7 @@ function modpol.orgs:has_pending_actions(user)
     end
 end
 
---- Interact a user with given process
+--- Create user interaction with given process
 -- @function modpol.orgs:interact
 -- @param process_id
 -- @param user