better doctor commands
This commit is contained in:
+181
-20
@@ -2627,13 +2627,19 @@ class CommunityBot(Plugin):
|
|||||||
"doctor",
|
"doctor",
|
||||||
help="review bot permissions across the space and all rooms to identify potential issues"
|
help="review bot permissions across the space and all rooms to identify potential issues"
|
||||||
)
|
)
|
||||||
async def doctor_check(self, evt: MessageEvent) -> None:
|
@command.argument("room", required=False)
|
||||||
|
async def doctor_check(self, evt: MessageEvent, room: str = None) -> None:
|
||||||
if not await self.check_parent_room(evt):
|
if not await self.check_parent_room(evt):
|
||||||
return
|
return
|
||||||
if not await self.user_permitted(evt.sender):
|
if not await self.user_permitted(evt.sender):
|
||||||
await evt.reply("You don't have permission to use this command")
|
await evt.reply("You don't have permission to use this command")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# If a room is specified, show detailed report for that room
|
||||||
|
if room:
|
||||||
|
await self._doctor_room_detail(evt, room)
|
||||||
|
return
|
||||||
|
|
||||||
msg = await evt.respond("Running diagnostic check...")
|
msg = await evt.respond("Running diagnostic check...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -2681,11 +2687,12 @@ class CommunityBot(Plugin):
|
|||||||
if bot_level < 100:
|
if bot_level < 100:
|
||||||
report["issues"].append(f"Bot lacks administrative privileges in parent space (level: {bot_level})")
|
report["issues"].append(f"Bot lacks administrative privileges in parent space (level: {bot_level})")
|
||||||
|
|
||||||
if report["space"]["users_higher"]:
|
# Remove verbose warnings from summary - these will be shown in detailed room reports
|
||||||
report["warnings"].append(f"Users with higher power level in parent space: {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_higher']])}")
|
# if report["space"]["users_higher"]:
|
||||||
|
# report["warnings"].append(f"Users with higher power level in parent space: {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_higher']])}")
|
||||||
if report["space"]["users_equal"]:
|
#
|
||||||
report["warnings"].append(f"Users with equal power level in parent space: {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_equal']])}")
|
# if report["space"]["users_equal"]:
|
||||||
|
# report["warnings"].append(f"Users with equal power level in parent space: {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_equal']])}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
report["space"] = {
|
report["space"] = {
|
||||||
@@ -2756,11 +2763,12 @@ class CommunityBot(Plugin):
|
|||||||
if bot_level < 100:
|
if bot_level < 100:
|
||||||
report["issues"].append(f"Bot lacks administrative privileges in room '{room_name}' ({room_id}) - level: {bot_level}")
|
report["issues"].append(f"Bot lacks administrative privileges in room '{room_name}' ({room_id}) - level: {bot_level}")
|
||||||
|
|
||||||
if room_report["users_higher"]:
|
# Remove verbose warnings from summary - these will be shown in detailed room reports
|
||||||
report["warnings"].append(f"Users with higher power level in room '{room_name}': {', '.join([f'{u['user']} ({u['level']})' for u in room_report['users_higher']])}")
|
# if room_report["users_higher"]:
|
||||||
|
# report["warnings"].append(f"Users with higher power level in room '{room_name}': {', '.join([f'{u['user']} ({u['level']})' for u in room_report['users_higher']])}")
|
||||||
if room_report["users_equal"]:
|
#
|
||||||
report["warnings"].append(f"Users with equal power level in room '{room_name}': {', '.join([f'{u['user']} ({u['level']})' for u in room_report['users_equal']])}")
|
# if room_report["users_equal"]:
|
||||||
|
# report["warnings"].append(f"Users with equal power level in room '{room_name}': {', '.join([f'{u['user']} ({u['level']})' for u in room_report['users_equal']])}")
|
||||||
|
|
||||||
report["rooms"][room_id] = room_report
|
report["rooms"][room_id] = room_report
|
||||||
|
|
||||||
@@ -2771,8 +2779,8 @@ class CommunityBot(Plugin):
|
|||||||
}
|
}
|
||||||
report["issues"].append(f"Failed to check room {room_id}: {e}")
|
report["issues"].append(f"Failed to check room {room_id}: {e}")
|
||||||
|
|
||||||
# Generate response
|
# Generate concise summary response
|
||||||
response = "<h3>🔍 Bot Permission Diagnostic Report</h3>\n\n"
|
response = "<h3>🔍 Bot Permission Diagnostic Summary</h3>\n\n"
|
||||||
|
|
||||||
# Space summary - only show if there are issues
|
# Space summary - only show if there are issues
|
||||||
space_has_issues = False
|
space_has_issues = False
|
||||||
@@ -2791,7 +2799,7 @@ class CommunityBot(Plugin):
|
|||||||
response += f"⚠️ <b>Users with equal power:</b> {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_equal']])}\n"
|
response += f"⚠️ <b>Users with equal power:</b> {', '.join([f'{u['user']} ({u['level']})' for u in report['space']['users_equal']])}\n"
|
||||||
response += "\n"
|
response += "\n"
|
||||||
|
|
||||||
# Rooms summary - only show problematic rooms
|
# Rooms summary - only show problematic rooms with room IDs
|
||||||
problematic_rooms = []
|
problematic_rooms = []
|
||||||
admin_rooms = 0
|
admin_rooms = 0
|
||||||
non_admin_rooms = 0
|
non_admin_rooms = 0
|
||||||
@@ -2803,27 +2811,28 @@ class CommunityBot(Plugin):
|
|||||||
error_rooms += 1
|
error_rooms += 1
|
||||||
if room_data["error"] == "Bot not in room":
|
if room_data["error"] == "Bot not in room":
|
||||||
not_in_room_count += 1
|
not_in_room_count += 1
|
||||||
problematic_rooms.append(f"❌ <b>{room_data.get('room_name', room_id)}:</b> Bot not in room")
|
problematic_rooms.append(f"❌ <b>{room_data.get('room_name', room_id)}</b> ({room_id}): Bot not in room")
|
||||||
else:
|
else:
|
||||||
problematic_rooms.append(f"❌ <b>{room_data.get('room_name', room_id)}:</b> Error - {room_data['error']}")
|
problematic_rooms.append(f"❌ <b>{room_data.get('room_name', room_id)}</b> ({room_id}): Error - {room_data['error']}")
|
||||||
else:
|
else:
|
||||||
if room_data["has_admin"]:
|
if room_data["has_admin"]:
|
||||||
admin_rooms += 1
|
admin_rooms += 1
|
||||||
# Only show if there are power level conflicts
|
# Only show if there are power level conflicts
|
||||||
if room_data["users_higher"] or room_data["users_equal"]:
|
if room_data["users_higher"] or room_data["users_equal"]:
|
||||||
room_info = f"✅ <b>{room_data['room_name']}:</b> Admin: Yes (level: {room_data['bot_power_level']})"
|
room_info = f"⚠️ <b>{room_data['room_name']}</b> ({room_id}): Admin: Yes (level: {room_data['bot_power_level']})"
|
||||||
if room_data["users_higher"]:
|
if room_data["users_higher"]:
|
||||||
room_info += f"\n ⚠️ Higher power users: {', '.join([f'{u['user']} ({u['level']})' for u in room_data['users_higher']])}"
|
room_info += f" - Higher power users: {len(room_data['users_higher'])}"
|
||||||
if room_data["users_equal"]:
|
if room_data["users_equal"]:
|
||||||
room_info += f"\n ⚠️ Equal power users: {', '.join([f'{u['user']} ({u['level']})' for u in room_data['users_equal']])}"
|
room_info += f" - Equal power users: {len(room_data['users_equal'])}"
|
||||||
problematic_rooms.append(room_info)
|
problematic_rooms.append(room_info)
|
||||||
else:
|
else:
|
||||||
non_admin_rooms += 1
|
non_admin_rooms += 1
|
||||||
problematic_rooms.append(f"❌ <b>{room_data['room_name']}:</b> Admin: No (level: {room_data['bot_power_level']})")
|
problematic_rooms.append(f"❌ <b>{room_data['room_name']}</b> ({room_id}): Admin: No (level: {room_data['bot_power_level']})")
|
||||||
|
|
||||||
# Only show rooms section if there are problematic rooms
|
# Only show rooms section if there are problematic rooms
|
||||||
if problematic_rooms:
|
if problematic_rooms:
|
||||||
response += f"<h4>🏠 Problematic Rooms ({len(problematic_rooms)} of {len(report['rooms'])} total)</h4>\n"
|
response += f"<h4>🏠 Problematic Rooms ({len(problematic_rooms)} of {len(report['rooms'])} total)</h4>\n"
|
||||||
|
response += "<i>Use <code>!community doctor <room_id></code> for detailed analysis of specific rooms</i>\n\n"
|
||||||
for room_info in problematic_rooms:
|
for room_info in problematic_rooms:
|
||||||
response += f"{room_info}\n"
|
response += f"{room_info}\n"
|
||||||
response += "\n"
|
response += "\n"
|
||||||
@@ -2953,3 +2962,155 @@ class CommunityBot(Plugin):
|
|||||||
chunks.append(current_chunk.strip())
|
chunks.append(current_chunk.strip())
|
||||||
|
|
||||||
return chunks
|
return chunks
|
||||||
|
|
||||||
|
async def _doctor_room_detail(self, evt: MessageEvent, room: str) -> None:
|
||||||
|
"""Generate detailed diagnostic report for a specific room.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
evt: The message event
|
||||||
|
room: Room ID or alias to analyze
|
||||||
|
"""
|
||||||
|
msg = await evt.respond(f"Analyzing room {room}...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Resolve room ID if alias provided
|
||||||
|
room_id = None
|
||||||
|
if room.startswith("#"):
|
||||||
|
try:
|
||||||
|
room_info = await self.client.resolve_room_alias(room)
|
||||||
|
room_id = room_info["room_id"]
|
||||||
|
except Exception as e:
|
||||||
|
await evt.respond(f"Could not resolve room alias {room}: {e}", edits=msg)
|
||||||
|
return
|
||||||
|
elif room.startswith("!"):
|
||||||
|
room_id = room
|
||||||
|
else:
|
||||||
|
await evt.respond(f"Invalid room format. Use room ID (!roomid:server) or alias (#alias:server)", edits=msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if room is in the space
|
||||||
|
space_rooms = await self.get_space_roomlist()
|
||||||
|
if room_id not in space_rooms:
|
||||||
|
await evt.respond(f"Room {room} is not part of the configured space.", edits=msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get room name
|
||||||
|
room_name = room_id
|
||||||
|
try:
|
||||||
|
room_name_event = await self.client.get_state_event(room_id, EventType.ROOM_NAME)
|
||||||
|
room_name = room_name_event.name
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
response = f"<h3>🔍 Detailed Analysis: {room_name}</h3>\n"
|
||||||
|
response += f"<b>Room ID:</b> {room_id}\n\n"
|
||||||
|
|
||||||
|
# Check if bot is in the room
|
||||||
|
try:
|
||||||
|
await self.client.get_state_event(room_id, EventType.ROOM_MEMBER, self.client.mxid)
|
||||||
|
response += "✅ <b>Bot membership:</b> Bot is a member of this room\n\n"
|
||||||
|
except Exception:
|
||||||
|
response += "❌ <b>Bot membership:</b> Bot is not a member of this room\n\n"
|
||||||
|
await evt.respond(response, edits=msg, allow_html=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get power levels
|
||||||
|
try:
|
||||||
|
power_levels = await self.client.get_state_event(room_id, EventType.ROOM_POWER_LEVELS)
|
||||||
|
bot_level = power_levels.get_user_level(self.client.mxid)
|
||||||
|
|
||||||
|
response += f"<h4>📊 Power Level Analysis</h4>\n"
|
||||||
|
response += f"• <b>Bot power level:</b> {bot_level}\n"
|
||||||
|
response += f"• <b>Administrative privileges:</b> {'✅ Yes' if bot_level >= 100 else '❌ No'}\n"
|
||||||
|
response += f"• <b>Default user level:</b> {power_levels.users_default}\n"
|
||||||
|
response += f"• <b>Invite level:</b> {power_levels.invite}\n"
|
||||||
|
response += f"• <b>Kick level:</b> {power_levels.kick}\n"
|
||||||
|
response += f"• <b>Ban level:</b> {power_levels.ban}\n"
|
||||||
|
response += f"• <b>Redact level:</b> {power_levels.redact}\n\n"
|
||||||
|
|
||||||
|
# Check for users with equal or higher power level
|
||||||
|
users_higher = []
|
||||||
|
users_equal = []
|
||||||
|
|
||||||
|
for user, level in power_levels.users.items():
|
||||||
|
if user != self.client.mxid and level >= bot_level:
|
||||||
|
if level == bot_level:
|
||||||
|
users_equal.append({"user": user, "level": level})
|
||||||
|
else:
|
||||||
|
users_higher.append({"user": user, "level": level})
|
||||||
|
|
||||||
|
if users_higher:
|
||||||
|
response += f"<h4>⚠️ Users with Higher Power Level</h4>\n"
|
||||||
|
for user_info in users_higher:
|
||||||
|
response += f"• <b>{user_info['user']}</b> (level: {user_info['level']})\n"
|
||||||
|
response += "\n"
|
||||||
|
|
||||||
|
if users_equal:
|
||||||
|
response += f"<h4>⚠️ Users with Equal Power Level</h4>\n"
|
||||||
|
for user_info in users_equal:
|
||||||
|
response += f"• <b>{user_info['user']}</b> (level: {user_info['level']})\n"
|
||||||
|
response += "\n"
|
||||||
|
|
||||||
|
if not users_higher and not users_equal:
|
||||||
|
response += "✅ <b>No power level conflicts detected</b>\n\n"
|
||||||
|
|
||||||
|
# Check specific permissions
|
||||||
|
response += f"<h4>🔐 Permission Analysis</h4>\n"
|
||||||
|
|
||||||
|
# Get required levels for various actions
|
||||||
|
events_default = power_levels.events_default
|
||||||
|
events = power_levels.events
|
||||||
|
|
||||||
|
permissions = [
|
||||||
|
("Send messages", events.get(str(EventType.ROOM_MESSAGE), events_default)),
|
||||||
|
("Send state events", power_levels.state_default),
|
||||||
|
("Change power levels", events.get(str(EventType.ROOM_POWER_LEVELS), events_default)),
|
||||||
|
("Send tombstone", events.get("m.room.tombstone", events_default)),
|
||||||
|
("Invite users", power_levels.invite),
|
||||||
|
("Kick users", power_levels.kick),
|
||||||
|
("Ban users", power_levels.ban),
|
||||||
|
("Redact messages", power_levels.redact)
|
||||||
|
]
|
||||||
|
|
||||||
|
for perm_name, required_level in permissions:
|
||||||
|
has_perm = bot_level >= required_level
|
||||||
|
status = "✅" if has_perm else "❌"
|
||||||
|
response += f"• {status} <b>{perm_name}:</b> {'Yes' if has_perm else 'No'} (required: {required_level})\n"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
response += f"❌ <b>Error getting power levels:</b> {e}\n\n"
|
||||||
|
|
||||||
|
# Check room state
|
||||||
|
try:
|
||||||
|
response += f"<h4>🏠 Room State</h4>\n"
|
||||||
|
|
||||||
|
# Check join rules
|
||||||
|
try:
|
||||||
|
join_rules = await self.client.get_state_event(room_id, EventType.ROOM_JOIN_RULES)
|
||||||
|
response += f"• <b>Join rule:</b> {join_rules.join_rule}\n"
|
||||||
|
except:
|
||||||
|
response += "• <b>Join rule:</b> Could not determine\n"
|
||||||
|
|
||||||
|
# Check encryption
|
||||||
|
try:
|
||||||
|
encryption = await self.client.get_state_event(room_id, EventType.ROOM_ENCRYPTION)
|
||||||
|
response += f"• <b>Encryption:</b> ✅ Enabled ({encryption.algorithm})\n"
|
||||||
|
except:
|
||||||
|
response += "• <b>Encryption:</b> ❌ Not enabled\n"
|
||||||
|
|
||||||
|
# Check space parent
|
||||||
|
try:
|
||||||
|
space_parent = await self.client.get_state_event(room_id, EventType.SPACE_PARENT)
|
||||||
|
response += f"• <b>Space parent:</b> ✅ {space_parent.state_key}\n"
|
||||||
|
except:
|
||||||
|
response += "• <b>Space parent:</b> ❌ Not set\n"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
response += f"❌ <b>Error checking room state:</b> {e}\n"
|
||||||
|
|
||||||
|
await evt.respond(response, edits=msg, allow_html=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"Failed to analyze room {room}: {e}"
|
||||||
|
self.log.error(error_msg)
|
||||||
|
await evt.respond(error_msg, edits=msg)
|
||||||
|
|||||||
Reference in New Issue
Block a user