Browse Source

Minetest checkbox_query now working; checkbox-based change_modules module still needs debugging

Nathan Schneider 2 years ago
parent
commit
28a05c584c

+ 1 - 1
modpol_core/interactions/interactions.lua

@@ -369,7 +369,7 @@ function modpol.interactions.checkbox_query(
       return nil
    end
    options_display = options_display..
-      "List numbers to check (e.g., 1,2,5):"
+      "List comma-separated options to flip (e.g., 1,2,5):"
    -- begin displaying
    print(user .. ": " .. label)
    print(options_display)

+ 83 - 134
modpol_core/modules/change_modules.lua

@@ -10,7 +10,10 @@ local change_modules = {
 }
 
 change_modules.data = {
-   result = nil
+   result = nil,
+   modules_before = {},
+   modules_after = {},
+   summary = "",
 }
 
 change_modules.config = {
@@ -18,149 +21,95 @@ change_modules.config = {
 
 function change_modules:initiate(result)
    self.data.result = result
-   -- Step 1: add or remove?
-   modpol.interactions.dropdown_query(
-      self.initiator, "Module change options:",
-      {"Add module","Remove module"},
-      function(input)
-         if input == "Add module" then
-            self:add_module()
-         elseif input == "Remove module" then
-            self:remove_module()
+   self.data.add_modules = {}
+   self.data.remove_modules = {}
+   local modules_before = {}
+   local modules_after = {}
+   -- generate self.config.modules table
+   for k, module in pairs(modpol.modules) do
+      if not modpol.modules[module.slug].hide then
+         local in_org = false
+         if self.org.modules[module.slug] then
+            in_org = true
          end
+         table.insert(
+            modules_before,
+            {module.name.." ["..module.slug.."]", in_org})
       end
-   )
-end
-
-function change_modules:add_module()
-   -- prepare module options
-   local available_modules = modpol.util.copy_table(modpol.modules)
-   for k,org_mod in pairs(self.org.modules) do
-      if available_modules[org_mod.slug] then
-            available_modules[org_mod.slug] = nil
-   end end
-   -- present module options
-   local modules_list = {}
-   for k,v in pairs(available_modules) do
-      table.insert(modules_list,v.name)
    end
-   if #modules_list == 0 then
-      modpol.interactions.message(
-         self.initiator, "Org has all modules")
-      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
-   end
-   table.sort(modules_list)
-   -- now ask which to add
-   modpol.interactions.dropdown_query(
-      self.initiator, "Choose a module to add:",
-      modules_list,
-      function(mod_choice)
-         -- confirm choice
-         modpol.interactions.binary_poll_user(
-            self.initiator,
-            "Confirm: propose to add module \"" ..
-            mod_choice .. "\"?",
-            function(input)
-               if input == "Yes" then
-                  self:propose_change("add",mod_choice)
-                  modpol.interactions.org_dashboard(
-                     self.initiator, self.org.id)
+   -- send query to user
+   modpol.interactions.checkbox_query(
+      self.initiator,
+      "Check the modules to activate in this org:",
+      modules_before,
+      function(input)
+         -- identify changes
+         modules_after = input
+         for i,v in ipairs(modules_after) do
+            if v[2] ~= modules_before[i][2] then
+               if v[2] then
+                  table.insert(self.data.add_modules, v[1])
+                  modpol.msg("add-insert: "..v[1])
                else
-                  self:add_module()
+                  table.insert(self.data.remove_modules, v[1])
+                  modpol.msg("remove-insert: "..v[1])
                end
             end
-         )
-      end
-   )
+         end
+         -- abort if no changes
+         if self.data.add_modules == {}
+            and self.data.remove_modules == {} then
+            modpol.interactions.message(
+               self.initiator, "No module changes proposed")
+            modpol.interactions.org_dashboard(
+               self.initiator, self.org.id)
+            self.org:delete_process(self.id)
+            return
+         end
+         -- proceed with consent
+         local query = "Accept module changes in org "..
+            self.org.name.."?"
+         self.data.summary = ""
+         if #self.data.add_modules > 0 then
+            self.data.summary = self.data.summary.."\nAdd: "..
+               table.concat(self.data.add_modules,", ")
+         elseif #self.data.remove_modules > 0 then
+            summary = "\nRemove: "..
+               table.concat(self.data.remove_modules,", ")
+         end
+         self.org:call_module(
+            "consent",
+            self.initiator,
+            {
+               prompt = query..self.data.summary,
+               votes_required = #self.org.members
+            },
+            function()
+               self:implement_change()
+         end)
+         modpol.interactions.org_dashboard(
+            self.initiator, self.org.id)
+   end)
 end
 
-function change_modules:remove_module()
-   -- prepare module options
-   local available_modules = {}
-   for k,org_mod in pairs(self.org.modules) do
-      if not org_mod.hide then
-         available_modules[org_mod.slug] = modpol.util.copy_table(org_mod)
-   end end
-   local modules_list = {}
-   local modules_count = 0
-   for k,v in pairs(available_modules) do
-      table.insert(modules_list,v.name)
-      modules_count = modules_count + 1
+function change_modules:implement_change()
+   for i,v in ipairs(self.data.add_modules) do
+      local slug = string.match(v,"%[(.+)%]")
+      self.org.modules[slug] =
+         modpol.util.copy_table(modpol.modules[slug])
+      table.sort(self.org.modules)
    end
-   -- abort if no modules to remove
-   if modules_count == 0 then
-      modpol.interactions.message(
-         self.initiator, "Org has no modules")
-      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
+   for i,v in ipairs(self.data.remove_modules) do
+      local slug = string.match(v,"%[(.+)%]")
+      self.org.modules[slug] = nil
+      table.sort(self.org.modules)
    end
-   table.sort(modules_list)
-   -- now ask which to remove
-   modpol.interactions.dropdown_query(
-      self.initiator, "Choose a module to remove:",
-      modules_list,
-      function(mod_choice)
-         -- confirm choice
-         modpol.interactions.binary_poll_user(
-            self.initiator,
-            "Confirm: propose to remove module \"" .. mod_choice .. "\"?",
-            function(input)
-               if input == "Yes" then
-                  self:propose_change("remove",mod_choice)
-                  modpol.interactions.org_dashboard(
-                     self.initiator, self.org.id)
-               else
-                  self:remove_module()
-               end
-            end
-         )
-      end
-   )
-end
-
---- propose_change
--- @field type "add" or "remove"
-function change_modules:propose_change(type, mod_text)
-   self.org:call_module(
-      "consent",self.initiator,
-      {
-         prompt = "Do you consent to "..type..
-            " this module in org "..self.org.name..
-            ":\n"..mod_text,
-         votes_required = #self.org.members
-      },
-      function()
-         if type == "add" then
-            for k,v in pairs(modpol.modules) do
-               if v.name == mod_text then
-                  table.insert(self.org.modules,v)
-               end
-            end
-            modpol.interactions.message_org(
-               self.initiator,self.org.id,
-               "Consent reached:\nAdding \""
-               ..mod_text.."\" to org "..self.org.name)
-         elseif type == "remove" then
-            local i = 0
-            for k,v in pairs(self.org.modules) do
-               i = i + 1
-               if v.name == mod_text then
-                  self.org.modules[k] = nil
-               end                  
-            end
-            modpol.interactions.message_org(
-               self.initiator,self.org.id,
-               "Consent reached:\nRemoving \""
-               ..mod_text.."\" from org "..self.org.name)
-         end
-   end)
+   -- announce and shut down
+   modpol.interactions.message_org(
+      self.initiator,
+      self.org.id,
+      "Module changes applied to org "..self.org.name..":"..
+      self.data.summary)
    if self.data.result then self.data.result() end
    self.org:delete_process(self.id)
 end

+ 1 - 1
modpol_core/modules/display_processes.lua

@@ -38,7 +38,7 @@ function display_processes:initiate(result)
                   and type(v2) ~= "table" then
                   v2_string = tostring(v2)
                elseif type(v2) == "table" then
-                  v2_string = table.concat(v2)
+                  v2_string = tostring(v2)
                else
                   v2_string = "Could not render"
                end

+ 88 - 9
modpol_minetest/overrides/interactions.lua

@@ -66,13 +66,13 @@ function modpol.interactions.dashboard(user)
        "size[10,8]",
        "hypertext[0.5,0.5;9,1;title;<big>Org dashboard</big>]",
        "label[0.5,2;All orgs:]",
-       "dropdown[2,1.5;7,0.8;all_orgs;View...,"..formspec_list(all_orgs)..";;]",
+       "dropdown[2.5,1.5;7,0.8;all_orgs;View...,"..formspec_list(all_orgs)..";;]",
        "label[0.5,3;Your orgs:]",
-       "dropdown[2,2.5;7,0.8;user_orgs;View...,"..formspec_list(user_orgs)..";;]",
+       "dropdown[2.5,2.5;7,0.8;user_orgs;View...,"..formspec_list(user_orgs)..";;]",
        "label[0.5,4;All users:]",
-       "dropdown[2,3.5;7,0.8;all_users;View...,"..formspec_list(all_users)..";;]",
+       "dropdown[2.5,3.5;7,0.8;all_users;View...,"..formspec_list(all_users)..";;]",
        "label[0.5,5;Pending ("..user_pending_count.."):]",
-       "dropdown[2,4.5;7,0.8;pending;View...,"..formspec_list(user_pending)..";;]",
+       "dropdown[2.5,4.5;7,0.8;pending;View...,"..formspec_list(user_pending)..";;]",
        "button[0.5,7;1,0.8;refresh;Refresh]",
        "button_exit[8.5,7;1,0.8;close;Close]",
     }
@@ -181,13 +181,13 @@ function modpol.interactions.org_dashboard(user, org_string)
           minetest.formspec_escape(org.name).."</b>"..membership_toggle(org.name).."</big>]",
        "label[0.5,1.25;Parent: "..parent..membership_toggle(parent).."]",
        "label[0.5,2;Members:]",
-       "dropdown[2,1.5;7,0.8;members;View...,"..formspec_list(members)..";;]",
+       "dropdown[2.5,1.5;7,0.8;members;View...,"..formspec_list(members)..";;]",
        "label[0.5,3;Child orgs:]",
-       "dropdown[2,2.5;7,0.8;children;View...,"..formspec_list(children)..";;]",
+       "dropdown[2.5,2.5;7,0.8;children;View...,"..formspec_list(children)..";;]",
        "label[0.5,4;Modules:]",
-       "dropdown[2,3.5;7,0.8;modules;View...,"..formspec_list(modules)..";;]",
+       "dropdown[2.5,3.5;7,0.8;modules;View...,"..formspec_list(modules)..";;]",
        "label[0.5,5;Pending ("..num_pending.."):]",
-       "dropdown[2,4.5;7,0.8;pending;View...,"..formspec_list(pending)..";;]",
+       "dropdown[2.5,4.5;7,0.8;pending;View...,"..formspec_list(pending)..";;]",
        "button[0.5,7;1,0.8;refresh;Refresh]",
        "button[8.5,7;1,0.8;back;Back]",
     }
@@ -286,7 +286,7 @@ function modpol.interactions.user_dashboard(viewer, user, completion)
        "size[10,8]",
        "hypertext[0.5,0.5;9,1;title;<big>User: <b>"..user.."</b></big>]",
        "label[0.5,2;User's orgs:]",
-       "dropdown[2,1.5;7,0.8;user_orgs;View...,"..formspec_list(user_orgs)..";;]",
+       "dropdown[2.5,1.5;7,0.8;user_orgs;View...,"..formspec_list(user_orgs)..";;]",
        "button[0.5,7;1.5,0.8;message;Message]",
        "button_exit[8.5,7;1,0.8;close;Close]",
     }
@@ -484,6 +484,85 @@ minetest.register_on_player_receive_fields(function (player, formname, fields)
       end
 end)
 
+
+--- Function: modpol.interactions.checkbox_query
+-- Allows user to select from a set of options
+-- @param user Name of user (string)
+-- @param label Query for user before options (string)
+-- @param options table of options and their checked status in the form {{"option_1_string", true}, {"option_2_string", false}}
+-- @param func function to be called with param "input", made up of the corrected table in the same format as the param options
+function modpol.interactions.checkbox_query(
+      user, label, options, func)
+   -- set up formspec
+   -- prepare options
+   local vertical = 0
+   local checkbox_options = {}
+   for i,v in ipairs(options) do
+      local fs_line = ""
+      vertical = i * .5
+      fs_line = "checkbox[0,"..vertical..";checkbox_"..i..";"..
+         v[1]..";"..tostring(v[2]).."]"
+      table.insert(checkbox_options, fs_line)
+   end
+   local max = vertical * 4
+   local bar_height = vertical / 2
+   local formspec = {
+      "formspec_version[4]",
+      "size[10,8]",
+      "label[0.5,0.5;"..label.."]",
+      "scrollbaroptions[arrows=default;max="..max..";smallstep=10;largestep=100;thumbsize="..bar_height.."]",
+      "scrollbar[9,1;0.3,5.5;vertical;scroller;0]",
+      "scroll_container[0.5,1;9,5.5;scroller;vertical]",
+   }
+   -- prepare options
+   for i,v in ipairs(options) do
+      local fs_line = ""
+      local vertical = i * .5
+      fs_line = "checkbox[0,"..vertical..";checkbox_"..i..";"..
+         minetest.formspec_escape(v[1])..";"
+         ..tostring(v[2]).."]"
+      table.insert(formspec, fs_line)
+   end
+   table.insert(formspec,"scroll_container_end[]")
+   table.insert(formspec,"button[0.5,7;1.5,0.8;submit;Submit]")
+   table.insert(
+      formspec,"button_exit[8,7;1.5,0.8;cancel;Cancel]")
+   local formspec_string = table.concat(formspec, "")
+   -- present to players
+   minetest.show_formspec(user, "modpol:checkbox_query", formspec_string)
+   -- put func in _contexts
+   if _contexts[user] == nil then _contexts[user] = {} end
+   _contexts[user]["checkbox_query_func"] = func
+   _contexts[user]["checkbox_query_result"] = options
+end
+-- receive fields
+minetest.register_on_player_receive_fields(function (player, formname, fields)
+      if formname == "modpol:checkbox_query" then
+         local pname = player:get_player_name()
+         -- start checking fields
+         if fields.cancel then
+            minetest.close_formspec(pname, formname)
+         elseif fields.submit then
+            -- send in result
+            minetest.close_formspec(pname, formname)
+            _contexts[pname].checkbox_query_func(
+               _contexts[pname].checkbox_query_result)
+         else
+            for k,v in pairs(fields) do
+               -- identify checkbox actions and flip bool
+               if string.find(k,"checkbox_") then
+                  local index = tonumber(
+                     string.match(k,"%d+"))
+                  _contexts[pname].checkbox_query_result[index][2] =
+                     not _contexts[pname].checkbox_query_result[index][2]
+               end
+            end
+         end
+      end
+end)
+
+
+
 -- Function: modpol.binary_poll_user(user, question, function)
 -- Overrides function at modpol/interactions.lua
 -- Params: user (string), question (string), func (function)