Compare commits

..

29 Commits

Author SHA1 Message Date
Nathan Schneider
13eb58a3ee Removed child org from parent children list 2022-08-26 15:59:38 -07:00
Nathan Schneider
ec0e4aa9c1 Small fix on policy_change variables 2022-08-23 17:11:00 -06:00
Nathan Schneider
b09a7a24b4 Improvement on error catching in process 2022-08-23 17:04:04 -06:00
Nathan Schneider
9d759530e6 Fixes on process logic 2022-08-23 16:55:57 -06:00
Nathan Schneider
838a017f14 Various bugfixes on defer and processes 2022-08-17 17:24:53 -06:00
Nathan Schneider
df20cc835b Small bugfixes 2022-08-17 15:39:11 -06:00
Nathan Schneider
0c13e6b084 Revert on CLI interactions pending process list 2022-08-17 15:09:12 -06:00
ntnsndr
d24262d494 small documentation fixes 2022-08-17 19:57:52 +00:00
23cf6abacd Merge branch 'bug-fixes' into 'master'
fixed process counter and a other small bugs

See merge request medlabboulder/modpol!37
2022-08-16 15:33:09 +00:00
Luke Miller
daa6d95bd6 merged changes, using standardized lazy table length function instead of for loop in interactions module 2022-08-16 11:12:07 -04:00
Luke Miller
52334f409e fixed process count, added lazy table length function, removed orgs now decrement org counter, orgs loaded message should now be accurate 2022-08-16 11:10:40 -04:00
56adaba7d6 Simplified README, reference to modpol.net 2022-08-16 04:49:40 +00:00
06e7bb9d2d Replaced image on README 2022-08-16 02:40:20 +00:00
Nathan Schneider
46dc48ffcc Fixed processes display in core except modules/display_processes.lua 2022-08-13 21:59:09 -06:00
Nathan Schneider
45347e2ac7 Merge branch 'master' of https://gitlab.com/medlabboulder/modpol 2022-08-13 17:02:58 -06:00
Nathan Schneider
1ff94b65fb Fixes on defer and remove_process 2022-08-13 17:02:30 -06:00
Nathan Schneider
4337e5511b Made approval on remove_process configurable 2022-08-13 16:34:03 -06:00
a26d2714d9 Merge branch 'remove-mkdir' into 'master'
Factored out Unix dependent os call

See merge request medlabboulder/modpol!36
2022-08-12 03:38:02 +00:00
Luke Miller
8d3428653c Merge branch 'master' of https://gitlab.com/medlabboulder/modpol 2022-08-11 14:57:42 -04:00
Luke Miller
6977614a7d Merge branch 'master' of https://gitlab.com/medlabboulder/modpol 2022-08-11 14:50:39 -04:00
Luke Miller
919194c995 added a placeholder file to keep data directory in git, removed now unnecessary unix mkdir call 2022-08-11 14:50:10 -04:00
Nathan Schneider
0532b084b7 Small correction on README 2022-08-11 10:49:03 -06:00
9b27ac145c Merge branch 'generic_approval' into 'master'
Major improvements on policy configuration

See merge request medlabboulder/modpol!35
2022-08-09 23:04:54 +00:00
Nathan Schneider
22a2048d5a Major improvements on policy configuration
- Bugfixes on change_policy
- Replaced _consent modules with configurable modules
2022-08-09 17:00:24 -06:00
Nathan Schneider
78ea89559f Simplier way of doing generic calls with call_module 2022-08-05 16:41:13 -06:00
Nathan Schneider
0ec287fa57 Reverting 2022-08-05 16:34:24 -06:00
Nathan Schneider
1f33232394 First shot at a generic approve() function for modules, testing on change_policy 2022-08-05 16:10:56 -06:00
Nathan Schneider
99c75861b0 small bugfix on display_processes 2022-05-25 12:30:59 -06:00
Nathan Schneider
26df04445d Small fix on CLI interactions on pending actions. 2022-05-25 12:19:34 -06:00
36 changed files with 407 additions and 698 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
*/data */data/*
!*/data/placeholder

View File

@ -1,26 +1,12 @@
# Modpol for Minetest # Modpol for Minetest
![](lib/empire-modpol.png)
Modpol, short for "modular politics," enables diverse governance processes on multi-user platforms. It offers a library with which users can choose, modify, and create modules that add specific governance functionalities. Modpol, short for "modular politics," enables diverse governance processes on multi-user platforms. It offers a library with which users can choose, modify, and create modules that add specific governance functionalities.
This implementation is a mod for [Minetest](https://minetest.net), a free/open-source voxel game. It is designed to be adapted to other multi-user platforms that also employ Lua as an extension language. This implementation is a mod for [Minetest](https://minetest.net), a free/open-source voxel game. It is designed to be adapted to other multi-user platforms that also employ Lua as an extension language.
## How to use it **Learn more at [modpol.net](https://modpol.net).**
Modpol is built around groups called *orgs*. At the base is an org with all users in it, called `Root` by default. *Modules* enable people to do things within orgs, such as decide on membership, grant powers to the org, and much more. To get started in Minetest:
* Type the command `/mp`
* Select the org `Root`
* Choose one of its modules to make new orgs and craft their behavior
![](lib/module_list.png)
Modules can be nested in each other, so one module can rely on another module to accomplish a process. Users might use a module to unilaterally carry out actions in the game, or the module might require a group decision to do so. Users can also change the modules available to users of a given org. There are currently two ways of doing this:
* Admins can remove modules from the list of modules loaded in `modpol_core/api.lua` and `modpol_minetest/api.lua`. This will make those modules no longer available to any user.
* Players can change the modules available in a given org from within the program using the `Change modules` module. Removed modules can be re-added in any org by using `Change modules` again.
Modpol should give you the ability to do whatever kind of politics you want with your modules. If there is something you would like to do that is not available, [develop a module for it](https://gitlab.com/medlabboulder/modpol/-/wikis/Module-Writing-Guide) (or ask us for help!).
## Installation in Minetest ## Installation in Minetest
@ -28,7 +14,7 @@ To use this in Minetest, simply install it in your `mods/` or `worldmods/` folde
In the game, open the Modpol dashboard with the command `/mp`. In the game, open the Modpol dashboard with the command `/mp`.
For testing purposes, players with the `privs` privilege (generally admins) can use the `/mp` command, which resets all the orgs and opens a dashboard.\ For testing purposes, players with the `privs` privilege (generally admins) can use the `/mptest` command, which resets all the orgs and opens a dashboard.\
## Standalone Version on the Command Line ## Standalone Version on the Command Line
@ -55,23 +41,6 @@ In the interpreter, for a list of global functions and tables, use `modpol.menu(
The persistent storage method may be chosen in `modpol.lua`. If available, Modpol uses Minetest's built-in StorageRef system for Minetest 5.*. If that is not available, or in CLI mode, data will be stored in a data directory at `modpol_core/data/`. This will contain a log file and serialized program data files. The persistent storage method may be chosen in `modpol.lua`. If available, Modpol uses Minetest's built-in StorageRef system for Minetest 5.*. If that is not available, or in CLI mode, data will be stored in a data directory at `modpol_core/data/`. This will contain a log file and serialized program data files.
## Design philosophy
Modpol seeks to implement a theoretical framework called "[modular politics](https://metagov.org/modpol)," which proposes these design goals:
* *Modularity*: Platform operators and community members should have the ability to construct systems by creating, importing, and arranging composable parts together as a coherent whole.
* *Expressiveness*: The governance layer should be able to implement as wide a range of processes as possible.
* *Portability*: Governance tools developed for one platform should be portable to another platform for reuse and adaptation.
* *Interoperability*: Governance systems operating on different platforms and protocols should have the ability to interact with each other, sharing data and influencing each other's processes.
Additionally, Modpol seeks to counteract the tendency for "[implicit feudalism](https://ntnsndr.in/ImplicitFeudalism)," according to which rigid, top-down power structures are the norm in online spaces. To this end, some design patterns include:
* *Groups, not roles*: While most platforms assign powers through particular permissions given to individuals, in Modpol, power lies in groups (which Modpol calls "orgs").
* *Consent, not oligarchy*: Rather than assuming that decisions will be made by a few power-holders, the software assumes that consent by all affected users is the norm.
* *Inheritance, not blank slates*: When a new group is formed, it inherits the patterns of what preceded it, rather than imagining that it is starting from scratch.
It is certainly possible to use Modpol to replicate practices of implicit feudalism, such as all-powerful admins, but doing so requires extra work to overcome these defaults.
## Documentation ## Documentation
Various guides are available at the [GitLab wiki](https://gitlab.com/medlabboulder/modpol/-/wikis/home). Various guides are available at the [GitLab wiki](https://gitlab.com/medlabboulder/modpol/-/wikis/home).
@ -101,7 +70,7 @@ We are grateful for initial support for this project from a residency with [The
## Contributing ## 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). Learn more about the project and how to develop your own modules in [the wiki](https://gitlab.com/medlabboulder/modpol/-/wikis/home).

BIN
lib/empire-modpol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

View File

@ -12,27 +12,22 @@ dofile (localdir .. "/interactions/interactions.lua")
--modules --modules
--TODO make this automatic and directory-based --TODO make this automatic and directory-based
dofile (localdir .. "/storage/store-modules.lua") dofile (localdir .. "/modules/add_child_org.lua")
modpol.load_modules(localdir .. "/modules") dofile (localdir .. "/modules/change_modules.lua")
dofile (localdir .. "/modules/change_policy.lua")
-- dofile (localdir .. "/modules/add_child_org_consent.lua") dofile (localdir .. "/modules/consent.lua")
-- dofile (localdir .. "/modules/add_child_org.lua") dofile (localdir .. "/modules/create_token.lua")
-- dofile (localdir .. "/modules/change_modules.lua") dofile (localdir .. "/modules/defer.lua")
-- dofile (localdir .. "/modules/change_policy.lua") dofile (localdir .. "/modules/display_policies.lua")
-- dofile (localdir .. "/modules/consent.lua") dofile (localdir .. "/modules/display_processes.lua")
-- dofile (localdir .. "/modules/create_token.lua") dofile (localdir .. "/modules/join_org.lua")
-- dofile (localdir .. "/modules/defer_consent.lua") dofile (localdir .. "/modules/leave_org.lua")
-- dofile (localdir .. "/modules/display_policies.lua") dofile (localdir .. "/modules/message_org.lua")
-- dofile (localdir .. "/modules/display_processes.lua") dofile (localdir .. "/modules/randomizer.lua")
-- dofile (localdir .. "/modules/join_org_consent.lua") dofile (localdir .. "/modules/remove_child_org.lua")
-- dofile (localdir .. "/modules/leave_org.lua") dofile (localdir .. "/modules/remove_member.lua")
-- dofile (localdir .. "/modules/message_org.lua") dofile (localdir .. "/modules/remove_org.lua")
-- dofile (localdir .. "/modules/randomizer.lua") dofile (localdir .. "/modules/remove_process.lua")
-- dofile (localdir .. "/modules/remove_child_consent.lua") dofile (localdir .. "/modules/rename_org.lua")
-- dofile (localdir .. "/modules/remove_member_consent.lua") dofile (localdir .. "/modules/send_token.lua")
-- dofile (localdir .. "/modules/remove_org_consent.lua") dofile (localdir .. "/modules/tokenomics.lua")
-- dofile (localdir .. "/modules/remove_org.lua")
-- dofile (localdir .. "/modules/remove_process.lua")
-- dofile (localdir .. "/modules/rename_org_consent.lua")
-- dofile (localdir .. "/modules/send_token.lua")
-- dofile (localdir .. "/modules/tokenomics.lua")

View File

View File

@ -26,9 +26,13 @@ function modpol.interactions.get_policy_string(
if this_org.policies[module_slug][k] then if this_org.policies[module_slug][k] then
this_policy = this_policy =
tostring(this_org.policies[module_slug][k]) tostring(this_org.policies[module_slug][k])
else
if not v then
this_policy = "none"
else else
this_policy = tostring(v) this_policy = tostring(v)
end end
end
table.insert(output, k.." - "..this_policy) table.insert(output, k.." - "..this_policy)
end end
return "Policies:\n" .. table.concat(output, sep) return "Policies:\n" .. table.concat(output, sep)
@ -119,7 +123,7 @@ function modpol.interactions.dashboard(user)
print("Orgs and users reset") print("Orgs and users reset")
modpol.interactions.dashboard(user) modpol.interactions.dashboard(user)
elseif sel == "Q" or "q" then elseif sel == "Q" or sel == "q" then
return return
else else
@ -148,8 +152,10 @@ function modpol.interactions.org_dashboard(user, org_string)
local children = {} local children = {}
for k,v in ipairs(org.children) do for k,v in ipairs(org.children) do
local this_child = modpol.orgs.get_org(v) local this_child = modpol.orgs.get_org(v)
if this_child then
table.insert(children, this_child.name) table.insert(children, this_child.name)
end end
end
-- prepare modules menu -- prepare modules menu
local modules = {} local modules = {}
@ -165,7 +171,13 @@ function modpol.interactions.org_dashboard(user, org_string)
table.sort(modules) table.sort(modules)
-- list pending -- list pending
local process_msg = #org.processes .. " total processes" local processes = {}
for i,v in ipairs(org.processes) do
if v ~= "deleted" then
processes[i] = org.processes[i]
end
end
local process_msg = #processes .. " total processes"
if org.pending[user] then if org.pending[user] then
process_msg = process_msg .. " (" .. process_msg = process_msg .. " (" ..
modpol.util.num_pairs(org.pending[user]) .. " pending)" modpol.util.num_pairs(org.pending[user]) .. " pending)"
@ -207,6 +219,7 @@ function modpol.interactions.org_dashboard(user, org_string)
org.name, module.slug, "\n").. org.name, module.slug, "\n")..
"\n".."Proceed?", "\n".."Proceed?",
function(input) function(input)
print("\n")
if input == "Yes" then if input == "Yes" then
org:call_module(module_sel, user) org:call_module(module_sel, user)
elseif input == "No" then elseif input == "No" then
@ -219,11 +232,9 @@ function modpol.interactions.org_dashboard(user, org_string)
modpol.interactions.org_dashboard(user, org.id) modpol.interactions.org_dashboard(user, org.id)
end end
elseif sel == 'p' or sel == 'P' then elseif sel == 'p' or sel == 'P' then -- Pending processes
local processes = {}
print("All processes: (* indicates pending)") print("All processes: (* indicates pending)")
for i,v in ipairs(org.processes) do for i,v in ipairs(processes) do
if v ~= "deleted" then
local active = '' local active = ''
if org.pending[user] then if org.pending[user] then
if org.pending[user][v.id] then if org.pending[user][v.id] then
@ -232,7 +243,6 @@ function modpol.interactions.org_dashboard(user, org_string)
end end
print("["..v.id.."] "..v.slug..active) print("["..v.id.."] "..v.slug..active)
end end
end
print() print()
print("Interact with which one (use [id] number)?") print("Interact with which one (use [id] number)?")
local to_interact = io.read() local to_interact = io.read()
@ -247,6 +257,7 @@ function modpol.interactions.org_dashboard(user, org_string)
if org.pending[user][process.id] then if org.pending[user][process.id] then
org:interact(process.id, user) org:interact(process.id, user)
end end
modpol.interactions.org_dashboard(user, org.id)
end end
elseif sel == 'b' or sel == 'B' then elseif sel == 'b' or sel == 'B' then
modpol.interactions.dashboard(user) modpol.interactions.dashboard(user)
@ -337,14 +348,14 @@ function modpol.interactions.display(user, title, message, completion)
modpol.interactions.message( modpol.interactions.message(
self.initiator, "Error: input not typed for display") self.initiator, "Error: input not typed for display")
if completion then completion() else if completion then completion() else
modpol.intereactions.dashboard(user) modpol.interactions.dashboard(user)
end end
end end
print(message) print(message)
print("\nEnter to continue") print("\nEnter to continue")
io.read() io.read()
if completion then completion() else if completion then completion() else
modpol.intereactions.dashboard(user) modpol.interactions.dashboard(user)
end end
end end
@ -467,10 +478,8 @@ function modpol.interactions.binary_poll_user(user, question, func)
answer = io.read() answer = io.read()
until answer == "y" or answer == "n" until answer == "y" or answer == "n"
if answer == "y" then if answer == "y" then
modpol.interactions.message(user, "Response recorded")
func("Yes") func("Yes")
elseif answer == "n" then elseif answer == "n" then
modpol.interactions.message(user, "Response recorded")
func("No") func("No")
else else
modpol.interactions.message(user, "Error: invalid response") modpol.interactions.message(user, "Error: invalid response")

View File

@ -55,7 +55,7 @@ dofile (topdir .. "/util/misc.lua")
-- Select a storage method -- Select a storage method
-- -- preferably, declare this in the init.lua that calls modpol.lua This is the default. -- -- preferably, declare this in the init.lua that calls modpol.lua This is the default.
-- Works with CLI: -- Works with CLI:
modpol.storage_file_path = modpol.storage_file_path or topdir .. "/storage/unix-storage.lua" modpol.storage_file_path = modpol.storage_file_path or topdir .. "/storage/storage-local.lua"
-- Works with Minetest 5: -- Works with Minetest 5:
--modpol.storage_file_path = modpol.storage_file_path or topdir .. "/storage/storage-mod_storage.lua") --modpol.storage_file_path = modpol.storage_file_path or topdir .. "/storage/storage-mod_storage.lua")

View File

@ -1,4 +1,4 @@
--- Adds a child org. --- Adds a child org
-- @module add_child_org -- @module add_child_org
local add_child_org = { local add_child_org = {
@ -8,9 +8,10 @@ local add_child_org = {
} }
add_child_org.data = { add_child_org.data = {
child_name = "", child_name = "",
result = nil result = false
} }
add_child_org.config = { add_child_org.config = {
approval_module = false
} }
--- Initiate consent for new child org --- Initiate consent for new child org
@ -42,23 +43,35 @@ function add_child_org:initiate(result)
modpol.interactions.message( modpol.interactions.message(
self.initiator, self.initiator,
"Proposed child org: " .. input) "Proposed child org: " .. input)
-- create the org -- initiate consent process
self.data.result = result
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() self:create_child_org()
end
)
modpol.interactions.org_dashboard( modpol.interactions.org_dashboard(
self.initiator, self.org.name) self.initiator, self.org.name)
end end
) )
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
function add_child_org:create_child_org() function add_child_org:create_child_org()
self.org:add_org(self.data.child_name, self.initiator) self.org:add_org(self.data.child_name, self.initiator)
modpol.interactions.message_org( modpol.interactions.message_org(
self.initiator, self.initiator,
self.org.name, self.org.name,
"Created child org " "Created child org in " .. self.org.name .. ": "
..self.data.child_name) .. self.data.child_name)
if self.data.result then self.data.result() end if self.data.result then self.data.result() end
self.org:delete_process(self.id) self.org:delete_process(self.id)
end end

View File

@ -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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ consent.data = {
consent.config = { consent.config = {
prompt = "Do you consent?", prompt = "Do you consent?",
votes_required = 1 votes_required = false
} }
--- Initiate consent --- Initiate consent
@ -22,13 +22,22 @@ consent.config = {
-- @param result Callback if this module is embedded in other modules -- @param result Callback if this module is embedded in other modules
function consent:initiate(result) function consent:initiate(result)
self.data.result = result self.data.result = result
-- if org is empty, consent is given automatically -- if org is empty or no votes required, consent given
if self.org:get_member_count() == 0 then 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 if self.data.result then
self.data.result() end self.data.result() end
self.org:delete_process(self.id) self.org:delete_process(self.id)
else else
-- otherwise, create poll -- 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 for id, member in pairs(self.org.members) do
self.org:add_pending_action(self.id, member, "callback") self.org:add_pending_action(self.id, member, "callback")
end end
@ -54,6 +63,10 @@ function consent:callback(member)
"/"..self.config.votes_required..")" "/"..self.config.votes_required..")"
) )
if self.data.votes >= self.config.votes_required then 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 if self.data.result then
self.data.result() end self.data.result() end
self.org:delete_process(self.id) self.org:delete_process(self.id)

View File

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

View File

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

View File

@ -29,11 +29,15 @@ function display_policies:initiate(result)
v2 = self.org.policies[k][k2] v2 = self.org.policies[k][k2]
end end
local v2_string = "" local v2_string = ""
if type(v2) == "string" then if not v2 then
v2_string = "none"
elseif type(v2) == "string" then
v2_string = v2 v2_string = v2
elseif type(v2) == "table" elseif type(v2) == "table"
or type(v2) == "number" then or type(v2) == "number" then
v2_string = tostring(v2) v2_string = tostring(v2)
elseif type(v2) == "boolean" then
v2_string = tostring(v2)
else else
v2_string = "Could not render" v2_string = "Could not render"
end end
@ -53,10 +57,10 @@ function display_policies:initiate(result)
"Policies in org "..self.org.name, "Policies in org "..self.org.name,
output, output,
function() function()
self.org:delete_process(self.id)
modpol.interactions.org_dashboard( modpol.interactions.org_dashboard(
self.initiator, self.org.id) self.initiator, self.org.id)
if result then result() end if result then result() end
self.org:delete_process(self.id)
end end
) )
end end

View File

@ -19,7 +19,7 @@ display_processes.config = {
-- @param result Callback if this module is embedded in other modules -- @param result Callback if this module is embedded in other modules
function display_processes:initiate(result) function display_processes:initiate(result)
local display_table = {} local display_table = {}
for k,v in pairs(self.org.processes) do for k,v in ipairs(self.org.processes) do
if v ~= "deleted" then if v ~= "deleted" then
local input = v.id..": "..v.slug local input = v.id..": "..v.slug
table.insert(display_table, input) table.insert(display_table, input)

View File

@ -1,3 +0,0 @@
change_modules-dropdown.lua
join_org.lua
template.lua

View File

@ -1,44 +1,55 @@
--- Adds a user to org --- Join org
-- Adds initiator to an org
-- @module join_org -- @module join_org
join_org = {} local join_org = {
name = "Join this org",
join_org.setup = {
name = "Join Org",
slug = "join_org", slug = "join_org",
desc = "If consent process is passed, initiator joins this org." desc = "Allows initiator to join this org"
} }
--- Adds the user to the org join_org.data = {
-- @function join_org.initiate result = nil
}
join_org.config = {
approval_module = false
}
--- Initiate join org with consent
-- @function join_org:initiate
-- @param result Callback if this module is embedded in other modules -- @param result Callback if this module is embedded in other modules
function join_org.initiate(result) function join_org:initiate(result)
modpol.interactions.binary_poll_user( if self.org:has_member(self.initiator) then
initiator, modpol.interactions.message(
"Would you like to join " .. org.name, self.initiator,
function (resp) "You are already a member of this org")
if resp == "Yes" then
self.org:add_member(self.initiator)
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 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
--- 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 end
modpol.modules.join_org = join_org modpol.modules.join_org = join_org

View File

@ -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

View File

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

View File

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

View File

@ -1,32 +1,57 @@
--- A simple module that removes an org. --- Remove org
-- Removes the current org
-- @module remove_org -- @module remove_org
remove_org = { local remove_org = {
name = "Remove this org", name = "Remove this org",
slug = "remove_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
}
--- Removes org remove_org.config = {
approval_module = false
}
--- Remove org if all members consent
-- @function remove_org:initiate -- @function remove_org:initiate
-- @param result Callback if this module is embedded in other modules -- @param result Callback if this module is embedded in other modules
function remove_org:initiate(result) function remove_org:initiate(result)
if self.org == modpol.instance then if self.org == modpol.instance then
modpol.interactions.message( modpol.interactions.message(
self.initiator, self.initiator,
"Cannot remove the root org") "Cannot remove root org")
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
end
if result then result() end 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 = "Remove org " .. self.org.name .. "?"
},
function()
self:complete()
end
)
modpol.interactions.org_dashboard(
self.initiator, modpol.orgs.get_org(self.org.parent).name)
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 end
modpol.modules.remove_org = remove_org modpol.modules.remove_org = remove_org

View File

@ -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

View File

@ -4,7 +4,7 @@
local remove_process = { local remove_process = {
name = "Remove process", name = "Remove process",
slug = "remove_process", slug = "remove_process",
desc = "User can remove own processes, consent required for those of others", desc = "User can remove own processes, approval required for those of others",
hide = false; hide = false;
} }
@ -12,6 +12,7 @@ remove_process.data = {
} }
remove_process.config = { remove_process.config = {
approval_module = "consent"
} }
--- Initiate function --- Initiate function
@ -71,11 +72,12 @@ function remove_process:initiate(result)
self.org:delete_process(self.id) self.org:delete_process(self.id)
else else
self:call_module( self:call_module(
"consent", self.config.approval_module,
self.initiator, self.initiator,
{ {
prompt = "Approve removal of process "..process_choice.."?", prompt =
votes_required = #self.org.members "Approve removal of process "
..process_choice.."?"
}, },
function(input) function(input)
modpol.interactions.message_org( modpol.interactions.message_org(

View File

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

View File

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

View File

@ -26,9 +26,12 @@ module_template.data = {
-- When calling a module from within another module, -- When calling a module from within another module,
-- variables not defined in config will be ignored. -- variables not defined in config will be ignored.
-- Default values set in config can be overridden -- 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_1 ex: votes_required, default = 5
-- @field field_2 ex: voting_type, default = "majority" -- @field field_2 ex: voting_type, default = "majority"
module_template.config = { module_template.config = {
approval_module = false -- visible but empty
hidden_config = nil -- not visible to users unless used
field_1 = 5 field_1 = 5
field_2 = "majority" field_2 = "majority"
} }

View File

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

View File

@ -25,19 +25,24 @@ end
--- Return org when given its id or name --- Return org when given its id or name
-- @function modpol.orgs.get_org -- @function modpol.orgs.get_org
-- @param arg string for name of org or id of org -- @param arg string for name of org or id of org, or nil if no org
-- @return org specified by id or name -- @return org specified by id or name
function modpol.orgs.get_org(arg) function modpol.orgs.get_org(arg)
local output = nil
if type(arg) == 'string' then if type(arg) == 'string' then
for id, org in ipairs(modpol.orgs.array) do for id, org in ipairs(modpol.orgs.array) do
if org ~= "deleted" then
if org.name == arg then if org.name == arg then
return org output = org
end
end end
end end
elseif type(arg) == 'number' then elseif type(arg) == 'number' then
return modpol.orgs.array[arg] if modpol.orgs.array[arg] ~= "deleted" then
output = modpol.orgs.array[arg]
end end
return nil end
return output
end end
--- Return a table list of all org names --- Return a table list of all org names
@ -80,7 +85,7 @@ function modpol.orgs.reset()
modpol.util.copy_table(modpol.instance.members) modpol.util.copy_table(modpol.instance.members)
for id, org in ipairs(modpol.orgs.array) do for id, org in ipairs(modpol.orgs.array) do
if id > 1 then if id > 1 then
modpol.orgs.array[id] = "removed" modpol.orgs.array[id] = "deleted"
end end
end end
@ -215,6 +220,17 @@ function modpol.orgs:delete()
return false return false
end end
-- remove from parent's list
local parent = modpol.orgs.get_org(self.id)
if parent then
for k,v in ipairs(parent.children) do
if v == self.id then
v = "deleted"
end
end
end
-- remove children
if #self.children > 0 then if #self.children > 0 then
for i, child_id in pairs(self.children) do for i, child_id in pairs(self.children) do
local child = modpol.orgs.get_org(child_id) local child = modpol.orgs.get_org(child_id)
@ -223,7 +239,8 @@ function modpol.orgs:delete()
end end
end end
modpol.orgs.array[self.id] = 'removed' modpol.orgs.array[self.id] = 'deleted'
modpol.orgs.count = modpol.orgs.count - 1
modpol.ocutil.log('Deleted org ' .. self.name .. ': ' .. self.id) modpol.ocutil.log('Deleted org ' .. self.name .. ': ' .. self.id)
self:record('Deleted ' .. self.name .. ' and all child orgs', 'del_org') self:record('Deleted ' .. self.name .. ' and all child orgs', 'del_org')

View File

@ -3,13 +3,22 @@
--- Call modules --- Call modules
-- @function modpol.orgs.call_module -- @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 intiator Initiator for module
-- @param config Config for module -- @param config Config for module
-- @param result -- @param result
function modpol.orgs:call_module(module_slug, initiator, config, result, parent_id) function modpol.orgs:call_module(module_slug, initiator, config, result, parent_id)
if not modpol.modules[module_slug] then
modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. module_slug .. '" not found') -- first, if no slug, just run result
-- may not be necessary if we use false as default approval_module
if not module_slug then
if result() then
result()
end
return
-- if module doesn't exist, abort
elseif not modpol.modules[module_slug] then
modpol.ocutil.log('Error in ' .. self.name .. ':call_module -> module "' .. tostring(module_slug) .. '" not found')
return return
end end
@ -64,6 +73,8 @@ function modpol.orgs:call_module(module_slug, initiator, config, result, parent_
return index return index
end end
--- Get the root process of the given id --- Get the root process of the given id
-- @function modpol.orgs.get_root_process -- @function modpol.orgs.get_root_process
-- @param id -- @param id
@ -76,7 +87,7 @@ function modpol.orgs:get_root_process(id)
return process return process
end end
--- Delete the process given id --- Delete the process given id, return to dashboard
-- @function modpol.orgs.delete_process -- @function modpol.orgs.delete_process
-- @param id -- @param id
function modpol.orgs:delete_process(id) function modpol.orgs:delete_process(id)
@ -97,6 +108,7 @@ function modpol.orgs:delete_process(id)
end end
end end
--- Delete process tree by id --- Delete process tree by id
-- @function modpol.orgs:delete_process_tree -- @function modpol.orgs:delete_process_tree
-- @param id Id of process tree -- @param id Id of process tree
@ -122,7 +134,7 @@ end
-- @param user -- @param user
function modpol.orgs:remove_pending_action(process_id, user) function modpol.orgs:remove_pending_action(process_id, user)
if self.pending[user] then if self.pending[user] then
self.pending[user][process_id] = nil self.pending[user][process_id] = "deleted"
end end
end end
@ -131,7 +143,7 @@ end
-- @param process_id -- @param process_id
function modpol.orgs:wipe_pending_actions(process_id) function modpol.orgs:wipe_pending_actions(process_id)
for user in pairs(self.pending) do for user in pairs(self.pending) do
self.pending[user][process_id] = nil self.pending[user][process_id] = "deleted"
end end
end end
@ -153,7 +165,7 @@ function modpol.orgs:has_pending_actions(user)
end end
end end
--- Interact a user with given process --- Create user interaction with given process
-- @function modpol.orgs:interact -- @function modpol.orgs:interact
-- @param process_id -- @param process_id
-- @param user -- @param user

View File

@ -11,8 +11,6 @@ modpol.file_ledger = modpol.datadir .. "/ledger.dat"
modpol.file_orgs = modpol.datadir .. "/orgs.dat" modpol.file_orgs = modpol.datadir .. "/orgs.dat"
modpol.file_old_ledgers = modpol.datadir .. "/old_ledgers.dat" modpol.file_old_ledgers = modpol.datadir .. "/old_ledgers.dat"
os.execute ("mkdir -p " .. modpol.datadir)
modpol.ocutil.setlogdir (modpol.datadir) modpol.ocutil.setlogdir (modpol.datadir)
modpol.ocutil.setlogname ("modpol.log") modpol.ocutil.setlogname ("modpol.log")
@ -101,7 +99,7 @@ local load_orgs = function()
-- setmetatable(org, modpol.orgs) -- setmetatable(org, modpol.orgs)
-- end -- end
local nn = modpol.ocutil.table_length (modpol.orgs.array) local nn = modpol.orgs.count
local str = "entries" local str = "entries"
if nn == 1 then str = "entry" end if nn == 1 then str = "entry" end
modpol.ocutil.log (nn .. " orgs loaded from disk") modpol.ocutil.log (nn .. " orgs loaded from disk")

View File

@ -1,23 +0,0 @@
modpol.load_modules = function(path)
dofile (path .. "/add_child_org_consent.lua")
dofile (path .. "/add_child_org.lua")
dofile (path .. "/change_modules.lua")
dofile (path .. "/change_policy.lua")
dofile (path .. "/consent.lua")
dofile (path .. "/create_token.lua")
dofile (path .. "/defer_consent.lua")
dofile (path .. "/display_policies.lua")
dofile (path .. "/display_processes.lua")
dofile (path .. "/join_org_consent.lua")
dofile (path .. "/leave_org.lua")
dofile (path .. "/message_org.lua")
dofile (path .. "/randomizer.lua")
dofile (path .. "/remove_child_consent.lua")
dofile (path .. "/remove_member_consent.lua")
dofile (path .. "/remove_org_consent.lua")
dofile (path .. "/remove_org.lua")
dofile (path .. "/remove_process.lua")
dofile (path .. "/rename_org_consent.lua")
dofile (path .. "/send_token.lua")
dofile (path .. "/tokenomics.lua")
end

View File

@ -1,59 +0,0 @@
local lfs
-- checks if lua file system is installed
local using_lfs = pcall(function() lfs = require "lfs" end)
-- switches to legacy module loading if lfs is not available
if using_lfs then
-- loads file names to ignore into a table
function fetch_ignores(module_path)
local ignore_list = {}
-- checks if ignore.txt exists
local f_test = io.open(module_path .. "/ignore.txt", "r")
if not f_test then return {} end
-- puts each line of ignore.txt into the table
local f = io.lines(module_path .. "/ignore.txt")
for line in f do
table.insert(ignore_list, line)
end
return ignore_list
end
-- checks if a string is in a list
function check_list(ignore_list, name)
for i, v in ipairs(ignore_list) do
if v == name then
return true
end
end
return false
end
modpol.load_modules = function(module_path)
local loaded = 0
local ignored = 0
local ignores = fetch_ignores(module_path)
for file in lfs.dir(module_path) do
if file == "." or file == ".." then
-- ignoring current and parent directory
else
-- only looks for .lua files
if string.sub(file, -4, -1) == ".lua" then
-- doesn't load files in the ignore.txt
if check_list(ignores, file) then
ignored = ignored + 1
else
dofile(module_path .. "/" .. file)
loaded = loaded + 1
end
end
end
end
print(loaded .. " modules loaded (" .. ignored .. " ignored)")
end
else
dofile (modpol.topdir .. "/storage/store-modules-legacy.lua")
end

View File

@ -1,109 +0,0 @@
-- ===================================================================
-- /unix-storage.lua
-- Persistent storage in /data using Serpent Serializer
-- Unix systems only
modpol.datadir = modpol.topdir .. "/data"
modpol.file_ledger = modpol.datadir .. "/ledger.dat"
modpol.file_orgs = modpol.datadir .. "/orgs.dat"
os.execute ("mkdir -p " .. modpol.datadir)
modpol.ocutil.setlogdir (modpol.datadir)
modpol.ocutil.setlogname ("modpol.log")
modpol.serpent = {}
dofile (modpol.topdir .. "/util/serpent/serpent.lua")
-- ===================================================================
local write_file = function(path, data)
local file, err
file, err = io.open(path, "w")
if err then print(err) os.exit(1) end
file:write(data)
file:close()
end
local read_file = function(path)
local file, err
file, err = io.open(path, "r")
if err then return nil end
local data = file:read()
file:close()
return data
end
-- ===================================================================
local store_ledger = function(verbose)
local serialized_ledger = modpol.serpent.dump(modpol.ledger)
write_file(modpol.file_ledger, serialized_ledger)
local count = 0
for _ in pairs(modpol.ledger) do count = count + 1 end
if verbose then modpol.ocutil.log(count .. " ledger entries stored to disk")
end
end
local store_orgs = function(verbose)
local serialized_orgs = modpol.serpent.dump(modpol.orgs)
write_file(modpol.file_orgs, serialized_orgs)
local count = 0
for _ in pairs(modpol.orgs.array) do count = count + 1 end
if verbose then modpol.ocutil.log(count .. " orgs stored to disk")
end
end
modpol.store_data = function(verbose)
store_ledger(verbose)
store_orgs(verbose)
end
-- ===================================================================
local load_ledger = function()
local obj = read_file(modpol.file_ledger)
if obj ~= nil then
local func, err = load(obj)
if err then
modpol.ocutil.log("Error loading ledger data")
os.exit(1)
end
modpol.ledger = func()
local count = 0
for _ in pairs(modpol.ledger) do count = count + 1 end
modpol.ocutil.log(count .. " ledger entries loaded from disk")
else
modpol.ocutil.log("No stored ledger data found")
end
end
local load_orgs = function()
local obj = read_file(modpol.file_orgs)
if obj ~= nil then
local func, err = load(obj)
if err then
modpol.ocutil.log("Error loading org data")
os.exit(1)
end
modpol.orgs = func()
local count = 0
for _ in pairs(modpol.orgs.array) do count = count + 1 end
modpol.ocutil.log(count .. " orgs loaded from disk")
else
modpol.ocutil.log("No stored orgs found")
end
end
modpol.load_storage = function()
load_ledger()
load_orgs()
end

View File

@ -32,3 +32,13 @@ function modpol.util.num_pairs(t)
end end
return i return i
end end
function modpol.util.lazy_table_length(tbl, lazy_val)
local count = 0
for k, v in ipairs(tbl) do
if v ~= lazy_val then
count = count + 1
end
end
return count
end

View File

@ -137,11 +137,15 @@ function modpol.interactions.org_dashboard(user, org_string)
-- prepare children menu -- prepare children menu
local children = {} local children = {}
if org.children then
for k,v in ipairs(org.children) do for k,v in ipairs(org.children) do
local this_child = modpol.orgs.get_org(v) local this_child = modpol.orgs.get_org(v)
if this_child then
table.insert(children, this_child.name) table.insert(children, this_child.name)
end end
end
table.sort(children) table.sort(children)
end
-- prepare modules menu -- prepare modules menu
local modules = {} local modules = {}