diff --git a/.gitignore b/.gitignore index d0defb6..9aed33c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ */data/* -!*/data/placeholder \ No newline at end of file +!*/data/placeholder + +# ignore Mastodon credentials +modpol_mastodon/creds/ \ No newline at end of file diff --git a/README.md b/README.md index 85e46b6..6bede89 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,43 @@ -# Modpol for Minetest +# Modpol ![](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. -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. - **Learn more at [modpol.net](https://modpol.net).** -## Installation in Minetest +## Modpol for Minetest -To use this in Minetest, simply install it in your `mods/` or `worldmods/` folder. Minetest will load `init.lua`. +This implementation is a mod for [Minetest](https://minetest.net), a free/open-source voxel game. To use in Minetest, simply install the full codebase in your `mods/` or `worldmods/` folder. Minetest will load `init.lua`. In the game, open the Modpol dashboard with the command `/mp`. -For testing purposes, players with the `privs` privilege (generally admins) can use the `/mptest` 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. +## Mastodon Govbot -## Standalone Version on the Command Line +Modpol can operate a governance-supporting bot for communities on [Mastodon](https://joinmastodon.org), an open social network. -Modpol can also be used independently of Minetest as a command-line tool. Currently command-line use of modpol requires a Unix-style system, but it is intended to become more fully platform independent. +This version utilizes and requires the installation of [lupa](https://github.com/scoder/lupa), which integrates Lua into Python, and [Mastodon.py](https://pypi.org/project/Mastodon.py/), a Python library for interacting with the Mastodon API. + +*To do: explain how to set up the bot on the server.* + +* Install Python on your system and the two required libraries: + - `pip install lupa` + - `pip install Mastodon.py` +* Set up files `clientcred.secret` and `usercred.secret` in the `modpol_mastodon/creds/` directory, using the account settings in Mastodon + +Once it is configured, to initialize the bot, run from Modpol's base directory: + +``` +python govbot.py +``` + +This in turn calls login-mastodon.py, which initializes Modpol and the bot. + +## Command Line + +Modpol can also be used as a command-line tool. Currently command-line use of modpol requires a Unix-style system, but it is intended to become more fully platform independent. The command-line version is in the `modpol` subdirectory. To run the program on Unix systems in CLI mode, install lua or luajit and execute the following in this directory: @@ -38,7 +56,11 @@ In the interpreter, for a list of global functions and tables, use `modpol.menu( ## Storage -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`. + +By default, data will be stored in a data directory at `modpol_core/data/`. This will contain a log file and serialized program data files. + +For Minetest: If available, Modpol uses Minetest's built-in StorageRef system for Minetest 5.*. ## Documentation diff --git a/govbot.py b/govbot.py new file mode 100644 index 0000000..a7f7168 --- /dev/null +++ b/govbot.py @@ -0,0 +1,113 @@ +# MODPOL GOVBOT +# A Python bridge between Modpol and Mastodon + +## Initialize Modpol ## + +import lupa + +# Create a Lua runtime +lua = lupa.LuaRuntime(unpack_returned_tuples=True) + +# Load your Lua script +script_path = 'login_mastodon.lua' +with open(script_path, 'r') as f: + lua.execute(f.read()) + +print("Loaded Modpol into Govbot") + +# To do: load all override files + +# If your Lua script defines functions, you can call them from Python +#result = lua.globals().your_function_name() # Replace with your actual function name + +#print("Result from Lua:", result) + + +## Initialize Mastodon ## + +from mastodon import Mastodon +# ^ https://mastodonpy.readthedocs.io/en/stable/# +import time +import datetime +# ^ https://github.com/HikaruSama233/mastodon_autoreply_bot_template/blob/main/bot_template.py + +# Variables +## Character maximum for the server +char_max = 500 + +# Connect to Mastodon +govbot = Mastodon( + client_id='modpol_mastodon/creds/clientcred.secret', + access_token = 'modpol_mastodon/creds/usercred.secret') + +print("Signed in to Mastodon") + +# Handle notification events +def handle_event(event): + print("{} Handling notification ".format(datetime.datetime.now()) + + str(event['id'])) + if 'mention' in event['type']: + mention_username = event['account']['username'] + print(str(event['id']) + ": mention from @" + + mention_username) + # Command handling + # perhaps move this to a separate Interfaces file + if "!dashboard" in event['status']['content']: + govbot.status_reply(event['status'], + "[dashboard here]") + print("{} Replied to ".format(datetime.datetime.now()) + + str(event['id'])) + # To do: if DM + else: + govbot.status_reply(event['status'], + "Thanks for mentioning me!") + print("{} Replied to ".format(datetime.datetime.now()) + + str(event['id'])) + ## ADD OTHER IF STATEMENTS HERE + else: + govbot.status_reply(event['status'], + "I'm not sure how to parse that.") + print("{} Posted error message ".format(datetime.datetime.now()) + + str(event['id'])) + +# Check notifications +events_queue = {} +def check_events(): + notifications = govbot.notifications(mentions_only=True) + current_time = datetime.datetime.now() + if len(notifications) > 0: + print("{} Total notifications {}".format(current_time, len(notifications))) + events_queue = notifications + while len(events_queue) > 0: + id = events_queue[0]['id'] + handle_event(events_queue.pop(0)) # removes event from queue + govbot.notifications_dismiss(id) + elif str(current_time.minute) == '0': + print("{} No notifications".format(current_time)) + +# Initialization + +# Delete past posts (while we are testing) +## Get account information +account_info = govbot.account_verify_credentials() +## Extract and print account ID +acc_id = account_info['id'] +## Fetch the bot's posts +old_posts = govbot.account_statuses(id=acc_id) +## Delete +for post in old_posts: + govbot.status_delete(id=post.id) +# Delete past notifications +govbot.notifications_clear() + +print("{} Initialized".format(datetime.datetime.now())) + +first_post = "Commands:" +first_post += "\n!dashboard: View dashboard" +govbot.status_post(first_post[:char_max]) + +while 1: + # Check every 5 seconds + time.sleep(5) + if len(events_queue) == 0: + check_events() diff --git a/login_mastodon.lua b/login_mastodon.lua new file mode 100644 index 0000000..a9fb4cf --- /dev/null +++ b/login_mastodon.lua @@ -0,0 +1,2 @@ +dofile("modpol_core/modpol.lua") +