Files
Advanced-Community-Bot/community/helpers/common_utils.py
T
Dome edd3eee178 feat: native matrix URI pills for {user}/{room} + major rendering & codebase refactor
This change introduces native `matrix:` URI-based rendering for `{user}` and `{room}` placeholders,
replacing previous plaintext and matrix.to-based links. Users and rooms are now rendered as clickable
pills in supporting clients, with a clean display using display names and room names (no @/# prefixes).

Reporting, moderation, and auto-redaction messages have been updated to use the same rendering logic.
Inspect and event links now also use native `matrix:` URIs for direct in-client navigation.

Internally, URI generation and rendering logic have been unified via central helper functions,
ensuring consistent handling of user IDs, room IDs, aliases, and event IDs.

This commit also includes a broader refactor of the codebase:
- decomposed complex flows (e.g. join handling) into smaller helpers
- moved mutable class-level state to instance-level
- reduced duplicate API calls and redundant logic
- improved overall structure and maintainability

Test coverage has been extended for URI helpers and rendering logic to prevent regressions.

No breaking changes to existing template parameters like `{user_link}` or `{room_link}`.
2026-04-11 20:21:33 +02:00

90 lines
2.5 KiB
Python

"""Common utility functions for bot operations."""
from typing import Optional, Dict, Any
from mautrix.types import EventType, MessageEvent
async def get_room_name(client, room_id: str, logger) -> Optional[str]:
"""Get room name from room ID.
Args:
client: Matrix client instance
room_id: Room ID to get name for
logger: Logger instance for error reporting
Returns:
str: Room name or None if not found/error
"""
try:
room_name_event = await client.get_state_event(room_id, EventType.ROOM_NAME)
return room_name_event.name if room_name_event else None
except Exception as e:
logger.debug(f"Could not get room name for {room_id}: {e}")
return None
async def get_room_power_levels(client, room_id: str, logger) -> Optional[Any]:
"""Get power levels for a room.
Args:
client: Matrix client instance
room_id: Room ID to get power levels for
logger: Logger instance for error reporting
Returns:
PowerLevelStateEventContent or None if error
"""
try:
return await client.get_state_event(room_id, EventType.ROOM_POWER_LEVELS)
except Exception as e:
logger.debug(f"Could not get power levels for {room_id}: {e}")
return None
async def check_room_membership(client, room_id: str, user_id: str, logger) -> bool:
"""Check if a user is a member of a room.
Args:
client: Matrix client instance
room_id: Room ID to check
user_id: User ID to check
logger: Logger instance for error reporting
Returns:
bool: True if user is a member, False otherwise
"""
try:
await client.get_state_event(room_id, EventType.ROOM_MEMBER, user_id)
return True
except Exception:
return False
def format_room_info(room_id: str, room_name: Optional[str] = None) -> str:
"""Format room information for display.
Args:
room_id: Room ID
room_name: Optional room name
Returns:
str: Formatted room info
"""
if room_name:
return f"{room_name} ({room_id})"
return room_id
def safe_get(dictionary: Dict[str, Any], key: str, default: Any = None) -> Any:
"""Safely get a value from a dictionary with a default.
Args:
dictionary: Dictionary to get value from
key: Key to look up
default: Default value if key not found
Returns:
Value from dictionary or default
"""
return dictionary.get(key, default) if dictionary else default