Browse Source

Got modules basically working in CLI and Minetest, still having issues with Minetest interactions in module:initiate()

Nathan Schneider 2 years ago
parent
commit
721eb26777

+ 3 - 1
modpol/api.lua

@@ -13,7 +13,9 @@ dofile (localdir .. "/orgs/process.lua")
 dofile (localdir .. "/interactions/interactions.lua")
 
 --modules
+--TODO make this automatic and directory-based
+dofile (localdir .. "/modules/add_child_org.lua")
 dofile (localdir .. "/modules/consent.lua")
 dofile (localdir .. "/modules/join_org_consent.lua")
 dofile (localdir .. "/modules/remove_org_consent.lua")
---dofile (localdir .. "/modules/child_org.lua")
+dofile (localdir .. "/modules/remove_org.lua")

+ 13 - 6
modpol/interactions/interactions.lua

@@ -34,17 +34,16 @@ function modpol.interactions.dashboard(user)
    print('All users: ' .. table.concat(all_users, ', '))
    print()
 
-   print('Access which org?')
-
+   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 
-      return
+      print("Org id not found.")
    end   
-   modpol.interactions.org_dashboard(user, sel_org)
 end
 
 
@@ -72,8 +71,8 @@ function modpol.interactions.org_dashboard(user, org_name)
 
    -- list available modules
    local org_modules = {}
-   for k,v in ipairs(org.modules) do
-      table.insert(org_modules, org.modules[k].slug)
+   for k,v in pairs(org.modules) do
+      table.insert(org_modules, v.slug)
    end
 
    -- list pending actions
@@ -136,6 +135,7 @@ function modpol.interactions.org_dashboard(user, org_name)
       end
    else
       print("Command not found")
+      modpol.interactions.org_dashboard(user, org_name)
    end
 end
 
@@ -230,6 +230,13 @@ end
 -- Function: modpol.interactions.message_org
 -- input: initiator (string), org_id (number), message (string)
 -- output: broadcasts message to all org members
+function modpol.interactions.message_org(initiator, org_id, message)
+   local org = modpol.orgs.get_org(org_id)
+   local users = 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)

+ 29 - 0
modpol/modules/add_child_org.lua

@@ -0,0 +1,29 @@
+--- @module add_child_org
+-- Adds a child org
+
+local add_child_org = {
+    name = "Add child org",
+    slug = "add_child_org",
+    desc = "Create a child org within the current one"
+}
+add_child_org.data = {
+}
+add_child_org.config = {
+}
+
+-- @function initiate
+function add_child_org:initiate(result)
+   modpol.interactions.text_query(
+      self.initiator,"Child org name: ",
+      function(input)
+         self.org:add_org(input, self.initiator)
+         modpol.interactions.message_org(
+            self.initiator,
+            self.org.id,
+            "Child org created: "..input)
+         modpol.interactions.dashboard(self.initiator)
+   end)
+end
+
+--- (Required) Add to module table
+modpol.modules.add_child_org = add_child_org

+ 0 - 32
modpol/modules/child_org.lua

@@ -1,32 +0,0 @@
--- CHILD_ORG
--- Module that enables user to create child in current org
-
--- Initial configuration
-modpol.modules.child_org = {}
-modpol.modules.child_org.name = "Create child org"
-
-
--- == REQUEST ==
-
--- Initialization function
--- function: modpol.modules.child_org:initialize
-
-
--- gather data from initiator: child org name, comment
-
--- function: modpol.modules.child_org:request
-
-
-
--- == CONSENT ==
-
--- function: modpol.orgs:consent(process_id, result_function)
--- the result function should begin the completion process below
-
-
-
--- == COMPLETION ==
-
--- if approved/if failed functions?
-
--- function: modpol.modules.child_org.create(initiator, parent_org, child_org)

+ 30 - 20
modpol/modules/consent.lua

@@ -1,42 +1,52 @@
+--- @module consent
+-- A utility module for checking consent
 
-
-Consent = {}
-
-Consent.setup = {
+local consent = {
     name = "Consent",
     slug = "consent",
     desc = "Other modules can use to implement consent based decision making",
+}
+
+consent.data = {
     votes = 0
 }
 
-Consent.config = {
-    prompt = "Would you like to approve this action?",
+consent.config = {
+    prompt = "Do you consent?",
     votes_required = 1
 }
 
-function Consent:initiate(result)
-    self.result = result
-    for id, member in pairs(self.org.members) do
-        self.org:add_pending_action(self.id, member, "callback")
-    end
+function consent:initiate(result)
+   self.result = result
+   -- if org is empty, consent is given automatically
+   if self.org:get_member_count() == 0 then
+      self.result()
+      self.org:wipe_pending_actions(self.id)
+   else
+      -- otherwise, create poll
+      for id, member in pairs(self.org.members) do
+         self.org:add_pending_action(self.id, member, "callback")
+      end
+   end
 end
 
-function Consent:callback(member)
+function consent:callback(member)
     modpol.interactions.binary_poll_user(
         member,
         self.config.prompt,
         function (resp)
-            if resp == "Yes" then
-                self.votes = self.votes + 1
-            end
+           self.org:remove_pending_action(self.id,member)
+           if resp == "Yes" then
+              self.data.votes = self.data.votes + 1
+           end
             
-            if self.votes >= self.config.votes_required then
-                self.result()
-                self.org:wipe_pending_actions(self.id)
-            end
+           if self.data.votes >= self.config.votes_required then
+              if self.result then self.result() end
+              self.org:wipe_pending_actions(self.id)
+           end
         end
     )
 end
 
 
-modpol.modules.consent = Consent
+modpol.modules.consent = consent

+ 7 - 3
modpol/modules/join_org_consent.lua

@@ -2,14 +2,18 @@
 -- A simple module that calls a consent process on an org to add a member.
 -- Depends on the Consent module.
 
-join_org_consent = {}
-
-join_org_consent.setup = {
+local join_org_consent = {
     name = "Join this org",
     slug = "join_org_consent",
     desc = "Adds member with consent of all members."
 }
 
+join_org_consent.data = {
+}
+
+join_org_consent.config = {
+}
+
 function join_org_consent:initiate() 
     self.org:call_module(
         "consent", 

+ 14 - 9
modpol/modules/remove_org.lua

@@ -1,22 +1,27 @@
---- Remove Org
+--- @module Remove Org
 -- A simple module that calls a consent process on an org to remove it.
--- Depends on the Consent module.
-remove_org = {}
 
---- (Required): setup table containing name and description of the module
-remove_org.setup = {
+
+--- Main module table
+remove_org = {
     name = "Remove this org",
     slug = "remove_org",
     desc = "Removes an org if all members consent."
 }
 
+remove_org.config = {}
+remove_org.data = {}
+
 --- Initiate function
--- <li><code>self.org</code> (the org the module was called in),</li>
--- <li><code>self.initiator</code> (the user that callced the module),</li>
--- <li><code>self.id</code> (the process id of the module instance)</li>
 -- @function initiate
 function remove_org:initiate(config, result)
-
+   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 
    if result then result() end
 end
+
+modpol.modules.remove_org = remove_org

+ 18 - 10
modpol/modules/remove_org_consent.lua

@@ -1,31 +1,39 @@
 --- Remove org (consent)
 -- A simple module that calls a consent process on an org to remove it.
 -- Depends on the Consent module.
-remove_org_consent = {}
 
-remove_org_consent.setup = {
+local remove_org_consent = {
     name = "Remove this org",
-    slug = "remove_org",
+    slug = "remove_org_consent",
     desc = "Removes an org if all members consent."
 }
 
+remove_org_consent.data = {
+}
+
+remove_org_consent.config = {
+}
+
 function remove_org_consent:initiate() 
     self.org:call_module(
         "consent", 
         self.initiator, 
         {
-            prompt = "Remove org " .. self.org.name .. "?",
-            votes_required = #self.org.members
+           prompt = "Remove org " .. self.org.name .. "?",
+           votes_required = #self.org.members
         },
-        function () 
-            self:complete()
+        function ()
+           self:complete()
         end
     )
 end
 
-function join_org_consent:complete()
-    self.org:delete()
-    print("Removed org " .. self.org.name .. ".")
+function remove_org_consent:complete()
+   modpol.interactions.message_org(
+      self.initiator, self.org.id,
+      "Removing org: " .. self.org.name)
+   self.org:delete()
+   modpol.interactions.dashboard(self.initiator)
 end
 
 modpol.modules.remove_org_consent = remove_org_consent

+ 20 - 12
modpol/modules/template.lua

@@ -1,26 +1,31 @@
---- Template for modules
--- function initiate and table setup are required as a base.
--- @module Template
-Template = {}
+--- module_template
+-- @module module_template
 
---- (Required): setup table containing name and description of the module
--- @field name "Module Human-Readable Name"
--- @field slug "Template" same as module name
+--- (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"
-Template.setup = {
+local module_template = {
     name = "Module Human-Readable Name",
-    slug = "Template",
+    slug = "template",
     desc = "Description of the module"
 }
 
---- (Optional): config for module 
+--- (Required) Data for module
+-- Variables that module uses during the course of a process
+-- Can be blank
+module_template.data = {
+}
+
+--- (Required): config for module 
 -- Defines the input parameters to the module initiate function.
+-- Can be blank
 -- 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 field_1 ex: votes_required, default = 5
 -- @field field_2 ex: voting_type, default = "majority"
-Template.config = {
+module_template.config = {
     field_1 = 5
     field_2 = "majority"
 }
@@ -33,9 +38,12 @@ Template.config = {
 -- @param config (optional) If user wants to override fields in the config table
 -- @param result (optional) Callback if this module is embedded in other modules
 -- @function initiate
-function Template:initiate(config, result) 
+function module_template:initiate(config, result) 
     -- call interaction functions here!
 
     -- call result function 
     if result then result() end
 end
+
+--- (Required) Add to module table
+modpol.modules.module_template = module_template

+ 5 - 1
modpol/orgs/base.lua

@@ -1,3 +1,6 @@
+--- Orgs: Base
+-- Basic functions for orgs
+
 modpol.orgs = modpol.orgs or
 {
     count = 1,
@@ -171,7 +174,8 @@ function modpol.orgs:add_org(name, user)
     child_org.id = modpol.orgs.count
     child_org.name = name
     child_org.parent = self.id
-    child_org.processes = self.processes
+    child_org.processes = {}
+    child_org.modules = self.modules
     
     setmetatable(child_org, modpol.orgs)
 

+ 20 - 19
modpol/orgs/process.lua

@@ -1,6 +1,8 @@
-function modpol.orgs:call_module(module_name, initiator, config, result) 
-    if not modpol.modules[module_name] then
-        modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. module_name .. '" not found')
+--- Process functions for orgs
+
+function modpol.orgs:call_module(module_slug, initiator, config, result) 
+    if not modpol.modules[module_slug] then
+        modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. module_slug .. '" not found')
         return
     end
 
@@ -21,10 +23,10 @@ function modpol.orgs:call_module(module_name, initiator, config, result)
         index = #self.processes + 1
     end
 
-    local module = modpol.modules[module_name]
+    local module = modpol.modules[module_slug]
 
     -- sets default values for undeclared config variables
-    if module.config then
+    if #module.config > 0 then
         for k, v in pairs(module.config) do
             if config[k] == nil then
                 config[k] = v
@@ -39,14 +41,10 @@ function modpol.orgs:call_module(module_name, initiator, config, result)
         org = self,
         id = index,
         config = config,
-        name = module_name
+        data = module.data,
+        slug = module_slug
     }
 
-    -- copying default fields from setup
-    for k, v in pairs(module.setup) do
-        new_process[k] = v
-    end
-
     setmetatable(new_process, new_process.metatable)
 
     self.processes[index] = new_process
@@ -76,7 +74,7 @@ function modpol.orgs:wipe_pending_actions(process_id)
     end
 end
 
-function modpol.orgs:has_pending_actions()
+function modpol.orgs:has_pending_actions(user)
     -- next() will return the next pair in a table
     -- if next() returns nil, the table is empty
     if not self.pending[user] then
@@ -91,11 +89,14 @@ function modpol.orgs:has_pending_actions()
 end
 
 function modpol.orgs:interact(process_id, user)
-    local process = self.processes[process_id]
-    if self.pending[user] then
-        local callback = self.pending[user][process_id]
-        if callback then
-            process[callback](process, user)
-        end
-    end
+   local process = self.processes[process_id]
+   modpol.interactions.message(user,"hi!")
+   if self.pending[user] then
+      modpol.interactions.message(user,"id: "..process_id)
+      local callback = self.pending[user][process_id]
+      if callback then
+         modpol.interactions.message(user,"la!")
+         process[callback](process, user)
+      end
+   end
 end

+ 28 - 127
modpol_minetest/overrides/interactions.lua

@@ -59,10 +59,7 @@ function modpol.interactions.dashboard(user)
        "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[0.5,7;1,0.8;test_poll;Test poll]",
-       "button[2,7;1,0.8;add_org;Add org]",
-       "button[3.5,7;1.5,0.8;remove_org;Remove org]",
-       "button[5.5,7;1.5,0.8;reset_orgs;Reset orgs]",
+       "button[0.5,7;1.5,0.8;reset_orgs;Reset orgs]",
        "button_exit[8.5,7;1,0.8;close;Close]",
     }
     local formspec_string = table.concat(formspec, "")
@@ -75,22 +72,6 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          local pname = player:get_player_name()
          if nil then
             -- buttons first
-         elseif fields.test_poll then
-            -- FOR TESTING PURPOSES ONLY
-            modpol.interactions.text_query(
-               pname,"Poll question:",
-               function(input)
-                  modpol.interactions.binary_poll_user(
-                     pname, input,
-                     function(vote)
-                        modpol.interactions.message(
-                           pname, pname .. " voted " .. vote)
-                  end)
-            end)
-         elseif fields.add_org then
-            modpol.interactions.add_org(pname, 1)
-         elseif fields.remove_org then
-            modpol.interactions.remove_org(pname)
          elseif fields.reset_orgs then
             modpol.orgs.reset()
             modpol.instance:add_member(pname)
@@ -144,18 +125,20 @@ function modpol.interactions.org_dashboard(user, org_name)
    -- prepare modules menu
    local modules = {"View..."}
    if org.modules then
-      for k,v in ipairs(org.modules) do
-         table.insert(modules, org.modules[k].slug)
+      for k,v in pairs(org.modules) do
+         table.insert(modules, v.slug)
       end
    end
 
    -- prepare actions menu
    local actions = {"View..."}
+   local num_actions = 0
    if org.pending[user] then
       for k,v in pairs(org.pending[user]) do
          local action_string = "[" .. k .. "] " ..
-            org.processes[k].name            
+            org.processes[k].name
          table.insert(actions, action_string)
+         num_actions = num_actions + 1
       end
    end
 
@@ -177,7 +160,7 @@ 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:]",
+       "label[0.5,5;Actions ("..num_actions.."):]",
        "dropdown[2,4.5;5,0.8;actions;"..formspec_list(actions)..";;]",
        "button[0.5,7;1,0.8;test_poll;Test poll]",
        "button[2,7;1,0.8;add_child;Add child]",
@@ -195,12 +178,7 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          local org = modpol.orgs.get_org(_contexts[pname].current_org)
          if nil then
          elseif fields.join then
-            local new_request = {
-               user = pname,
-               type = "add_member",
-               params = {pname}
-            }
-            org:make_request(new_request)
+            org:add_member(pname)
             modpol.interactions.org_dashboard(pname,org.name)
          elseif fields.leave then
             org:remove_member(pname)
@@ -217,24 +195,19 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          elseif fields.add_child then
             modpol.interactions.text_query(
                pname, "Child org name:",
-               function(input)   
-                  local new_request = {
-                     user = pname,
-                     type = "add_org",
-                     params = {input}
-                  }
-                  org:make_request(new_request)
-                  modpol.interactions.message(pname,"requested")
-                  modpol.interactions.org_dashboard(
-                     pname,org.name)
+               function(input)
+                  org:add_org(input,pname)
+                  modpol.interactions.message_org(
+                     pname,
+                     org.id,
+                     "Child org created: " .. input)
             end)
          elseif fields.remove_org then
-            local new_request = {
-               user = pname,
-               type = "delete",
-               params = {}
-            }
-            org:make_request(new_request)
+            modpol.interactions.message_org(
+                     pname,
+                     org.id,
+                     "Removing org: " .. org.name)
+            org:delete()
             modpol.interactions.org_dashboard(pname,org.name)
          elseif fields.back then
             modpol.interactions.dashboard(pname)
@@ -244,8 +217,9 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          elseif fields.modules
             and fields.modules ~= "View..." then
             local module = fields.modules
-            org:call_module(module, user)
-
+            org:call_module(module, pname)
+            modpol.interactions.org_dashboard(pname,org.name)
+            
          -- Receiving actions
          elseif fields.actions
             and fields.actions ~= "View..." then
@@ -253,7 +227,7 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
                fields.actions,"%[(%d)%]")
             local process = org.processes[tonumber(action)]
             if process then
-               org:interact(process, user)
+               org:interact(process.id, pname)
             end
 
          -- Children
@@ -282,8 +256,8 @@ end
 -- ===========================
 
 -- Function: modpol.interactions.message
--- input: message (string)
--- output
+-- input: user (string), message (string)
+-- output: displays message to specified user
 function modpol.interactions.message(user, message)
    minetest.chat_send_player(user, message)
 end
@@ -291,7 +265,6 @@ end
 -- Function: modpol.interactions.text_query
 -- Overrides function at modpol/interactions.lua
 -- 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)
    -- set up formspec
@@ -303,7 +276,7 @@ function modpol.interactions.text_query(user, query, func)
        "button[0.5,2.5;1,0.8;yes;OK]",
     }
     local formspec_string = table.concat(formspec, "")
-    -- present to players
+    -- present to player
     minetest.show_formspec(user, "modpol:text_query", formspec_string)
     -- put func in _contexts
     if _contexts[user] == nil then _contexts[user] = {} end
@@ -367,10 +340,6 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
       end
 end)
 
-
--- SECONDARY INTERACTIONS
--- ======================
-
 -- Function: modpol.binary_poll_user(user, question, function)
 -- Overrides function at modpol/interactions.lua
 -- Params: user (string), question (string), func (function)
@@ -384,8 +353,8 @@ function modpol.interactions.binary_poll_user(user, question, func)
       "label[0.375,0.5;",minetest.formspec_escape(question), "]",
       "button[1,1.5;1,0.8;yes;Yes]",
       "button[2,1.5;1,0.8;no;No]",
-      --TKTK can we enable text wrapping?
-      --TKTK we could use scroll boxes to contain the text
+      --TODO can we enable text wrapping?
+      --TODO we could use scroll boxes to contain the text
    }
    local formspec_string = table.concat(formspec, "")
    if _contexts[user] == nil then _contexts[user] = {} end
@@ -409,71 +378,3 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
          minetest.close_formspec(pname, formname)
       end
 end)
-
--- COMPLEX INTERACTIONS
--- ====================
-
--- Function: modpol.interactions.message_org
--- input: initiator (string), org_id (number), message (string)
--- output: broadcasts message to all org members
-function modpol.interactions.message_org(initiator, org_id, message)
-   local org = modpol.orgs.get_org(org_id)
-   local users = 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
--- TODO for testing. This should be implemented as a request.
-function modpol.interactions.binary_poll_org(initiator, org_id, func)
-   local org = modpol.orgs.get_org(org_id)
-   local users = org:list_members()
-   modpol.interactions.text_query(
-      initiator, "Yes/no poll question:",
-      function(input)
-         for k,v in ipairs(users) do
-            modpol.interactions.binary_poll_user(v, input, func)
-         end
-   end)
-end
-
--- Function: modpol.interactions.add_org
--- input: initator (user string), base_org_id (ID)
--- output: interaction begins
--- GODMODE
-function modpol.interactions.add_org(user, base_org_id)
-   modpol.interactions.text_query(
-      user,"Org name:",
-      function(input)
-         local base_org = modpol.orgs.get_org(1)
-         local result = base_org:add_org(input, user)
-         local message = input .. " created"
-         modpol.interactions.message(user, message)
-         modpol.interactions.dashboard(user)
-   end)
-end
-
--- Function: modpol.interactions.remove_org
--- input: initator (user string)
--- output: interaction begins
--- GODMODE
-function modpol.interactions.remove_org(user)
-   -- start formspec
-   local orgs_list = modpol.orgs.list_all()
-   local label = "Choose an org to remove:"
-   modpol.interactions.dropdown_query(
-      user, label, orgs_list,
-      function(input)
-         if input then
-            local target_org = modpol.orgs.get_org(input)
-            local result = target_org:delete()
-            local message = input .. " deleted"
-            modpol.interactions.message(user, message)
-         end
-         modpol.interactions.dashboard(user)
-   end)
-end