power level management

apply admin and mod power levels across all rooms managed by the bot

readme updates for readability
This commit is contained in:
William Kray
2024-08-17 14:41:18 -07:00
parent fffc5b3893
commit e4ff8edd0d
4 changed files with 93 additions and 6 deletions
+14 -2
View File
@@ -50,12 +50,24 @@ need to rejoin all rooms themselves or be re-invited.
use the `guests` subcommand to see who is in a room but NOT a member of the parent space (invited guests) e.g.
`!community guests #myroom:alias.here`.
## admin/moderator management
set consistent power levels across all your rooms for your community administrators! the config defines a list of both
admins and moderators (admins have a Power Level of 100, mods have PL50). running the setpower subcommand (i.e.
`!community setpower`) will roll through all rooms in the space (including the space itself) and attempt to true-up user
permissions to match. if you are running legacy rooms not managed by the bot, and the bot does not have permission to
send power-level state events to the room, it will return a list for you to handle manually. users who have a PL greater
than 0 and are not listed as either an admin or moderator will be removed from the permission list, effectively
returning their power to whatever the room default is (usually 0).
## room creation
use the `createroom` subcommand to create a new room according to your preferences, and join it into the parent space.
will attempt to sanitize the room name and assign a room alias automatically. the bot user will be assigned very high
power level (1000) and set an admin power level (100) to plugin administrators. this ensures that the bot is still able
to manage room admins. the bot will also invite other users to these new rooms as configured.
power level (1000) and set an admin power level (100) to plugin administrators, 50 to moderators. this ensures that the
bot is still able to manage room admins. the bot will also invite other users to these new rooms as configured.
rooms created by the bot will have join restriction limited to members of the space.
## get room ID
+6 -2
View File
@@ -19,12 +19,16 @@ track_messages: True
# will update the user's last-active date when they add a reaction to a message
track_reactions: True
# list of users who can use administrative commands, these users will also be made room admins (PL100)
# in new rooms created with the create room commands
# list of users who can use administrative commands. these users will also be made room admins (PL100)
admins:
- '@user1:server.tld'
- '@user2:server.tld'
# list of users who should be considered community moderators. these users will be made room mods (PL50)
moderators:
- '@user3:server.tld'
- '@user4:server.tld'
# list of users who should be invited to new rooms immediately (other bots perhaps)
invitees:
- "@mybot:server.tld"
+72 -1
View File
@@ -8,7 +8,7 @@ import re
from mautrix.client import Client, InternalEventType, MembershipEventDispatcher, SyncStream
from mautrix.types import (Event, StateEvent, EventID, UserID, FileInfo, EventType,
MediaMessageEventContent, ReactionEvent, RedactionEvent, RoomID,
RoomAlias)
RoomAlias, PowerLevelStateEventContent)
from mautrix.errors import MNotFound
from mautrix.util.config import BaseProxyConfig, ConfigUpdateHelper
from maubot import Plugin, MessageEvent
@@ -22,6 +22,7 @@ from .db import upgrade_table
class Config(BaseProxyConfig):
def do_update(self, helper: ConfigUpdateHelper) -> None:
helper.copy("admins")
helper.copy("moderators")
helper.copy("parent_room")
helper.copy("track_messages")
helper.copy("track_reactions")
@@ -421,6 +422,8 @@ class CommunityBot(Plugin):
pl_override = {"users": {self.client.mxid: 1000}}
for u in self.config['admins']:
pl_override["users"][u] = 100
for u in self.config['moderators']:
pl_override["users"][u] = 50
pl_json = json.dumps(pl_override)
mymsg = await evt.respond(f"creating {sanitized_name}, give me a minute...")
@@ -510,6 +513,74 @@ class CommunityBot(Plugin):
except Exception as e:
await evt.respond(f"something went wrong: {e}")
@community.subcommand("setpower", help="set power levels according to the community configuration")
async def set_powerlevels(self, evt: MessageEvent,) -> None:
await evt.mark_read()
if evt.sender in self.config["admins"]:
msg = await evt.respond("truing up power levels, this could take a minute...")
admins = self.config['admins']
moderators = self.config['moderators']
roomlist = await self.get_space_roomlist()
# don't forget to include the space itself
roomlist.append(self.config["parent_room"])
success_list = []
error_list = []
adminpl = 100
modpl = 50
defaultpl = 0
for room in roomlist:
# need to get and evaluate the current state that contains powerlevels first
current_pl = await self.client.get_state_event(room, 'm.room.power_levels')
users = current_pl['users'].serialize()
updated_user_map = dict(users)
try:
roomname = None
roomnamestate = await self.client.get_state_event(room, 'm.room.name')
roomname = roomnamestate['name']
except Exception as e:
self.log.warning(e)
# update our powerlevel map values
for user in admins:
updated_user_map[user] = adminpl
for user in moderators:
updated_user_map[user] = modpl
# revoke values for people no longer in the config
for user in users.keys():
if ( user not in admins and
user not in moderators and
updated_user_map[user] > defaultpl and
user != self.client.mxid ):
del updated_user_map[user]
# and send the new state event back to the room
new_pl = current_pl
new_pl['users'] = updated_user_map
try:
self.log.debug(f"DEBUG sending finalized PL map to room {room}: {updated_user_map}")
await self.client.send_state_event(room, 'm.room.power_levels', new_pl)
success_list.append(roomname or room)
except Exception as e:
self.log.warning(e)
error_list.append(roomname or room)
time.sleep(0.5)
results = "the following rooms were updated:<p><code>{success_list}</code></p>the following errors were \
recorded:<p><code>{error_list}</code></p>".format(success_list=success_list, error_list=error_list)
await evt.respond(results, allow_html=True, edits=msg)
# sync our database after we've made changes to room memberships
await self.do_sync()
else:
await evt.reply("lol you don't have permission to do that")
@classmethod
def get_db_upgrade_table(cls) -> None:
+1 -1
View File
@@ -1,6 +1,6 @@
maubot: 0.1.0
id: org.jobmachine.communitybot
version: 0.1.3
version: 0.1.4
license: MIT
modules:
- community