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
+251
View File
@@ -0,0 +1,251 @@
"""Database utility functions."""
import asyncio
import time
from typing import List, Dict, Any
from mautrix.types import PaginationDirection
async def get_messages_to_redact(client, room_id: str, mxid: str, logger) -> List:
"""Get messages from a user in a room that should be redacted.
Args:
client: Matrix client instance
room_id: The room ID to search in
mxid: The user ID whose messages to find
logger: Logger instance for error reporting
Returns:
list: List of message events to redact
"""
try:
messages = await client.get_messages(
room_id,
limit=100,
filter_json={"senders": [mxid], "not_types": ["m.room.redaction"]},
direction=PaginationDirection.BACKWARD,
)
# Filter out events with empty content
filtered_events = [
event
for event in messages.events
if event.content and event.content.serialize()
]
logger.debug(
f"DEBUG found {len(filtered_events)} messages to redact in {room_id} (after filtering empty content)"
)
return filtered_events
except Exception as e:
logger.error(f"Error getting messages to redact: {e}")
return []
async def redact_messages(client, database, room_id: str, sleep_time: float, logger) -> Dict[str, int]:
"""Redact messages queued for redaction in a room.
Args:
client: Matrix client instance
database: Database instance
room_id: The room ID to redact messages in
sleep_time: Sleep time between redactions
logger: Logger instance for error reporting
Returns:
dict: Counters for successful and failed redactions
"""
counters = {"success": 0, "failure": 0}
events = await database.fetch(
"SELECT event_id FROM redaction_tasks WHERE room_id = $1", room_id
)
for event in events:
try:
await client.redact(
room_id, event["event_id"], reason="content removed"
)
counters["success"] += 1
await database.execute(
"DELETE FROM redaction_tasks WHERE event_id = $1", event["event_id"]
)
await asyncio.sleep(sleep_time)
except Exception as e:
if "Too Many Requests" in str(e):
logger.warning(
f"Rate limited while redacting messages in {room_id}, will try again in next loop"
)
return counters
logger.error(f"Failed to redact message: {e}")
counters["failure"] += 1
await asyncio.sleep(sleep_time)
return counters
async def upsert_user_timestamp(database, mxid: str, timestamp: int, logger) -> None:
"""Insert or update user activity timestamp.
Args:
database: Database instance
mxid: User Matrix ID
timestamp: Activity timestamp
logger: Logger instance for error reporting
"""
try:
await database.execute(
"""
INSERT INTO user_events (mxid, last_message_timestamp, ignore_inactivity)
VALUES ($1, $2, 0)
ON CONFLICT (mxid) DO UPDATE SET
last_message_timestamp = EXCLUDED.last_message_timestamp
""",
mxid,
timestamp,
)
except Exception as e:
logger.error(f"Failed to upsert user timestamp: {e}")
async def get_inactive_users(database, warn_threshold_days: int, kick_threshold_days: int,
logger) -> Dict[str, List[str]]:
"""Get lists of users who should be warned or kicked for inactivity.
Args:
database: Database instance
warn_threshold_days: Days threshold for warning
kick_threshold_days: Days threshold for kicking
logger: Logger instance for error reporting
Returns:
dict: Contains 'warn' and 'kick' lists of user IDs
"""
try:
current_time = int(time.time())
warn_threshold = current_time - (warn_threshold_days * 24 * 60 * 60)
kick_threshold = current_time - (kick_threshold_days * 24 * 60 * 60)
# Get users to warn
warn_results = await database.fetch(
"""
SELECT mxid FROM user_events
WHERE last_message_timestamp < $1
AND last_message_timestamp > $2
AND ignore_inactivity = 0
""",
warn_threshold,
kick_threshold,
)
# Get users to kick
kick_results = await database.fetch(
"""
SELECT mxid FROM user_events
WHERE last_message_timestamp < $2
AND ignore_inactivity = 0
""",
kick_threshold,
)
return {
"warn": [row["mxid"] for row in warn_results],
"kick": [row["mxid"] for row in kick_results]
}
except Exception as e:
logger.error(f"Failed to get inactive users: {e}")
return {"warn": [], "kick": []}
async def cleanup_stale_verification_states(database, logger) -> None:
"""Clean up stale verification states older than 24 hours.
Args:
database: Database instance
logger: Logger instance for error reporting
"""
try:
await database.execute(
"""
DELETE FROM verification_states
WHERE created_at < NOW() - INTERVAL '24 hours'
"""
)
except Exception as e:
logger.error(f"Failed to cleanup stale verification states: {e}")
async def get_verification_state(database, dm_room_id: str) -> Dict[str, Any]:
"""Get verification state for a DM room.
Args:
database: Database instance
dm_room_id: The DM room ID
Returns:
dict: Verification state data or None if not found
"""
try:
result = await database.fetchrow(
"SELECT * FROM verification_states WHERE dm_room_id = $1",
dm_room_id
)
return dict(result) if result else None
except Exception as e:
return None
async def create_verification_state(database, dm_room_id: str, user_id: str,
target_room_id: str, verification_phrase: str,
attempts_remaining: int, required_power_level: int) -> None:
"""Create a new verification state.
Args:
database: Database instance
dm_room_id: The DM room ID
user_id: The user ID being verified
target_room_id: The target room ID
verification_phrase: The phrase to verify
attempts_remaining: Number of attempts remaining
required_power_level: Required power level for the target room
"""
try:
await database.execute(
"""
INSERT INTO verification_states
(dm_room_id, user_id, target_room_id, verification_phrase, attempts_remaining, required_power_level)
VALUES ($1, $2, $3, $4, $5, $6)
""",
dm_room_id, user_id, target_room_id, verification_phrase,
attempts_remaining, required_power_level
)
except Exception as e:
pass # Verification state creation is not critical
async def update_verification_attempts(database, dm_room_id: str, attempts_remaining: int) -> None:
"""Update verification attempts remaining.
Args:
database: Database instance
dm_room_id: The DM room ID
attempts_remaining: New number of attempts remaining
"""
try:
await database.execute(
"UPDATE verification_states SET attempts_remaining = $1 WHERE dm_room_id = $2",
attempts_remaining, dm_room_id
)
except Exception as e:
pass # Verification state update is not critical
async def delete_verification_state(database, dm_room_id: str) -> None:
"""Delete a verification state.
Args:
database: Database instance
dm_room_id: The DM room ID
"""
try:
await database.execute(
"DELETE FROM verification_states WHERE dm_room_id = $1",
dm_room_id
)
except Exception as e:
pass # Verification state deletion is not critical