more refactoring

This commit is contained in:
William Kray
2025-09-09 14:49:45 -07:00
parent 6582112dfb
commit 87e02b7ea6
28 changed files with 4664 additions and 894 deletions
+199
View File
@@ -0,0 +1,199 @@
"""User management utility functions."""
import fnmatch
import re
import time
from typing import List, Dict, Tuple
from mautrix.types import EventType, UserID
from mautrix.errors import MNotFound
async def check_if_banned(client, userid: str, banlists: List[str], logger) -> bool:
"""Check if a user is banned according to banlists.
Args:
client: Matrix client instance
userid: The user ID to check
banlists: List of banlist room IDs or aliases
logger: Logger instance for error reporting
Returns:
bool: True if user is banned
"""
is_banned = False
myrooms = await client.get_joined_rooms()
banlist_roomids = await get_banlist_roomids(client, banlists, logger)
for list_id in banlist_roomids:
if list_id not in myrooms:
logger.error(
f"Bot must be in {list_id} before attempting to use it as a banlist."
)
continue
try:
list_state = await client.get_state(list_id)
user_policies = list(
filter(lambda p: p.type.t == "m.policy.rule.user", list_state)
)
except Exception as e:
logger.error(e)
continue
for rule in user_policies:
try:
if bool(
fnmatch.fnmatch(userid, rule["content"]["entity"])
) and bool(re.search("ban$", rule["content"]["recommendation"])):
return True
except Exception:
# Skip invalid rules
pass
return is_banned
async def get_banlist_roomids(client, banlists: List[str], logger) -> List[str]:
"""Get room IDs for all configured banlists.
Args:
client: Matrix client instance
banlists: List of banlist room IDs or aliases
logger: Logger instance for error reporting
Returns:
list: List of room IDs for banlists
"""
banlist_roomids = []
for banlist in banlists:
if banlist.startswith("#"):
try:
room_info = await client.resolve_room_alias(banlist)
list_id = room_info["room_id"]
banlist_roomids.append(list_id)
except Exception as e:
logger.error(f"Banlist fetching failed for {banlist}: {e}")
continue
else:
list_id = banlist
banlist_roomids.append(list_id)
return banlist_roomids
async def ban_user_from_rooms(client, user: str, roomlist: List[str], reason: str = "banned",
all_rooms: bool = False, redact_on_ban: bool = False,
get_messages_to_redact_func=None, database=None,
sleep_time: float = 0.1, logger=None) -> Dict:
"""Ban a user from a list of rooms.
Args:
client: Matrix client instance
user: User ID to ban
roomlist: List of room IDs to ban from
reason: Reason for the ban
all_rooms: Whether to ban even if user is not in room
redact_on_ban: Whether to queue messages for redaction
get_messages_to_redact_func: Function to get messages to redact
database: Database instance for redaction tasks
sleep_time: Sleep time between operations
logger: Logger instance
Returns:
dict: Ban results with success/error lists
"""
ban_event_map = {"ban_list": {}, "error_list": {}}
ban_event_map["ban_list"][user] = []
for room in roomlist:
try:
roomname = None
try:
roomnamestate = await client.get_state_event(room, "m.room.name")
roomname = roomnamestate["name"]
except:
pass
# ban user even if they're not in the room!
if not all_rooms:
await client.get_state_event(room, EventType.ROOM_MEMBER, user)
await client.ban_user(room, user, reason=reason)
if roomname:
ban_event_map["ban_list"][user].append(roomname)
else:
ban_event_map["ban_list"][user].append(room)
time.sleep(sleep_time)
except MNotFound:
pass
except Exception as e:
if logger:
logger.warning(e)
ban_event_map["error_list"][user] = []
ban_event_map["error_list"][user].append(roomname or room)
if redact_on_ban and get_messages_to_redact_func and database:
messages = await get_messages_to_redact_func(room, user)
# Queue messages for redaction
for msg in messages:
await database.execute(
"INSERT INTO redaction_tasks (event_id, room_id) VALUES ($1, $2)",
msg.event_id,
room,
)
if logger:
logger.info(
f"Queued {len(messages)} messages for redaction in {roomname or room}"
)
return ban_event_map
async def user_permitted(client, user_id: UserID, parent_room: str, min_level: int = 50,
room_id: str = None, logger=None) -> bool:
"""Check if a user has sufficient power level in a room.
Args:
client: Matrix client instance
user_id: The Matrix ID of the user to check
parent_room: The parent room ID
min_level: Minimum required power level (default 50 for moderator)
room_id: The room ID to check permissions in. If None, uses parent room.
logger: Logger instance for error reporting
Returns:
bool: True if user has sufficient power level
"""
try:
target_room = room_id or parent_room
# First check if user has unlimited power (creator in modern room versions)
from .room_utils import user_has_unlimited_power
if await user_has_unlimited_power(client, user_id, target_room):
return True
# Then check power level
power_levels = await client.get_state_event(
target_room, EventType.ROOM_POWER_LEVELS
)
user_level = power_levels.get_user_level(user_id)
return user_level >= min_level
except Exception as e:
if logger:
logger.error(f"Failed to check user power level: {e}")
return False
async def user_has_unlimited_power(client, user_id: str, room_id: str) -> bool:
"""Check if a user has unlimited power in a room (creator in modern room versions).
Args:
client: Matrix client instance
user_id: The user ID to check
room_id: The room ID to check in
Returns:
bool: True if user has unlimited power
"""
from .room_utils import user_has_unlimited_power as room_user_has_unlimited_power
return await room_user_has_unlimited_power(client, user_id, room_id)