Resolved merge conflicts with master
This commit is contained in:
@ -28,7 +28,6 @@ function add_child_org_consent:initiate(result)
|
||||
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(
|
||||
@ -45,7 +44,7 @@ function add_child_org_consent:initiate(result)
|
||||
self.initiator,
|
||||
"Proposed child org: " .. input)
|
||||
-- initiate consent process
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
@ -70,7 +69,8 @@ function add_child_org_consent:create_child_org()
|
||||
modpol.interactions.message_org(
|
||||
self.initiator,
|
||||
self.org.name,
|
||||
"Child org created: "..self.data.child_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
|
||||
|
169
modpol_core/modules/change_modules-dropdown.lua
Normal file
169
modpol_core/modules/change_modules-dropdown.lua
Normal file
@ -0,0 +1,169 @@
|
||||
--- change_modules
|
||||
-- @module change_modules
|
||||
-- Depends on consent
|
||||
|
||||
local change_modules = {
|
||||
name = "Change modules (consent)",
|
||||
slug = "change_modules",
|
||||
desc = "Add or remove modules from the org with member consent",
|
||||
hide = false;
|
||||
}
|
||||
|
||||
change_modules.data = {
|
||||
result = nil
|
||||
}
|
||||
|
||||
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()
|
||||
end
|
||||
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)
|
||||
else
|
||||
self:add_module()
|
||||
end
|
||||
end
|
||||
)
|
||||
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
|
||||
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
|
||||
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: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)
|
||||
if self.data.result then self.data.result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.change_modules = change_modules
|
@ -10,7 +10,10 @@ local change_modules = {
|
||||
}
|
||||
|
||||
change_modules.data = {
|
||||
result = nil
|
||||
result = nil,
|
||||
modules_before = {},
|
||||
modules_after = {},
|
||||
summary = "",
|
||||
}
|
||||
|
||||
change_modules.config = {
|
||||
@ -21,151 +24,93 @@ change_modules.config = {
|
||||
-- @function change_modules:initiate
|
||||
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"},
|
||||
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
|
||||
-- send query to user
|
||||
modpol.interactions.checkbox_query(
|
||||
self.initiator,
|
||||
"Check the modules to activate in this org:",
|
||||
modules_before,
|
||||
function(input)
|
||||
if input == "Add module" then
|
||||
self:add_module()
|
||||
elseif input == "Remove module" then
|
||||
self:remove_module()
|
||||
end
|
||||
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)
|
||||
-- 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])
|
||||
else
|
||||
self:add_module()
|
||||
table.insert(self.data.remove_modules, v[1])
|
||||
end
|
||||
end
|
||||
)
|
||||
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.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
|
||||
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
|
||||
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
|
||||
modpol.msg("Removing!")
|
||||
local i = 0
|
||||
for k,v in pairs(self.org.modules) do
|
||||
i = i + 1
|
||||
if v.name == mod_text then
|
||||
modpol.msg("got it!")
|
||||
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
|
||||
-- abort if no changes
|
||||
if #self.data.add_modules == 0
|
||||
and #self.data.remove_modules == 0 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
|
||||
self.data.summary = "\nRemove: "..
|
||||
table.concat(self.data.remove_modules,", ")
|
||||
end
|
||||
self: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: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
|
||||
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
|
||||
-- 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
|
||||
|
@ -2,9 +2,9 @@
|
||||
-- @module consent
|
||||
|
||||
local consent = {
|
||||
name = "Consent process utility",
|
||||
name = "Consent process",
|
||||
slug = "consent",
|
||||
desc = "A module other modules use for consent decisions",
|
||||
desc = "A utility module other modules use for consent decisions",
|
||||
hide = true
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ function consent:initiate(result)
|
||||
if self.org:get_member_count() == 0 then
|
||||
if self.data.result then
|
||||
self.data.result() end
|
||||
self.org:wipe_pending_actions(self.id)
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
-- otherwise, create poll
|
||||
for id, member in pairs(self.org.members) do
|
||||
@ -47,14 +47,19 @@ function consent:callback(member)
|
||||
if resp == "Yes" then
|
||||
self.data.votes = self.data.votes + 1
|
||||
end
|
||||
modpol.interactions.message_org(
|
||||
"consent", self.org.id,
|
||||
member.." decided "..resp.." on: "..
|
||||
self.config.prompt.." ("..self.data.votes..
|
||||
"/"..self.config.votes_required..")"
|
||||
)
|
||||
if self.data.votes >= self.config.votes_required then
|
||||
if self.data.result then
|
||||
self.data.result() end
|
||||
self.org:wipe_pending_actions(self.id)
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
modpol.interactions.org_dashboard(
|
||||
member, self.org.name)
|
||||
member, self.org.id)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
53
modpol_core/modules/create_token.lua
Normal file
53
modpol_core/modules/create_token.lua
Normal file
@ -0,0 +1,53 @@
|
||||
--- create_token
|
||||
-- @module create_token
|
||||
-- depends on tokenomics
|
||||
|
||||
local create_token = {
|
||||
name = "Create a token (consent)",
|
||||
slug = "create_token",
|
||||
desc = "With org consent, creates an org token",
|
||||
hide = false;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
create_token.data = {
|
||||
}
|
||||
|
||||
create_token.config = {
|
||||
token_name = ""
|
||||
}
|
||||
|
||||
--- (Required): initiate function
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function create_token:initiate(result)
|
||||
modpol.interactions.text_query(
|
||||
self.initiator,
|
||||
"Token name (alpha-numeric, no spaces):",
|
||||
function(input)
|
||||
self.config.token_name = input
|
||||
self:call_module(
|
||||
"tokenomics",
|
||||
self.initiator,
|
||||
{
|
||||
consent = true,
|
||||
token_slug = self.config.token_name
|
||||
},
|
||||
function(input2)
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.name)
|
||||
if result then result() end
|
||||
-- call this wherever process might end:
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
)
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.name)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.create_token = create_token
|
57
modpol_core/modules/defer_consent.lua
Normal file
57
modpol_core/modules/defer_consent.lua
Normal file
@ -0,0 +1,57 @@
|
||||
--- defer_consent
|
||||
-- @module defer_consent
|
||||
|
||||
--- (Required): data table containing name and description of the module
|
||||
-- @field name "Human-readable name (parens OK, no brackets)"
|
||||
-- @field slug "Same as module class name"
|
||||
-- @field desc "Description of the module"
|
||||
-- @field hide "Whether this is a hidden utility module"
|
||||
local defer_consent = {
|
||||
name = "Defer consent",
|
||||
slug = "defer_consent",
|
||||
desc = "Defers consent on a decision to another org",
|
||||
hide = true;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
defer_consent.data = {
|
||||
}
|
||||
|
||||
--- (Required): 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_org = "Root",
|
||||
votes_required = 1,
|
||||
prompt = "Do you consent?"
|
||||
}
|
||||
|
||||
--- (Required): initiate function
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function defer_consent:initiate(result)
|
||||
local defer_org = modpol.orgs.get_org(self.config.defer_org)
|
||||
if not defer_org then
|
||||
modpol.interactions.message(
|
||||
self.initiator, "Target org not found, aborting")
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
defer_org:call_module(
|
||||
"consent", self.initiator,
|
||||
{
|
||||
votes_required = self.config.votes_required,
|
||||
prompt = self.config.prompt
|
||||
},
|
||||
function()
|
||||
if result then result() end
|
||||
end)
|
||||
end
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.defer_consent = defer_consent
|
70
modpol_core/modules/display_processes.lua
Normal file
70
modpol_core/modules/display_processes.lua
Normal file
@ -0,0 +1,70 @@
|
||||
--- display_processes
|
||||
-- @module display_processes
|
||||
|
||||
local display_processes = {
|
||||
name = "Display processes",
|
||||
slug = "display_processes",
|
||||
desc = "Presents a detailed list of org processes",
|
||||
hide = false;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
display_processes.data = {
|
||||
}
|
||||
|
||||
display_processes.config = {
|
||||
}
|
||||
|
||||
--- (Required): initiate function
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function display_processes:initiate(result)
|
||||
local display_table = {}
|
||||
for k,v in pairs(self.org.processes) do
|
||||
if v ~= "deleted" then
|
||||
local input = v.id..": "..v.slug
|
||||
table.insert(display_table, input)
|
||||
input = "Org: "..v.org.name..
|
||||
", initiator: "..v.initiator
|
||||
table.insert(display_table, input)
|
||||
if v.config
|
||||
and modpol.util.num_pairs(v.config) > 0 then
|
||||
table.insert(display_table, "Policies:")
|
||||
for k2,v2 in pairs(v.config) do
|
||||
local v2_string = ""
|
||||
if type(v2) ~= "string"
|
||||
and type(v2) ~= "table" then
|
||||
v2_string = tostring(v2)
|
||||
elseif type(v2) == "table" then
|
||||
v2_string = tostring(v2)
|
||||
else
|
||||
v2_string = "Could not render"
|
||||
end
|
||||
input = k2..": "..v2_string
|
||||
table.insert(display_table, input)
|
||||
end
|
||||
end
|
||||
table.insert(display_table, "\n")
|
||||
end
|
||||
end
|
||||
local output = table.concat(display_table,"\n")
|
||||
if #display_table == 0 then
|
||||
output = "No processes found"
|
||||
end
|
||||
modpol.interactions.display(
|
||||
self.initiator,
|
||||
"Processes in org "..self.org.name,
|
||||
output,
|
||||
function()
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.display_processes = display_processes
|
@ -28,7 +28,7 @@ function join_org_consent:initiate(result)
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
self.data.result = result
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
|
49
modpol_core/modules/randomizer.lua
Normal file
49
modpol_core/modules/randomizer.lua
Normal file
@ -0,0 +1,49 @@
|
||||
--- @module randomizer
|
||||
-- A utility module that outputs a random result from a set of options
|
||||
|
||||
local randomizer = {
|
||||
name = "Randomizer",
|
||||
slug = "randomizer",
|
||||
desc = "A utility module other modules use for random decisions",
|
||||
hide = true
|
||||
}
|
||||
|
||||
randomizer.data = {
|
||||
}
|
||||
|
||||
-- options_table should be a table of strings
|
||||
randomizer.config = {
|
||||
options_table = {},
|
||||
num_results = 1,
|
||||
result_table = {}
|
||||
}
|
||||
|
||||
function randomizer:initiate(result)
|
||||
self.data.result = result
|
||||
self.data.options_table = modpol.util.copy_table(self.config.options_table)
|
||||
-- if options table is empty, randomizer returns that
|
||||
if #self.data.options_table == 0 or self.config.num_results == 0 then
|
||||
if self.data.result then
|
||||
self.data.result({}) end
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
-- otherwise, choose a random result
|
||||
self.random_loop()
|
||||
end
|
||||
end
|
||||
|
||||
-- returns result_table
|
||||
function randomizer:random_loop()
|
||||
self.data.results = 0
|
||||
if results == self.config.num_results then
|
||||
self.data.result(self.data.result_table)
|
||||
else
|
||||
math.randomseed(os.time())
|
||||
local index = math.random(self.data.options_table)
|
||||
table.insert(self.data.result_table, self.data.options_table[index])
|
||||
table.remove(self.data.options_table, index)
|
||||
self.data.results = self.data.results + 1
|
||||
end
|
||||
end
|
||||
|
||||
modpol.modules.randomizer = randomizer
|
@ -42,7 +42,7 @@ function remove_child_consent:initiate(result)
|
||||
children,
|
||||
function(input)
|
||||
self.data.child_to_remove = modpol.orgs.get_org(input)
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ function remove_member_consent:initiate(result)
|
||||
self.org.members,
|
||||
function(input)
|
||||
self.data.member_to_remove = input
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
|
@ -28,14 +28,14 @@ function remove_org_consent:initiate(result)
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
self.data.result = result
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
prompt = "Remove org " .. self.org.name .. "?",
|
||||
votes_required = #self.org.members
|
||||
},
|
||||
function ()
|
||||
function()
|
||||
self:complete()
|
||||
end
|
||||
)
|
||||
|
113
modpol_core/modules/remove_process.lua
Normal file
113
modpol_core/modules/remove_process.lua
Normal file
@ -0,0 +1,113 @@
|
||||
--- remove_process
|
||||
-- @module remove_process
|
||||
|
||||
local remove_process = {
|
||||
name = "Remove process",
|
||||
slug = "remove_process",
|
||||
desc = "User can remove own processes, consent required for those of others",
|
||||
hide = false;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
remove_process.data = {
|
||||
}
|
||||
|
||||
remove_process.config = {
|
||||
}
|
||||
|
||||
--- (Required): initiate function
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function remove_process:initiate(result)
|
||||
-- prepare process options
|
||||
local available_processes = {}
|
||||
for k,process in pairs(self.org.processes) do
|
||||
if process ~= "deleted" then
|
||||
available_processes[process.id] = process
|
||||
end
|
||||
end
|
||||
local process_list = {}
|
||||
local process_count = 0
|
||||
for k,v in pairs(available_processes) do
|
||||
local mine = ""
|
||||
if v.initiator == self.initiator then mine = "*" end
|
||||
table.insert(process_list,"["..v.id.."] "..v.slug..mine)
|
||||
process_count = process_count + 1
|
||||
end
|
||||
-- abort if no processes to remove
|
||||
if process_count == 0 then
|
||||
modpol.interactions.message(
|
||||
self.initiator, "Org has no modules")
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
return
|
||||
end
|
||||
table.sort(process_list)
|
||||
-- now ask which to remove
|
||||
modpol.interactions.dropdown_query(
|
||||
self.initiator, "Choose a process to remove (* marks yours, no consent required):",
|
||||
process_list,
|
||||
function(process_choice)
|
||||
-- confirm choice
|
||||
local process_id = tonumber(
|
||||
string.match(process_choice, "%d+"))
|
||||
local process_mine = string.match(process_choice,
|
||||
"%*")
|
||||
modpol.interactions.binary_poll_user(
|
||||
self.initiator,
|
||||
"Confirm: Remove process \""..
|
||||
process_choice .. "\"?",
|
||||
function(input)
|
||||
if input == "Yes" then
|
||||
if process_mine then
|
||||
self.org:delete_process_tree(process_id)
|
||||
modpol.interactions.message(
|
||||
self.initiator,
|
||||
"Removed process: "..process_choice)
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
else
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
prompt = "Approve removal of process "..process_choice.."?",
|
||||
votes_required = #self.org.members
|
||||
},
|
||||
function(input)
|
||||
modpol.interactions.message_org(
|
||||
self.initiator,
|
||||
self.org.id,
|
||||
"Removing process: "..
|
||||
process_choice)
|
||||
self.org:delete_process_tree(process_id)
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
)
|
||||
end
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
else
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.id)
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.remove_process = remove_process
|
@ -49,7 +49,7 @@ function rename_org_consent:initiate(result)
|
||||
"Proposed to change name of org " ..
|
||||
self.org.name .. " to " .. input)
|
||||
-- initiate consent process
|
||||
self.org:call_module(
|
||||
self:call_module(
|
||||
"consent",
|
||||
self.initiator,
|
||||
{
|
||||
|
77
modpol_core/modules/send_token.lua
Normal file
77
modpol_core/modules/send_token.lua
Normal file
@ -0,0 +1,77 @@
|
||||
--- send_token
|
||||
-- @module send_token
|
||||
-- depends on tokenomics
|
||||
|
||||
local send_token = {
|
||||
name = "Send tokens",
|
||||
slug = "send_token",
|
||||
desc = "Send tokens to another user",
|
||||
hide = false;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
send_token.data = {
|
||||
}
|
||||
|
||||
send_token.config = {
|
||||
token_name = ""
|
||||
}
|
||||
|
||||
--- (Required): initiate function
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function send_token:initiate(result)
|
||||
local token_list = {}
|
||||
if self.org.tokens then
|
||||
for k,v in pairs(self.org.tokens) do
|
||||
table.insert(token_list, k)
|
||||
end
|
||||
end
|
||||
if token_list == {} then
|
||||
modpol.interactions.message(
|
||||
self.initiator,
|
||||
"No tokens in org")
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.name)
|
||||
self.org:delete_process(self.id)
|
||||
return
|
||||
else
|
||||
modpol.interactions.dropdown_query(
|
||||
self.initiator,
|
||||
"Which token do you want to send?",
|
||||
token_list,
|
||||
function(input_token)
|
||||
modpol.interactions.dropdown_query(
|
||||
self.initiator,
|
||||
"Who do you want to send to?",
|
||||
modpol.util.copy_table(self.org.members),
|
||||
function(input_recipient)
|
||||
modpol.interactions.text_query(
|
||||
self.initiator,
|
||||
"How much do you want to give (a number)?",
|
||||
function(input_amount)
|
||||
modpol.modules.tokenomics.transfer(
|
||||
self.org.id,
|
||||
input_token,
|
||||
self.initiator,
|
||||
input_recipient,
|
||||
input_amount
|
||||
)
|
||||
modpol.interactions.org_dashboard(
|
||||
self.initiator, self.org.name)
|
||||
-- close process
|
||||
if result then result() end
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.send_token = send_token
|
@ -43,10 +43,13 @@ function module_template:initiate(result)
|
||||
-- call interaction functions here!
|
||||
|
||||
-- concluding functions:
|
||||
-- call these wherever process might end;
|
||||
-- first, where appropriate, return users to dashboards.
|
||||
-- second, result:
|
||||
-- may need to put result in self.data.result
|
||||
-- if process ends in another function
|
||||
-- call this when module is successful (not for abort):
|
||||
if result then result() end
|
||||
-- third, delete the process
|
||||
-- call this wherever process might end:
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
|
||||
|
213
modpol_core/modules/tokenomics.lua
Normal file
213
modpol_core/modules/tokenomics.lua
Normal file
@ -0,0 +1,213 @@
|
||||
--- tokenomics
|
||||
-- @module tokenomics
|
||||
-- Depends on consent
|
||||
|
||||
local tokenomics = {
|
||||
name = "Tokenomics",
|
||||
slug = "tokenomics",
|
||||
desc = "A simple library for token economics",
|
||||
hide = true;
|
||||
}
|
||||
|
||||
--- (Required) Data for module
|
||||
-- Variables that module uses during the course of a process
|
||||
-- Can be blank
|
||||
tokenomics.data = {
|
||||
result = nil
|
||||
}
|
||||
|
||||
--- (Required): 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,
|
||||
token_slug = "token",
|
||||
token_variables = {
|
||||
treasury = 0,
|
||||
negative_spend = true,
|
||||
balances = {}
|
||||
}
|
||||
}
|
||||
|
||||
--- (Required): initiate function: creates a token in an org
|
||||
-- set up the token data structure
|
||||
-- create an org treasury
|
||||
-- @param result (optional) Callback if this module is embedded in other modules
|
||||
-- @function initiate
|
||||
function tokenomics:initiate(result)
|
||||
-- TODO need to create a series of interactions to get the info from users
|
||||
self.data.result = result
|
||||
if self.org.tokens and self.org.tokens[slug] then
|
||||
modpol.interactions.message(
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
function tokenomics:create_token()
|
||||
if not self.org.tokens then self.org.tokens = {} end
|
||||
self.org.tokens[self.config.token_slug] =
|
||||
self.config.token_variables
|
||||
self.org:record("Created token "..self.config.token_slug,
|
||||
self.slug)
|
||||
modpol.interactions.message_org(
|
||||
self.initiator, self.org.id,
|
||||
"Created token "..self.config.token_slug)
|
||||
if self.data.result then self.data.result() end
|
||||
-- call this wherever process might end:
|
||||
self.org:delete_process(self.id)
|
||||
end
|
||||
|
||||
-----------------------------------------
|
||||
-- Utility functions
|
||||
-- all need to account for the fact that some users may not yet have balances
|
||||
-- all need to write to persistent data
|
||||
-- amount can be positive or negative (except transfer)
|
||||
|
||||
-- returns balance
|
||||
-- if no user, get treasury balance
|
||||
-- @param org Name (string) or id (num)
|
||||
-- @param token Slug (string)
|
||||
-- @param user Name (string)
|
||||
function tokenomics.balance(org, token, user)
|
||||
local this_org = modpol.orgs.get_org(org)
|
||||
if not this_org[token] then return nil, "Token not found" end
|
||||
if not user then
|
||||
return this_org[token].treasury
|
||||
end
|
||||
if not this_org[user] then
|
||||
return nil, "User not found"
|
||||
else
|
||||
local user_balance = this_org[token].balances[user]
|
||||
if user_balance then
|
||||
return user_balance
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @param org Org name (string) or id (number)
|
||||
-- @param token Token slug (string)
|
||||
function tokenomics.change_balance(org, token, user, amount)
|
||||
local this_org = modpol.orgs.get_org(org)
|
||||
if not this_org then
|
||||
return nil, "Cannot change balance: Org not found"
|
||||
elseif not this_org.tokens then
|
||||
return nil, "Cannot change balance: no tokens found"
|
||||
elseif not this_org.tokens[token] then
|
||||
return nil, "Cannot change balance: token not found"
|
||||
elseif not this_org.members[user] then
|
||||
return nil, "Cannot change balance: user not in org"
|
||||
elseif not tonumber(amount) then
|
||||
return nil, "Cannot change balance: invalid amount"
|
||||
else
|
||||
local old_balance = this_org.tokens[token].balances[user]
|
||||
if not old_balance then old_balance = 0 end
|
||||
local new_balance = old_balance + amount
|
||||
this_org.tokens[token].balances[user] = new_balance
|
||||
local msg = "Your balance of token "..token..
|
||||
" changed from "..old_balance.." to "..new_balance
|
||||
modpol.interactions.message(user, msg)
|
||||
self.org:record(
|
||||
"Changed token balance for "..user,self.slug)
|
||||
end
|
||||
end
|
||||
|
||||
-- @param amount Positive number
|
||||
function tokenomics.transfer(org, token, sender, recipient, amount)
|
||||
local sender_balance = tokenomics.balance(org, token, sender)
|
||||
local recipient_balance = tokenomics.balance(org, token, recipient)
|
||||
if not sender_balance or recipient_balance then
|
||||
return nil, "Transfer failed, user not found"
|
||||
else
|
||||
sender_balance = sender_balance - amount
|
||||
recipient_balance = recipient_balance + amount
|
||||
local neg_spend = modpol.orgs.get_org(org).tokens[token].negative_spend
|
||||
if sender_balance < 0 and not neg_spend then
|
||||
return nil, "Transfer failed, negative spend not allowed"
|
||||
else
|
||||
tokenomics.change_balance(
|
||||
org, token, sender, sender_balance)
|
||||
tokenomics.change_balance(
|
||||
org, token, recipient, recipient_balance)
|
||||
return "Transfer complete"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @param amount Can be positive or negative, assumes flow from treasury to recipient
|
||||
function tokenomics.treasury_transfer(org, token, recipient, amount)
|
||||
local this_org = modpol.orgs.get_org(org)
|
||||
if not this_org then
|
||||
return nil, "Cannot transfer treasury: Org not found"
|
||||
elseif not this_org.tokens then
|
||||
return nil, "Cannot transfer treasury: no tokens found"
|
||||
elseif not this_org.tokens[token] then
|
||||
return nil, "Cannot transfer treasury: token not found"
|
||||
elseif not this_org.members[user] then
|
||||
return nil, "Cannot transfer treasury: user not in org"
|
||||
elseif not tonumber(amount) then
|
||||
return nil, "Cannot change balance: invalid amount"
|
||||
else
|
||||
local new_treasury = this_org.tokens[token].treasury - amount
|
||||
local new_recipient_balance = tokenomics.balance(org, token, recipient) + amount
|
||||
if new_treasury < 0 and not this_org.tokens[token].negative_spend then
|
||||
return nil, "Transfer failed, negative spend not allowed"
|
||||
elseif new_recipient_balance < 0 and not this_org.tokens[token].negative_spend then
|
||||
return nil, "Transfer failed, negative spend not allowed"
|
||||
else
|
||||
this_org.tokens[token].treasury = new_treasury
|
||||
self.org:record("Treasury payment",self.slug)
|
||||
tokenomics.change_balance(org, token, recipient, amount)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- creates new tokens in the org treasury
|
||||
function tokenomics.issue(org, token, amount)
|
||||
local this_org = modpol.orgs.get_org(org)
|
||||
if not this_org then
|
||||
return nil, "Cannot transfer treasury: Org not found"
|
||||
elseif not this_org.tokens then
|
||||
return nil, "Cannot transfer treasury: no tokens found"
|
||||
elseif not this_org.tokens[token] then
|
||||
return nil, "Cannot transfer treasury: token not found"
|
||||
elseif not tonumber(amount) then
|
||||
return nil, "Cannot change balance: invalid amount"
|
||||
else
|
||||
this_org.tokens[token].treasury =
|
||||
this_org.tokens[token].treasury + amount
|
||||
self.org:record("Issued tokes to treasury","tokenomics")
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
|
||||
--- (Required) Add to module table
|
||||
modpol.modules.tokenomics = tokenomics
|
Reference in New Issue
Block a user