vibe coding a lot of this because i dont have a ton of time, replacing a space doesnt work still but i think some v12 things are working so far

This commit is contained in:
William Kray
2025-08-22 13:22:57 -07:00
parent e48f2e3344
commit 63299d33aa
+203 -46
View File
@@ -2155,7 +2155,11 @@ class CommunityBot(Plugin):
@community.subcommand("replaceroom", help="replace a room with a new one") @community.subcommand("replaceroom", help="replace a room with a new one")
@command.argument("room", required=False) @command.argument("room", required=False)
async def replace_room(self, evt: MessageEvent, room: str) -> None: async def replace_room(self, evt: MessageEvent, room: str) -> None:
self.log.info(f"=== REPLACEROOM COMMAND STARTED ===")
self.log.info(f"Command arguments: room='{room}', evt.room_id='{evt.room_id}'")
if not await self.check_parent_room(evt): if not await self.check_parent_room(evt):
self.log.info("Parent room check failed, returning")
return return
await evt.mark_read() await evt.mark_read()
@@ -2170,29 +2174,36 @@ class CommunityBot(Plugin):
if room.startswith("#"): if room.startswith("#"):
room_id = await self.client.resolve_room_alias(room) room_id = await self.client.resolve_room_alias(room)
room_id = room_id["room_id"] room_id = room_id["room_id"]
self.log.info(f"Resolved alias '{room}' to room ID: {room_id}")
else: else:
room_id = room room_id = room
self.log.info(f"Using direct room ID: {room_id}")
# Check bot permissions in the old room # Check bot permissions in the old room
self.log.info(f"=== CHECKING BOT PERMISSIONS ===")
has_perms, error_msg, _ = await self.check_bot_permissions( has_perms, error_msg, _ = await self.check_bot_permissions(
room_id, evt, ["state", "tombstone", "power_levels"] room_id, evt, ["state", "tombstone", "power_levels"]
) )
self.log.info(f"Bot permissions check result: has_perms={has_perms}, error_msg='{error_msg}'")
if not has_perms: if not has_perms:
await evt.respond(f"Cannot replace room: {error_msg}") await evt.respond(f"Cannot replace room: {error_msg}")
self.log.info("Bot permissions check failed, returning")
return return
# Get the room name from the state event # Get the room name from the state event
room_name = None
try: try:
room_name_event = await self.client.get_state_event( room_name_event = await self.client.get_state_event(
room_id, EventType.ROOM_NAME room_id, EventType.ROOM_NAME
) )
room_name = room_name_event.name room_name = room_name_event.name
self.log.info(f"Retrieved room name: '{room_name}'")
except Exception as e: except Exception as e:
self.log.warning(f"Failed to get room name: {e}") self.log.warning(f"Failed to get room name: {e}")
# await evt.respond("Could not find room name in state events") # room_name remains None
pass
# get the room topic from the state event # get the room topic from the state event
room_topic = None
try: try:
room_topic_event = await self.client.get_state_event( room_topic_event = await self.client.get_state_event(
room_id, EventType.ROOM_TOPIC room_id, EventType.ROOM_TOPIC
@@ -2200,24 +2211,83 @@ class CommunityBot(Plugin):
room_topic = room_topic_event.topic room_topic = room_topic_event.topic
except Exception as e: except Exception as e:
self.log.warning(f"Failed to get room topic: {e}") self.log.warning(f"Failed to get room topic: {e}")
pass # room_topic remains None
# Check if the room being replaced is a space # Check if the room being replaced is a space
is_space = False is_space = False
self.log.info(f"=== ABOUT TO START SPACE DETECTION ===")
self.log.info(f"=== SPACE DETECTION DEBUG START ===")
self.log.info(f"Room ID being checked: {room_id}")
self.log.info(f"EventType module: {EventType}")
self.log.info(f"EventType.ROOM_CREATE exists: {hasattr(EventType, 'ROOM_CREATE')}")
if hasattr(EventType, 'ROOM_CREATE'):
self.log.info(f"EventType.ROOM_CREATE value: {getattr(EventType, 'ROOM_CREATE')}")
else:
self.log.warning("EventType.ROOM_CREATE does not exist!")
try: try:
# Get the room creation event to check if it's a space # Get the room creation event to check if it's a space
state_events = await self.client.get_state(room_id) state_events = await self.client.get_state(room_id)
for event in state_events: self.log.info(f"Retrieved {len(state_events)} state events for space detection")
if event.type == EventType.ROOM_CREATE:
is_space = event.content.get("type") == "m.space" # Log all event types for debugging
event_types = [event.type for event in state_events]
self.log.info(f"Event types found: {event_types}")
# Debug EventType.ROOM_CREATE constant
self.log.info(f"EventType.ROOM_CREATE value: {EventType.ROOM_CREATE}")
self.log.info(f"EventType.ROOM_CREATE type: {type(EventType.ROOM_CREATE)}")
# Also try string comparison as fallback
room_create_string = "m.room.create"
self.log.info(f"String comparison value: {room_create_string}")
# Try to find the room creation event using multiple methods
room_create_event = None
for i, event in enumerate(state_events):
self.log.info(f"Event {i}: type={event.type} (type: {type(event.type)})")
# Try multiple comparison methods
if hasattr(EventType, 'ROOM_CREATE') and event.type == EventType.ROOM_CREATE:
self.log.info(f"✓ Matched EventType.ROOM_CREATE")
room_create_event = event
break break
elif str(event.type) == room_create_string:
self.log.info(f"✓ Matched string comparison 'm.room.create'")
room_create_event = event
break
elif event.type == "m.room.create":
self.log.info(f"✓ Matched direct string comparison")
room_create_event = event
break
else:
self.log.info(f"✗ No match for event {i}")
# Now process the room creation event if found
if room_create_event:
space_type = room_create_event.content.get("type")
self.log.info(f"Found ROOM_CREATE event with type: {space_type}")
self.log.info(f"Full ROOM_CREATE content: {room_create_event.content}")
is_space = (space_type == "m.space")
self.log.info(f"Space detection result: {is_space}")
else:
self.log.warning("No ROOM_CREATE event found using any method")
if is_space: if is_space:
self.log.info(f"Room {room_id} is a space - will create new space") self.log.info(f"✓ FINAL RESULT: Room {room_id} IS a space - will create new space")
else:
self.log.info(f"✗ FINAL RESULT: Room {room_id} is NOT a space - will create regular room")
except Exception as e: except Exception as e:
self.log.warning(f"Failed to check if room is a space: {e}") self.log.error(f"❌ ERROR during space detection: {e}")
import traceback
self.log.error(f"Traceback: {traceback.format_exc()}")
# Assume it's not a space if we can't determine # Assume it's not a space if we can't determine
is_space = False is_space = False
self.log.info(f"=== SPACE DETECTION DEBUG END - is_space={is_space} ===")
# Get list of aliases to transfer while removing them from the old room # Get list of aliases to transfer while removing them from the old room
aliases_to_transfer = await self.remove_room_aliases(room_id, evt) aliases_to_transfer = await self.remove_room_aliases(room_id, evt)
@@ -2227,10 +2297,19 @@ class CommunityBot(Plugin):
return return
# Inform user about what type of room is being replaced # Inform user about what type of room is being replaced
if not room_name:
room_name = f"Room {room_id[:8]}..." # Fallback name
self.log.warning(f"Using fallback room name: {room_name}")
self.log.info(f"Final decision - is_space: {is_space}, room_name: '{room_name}'")
self.log.info(f"About to send user message - is_space: {is_space}")
if is_space: if is_space:
await evt.respond(f"Replacing space '{room_name}' with a new space...") await evt.respond(f"Replacing space '{room_name}' with a new space...")
self.log.info(f"✓ Sent 'Replacing space' message to user")
else: else:
await evt.respond(f"Replacing room '{room_name}' with a new room...") await evt.respond(f"Replacing room '{room_name}' with a new room...")
self.log.info(f"✗ Sent 'Replacing room' message to user")
# Validate that the new room alias is available # Validate that the new room alias is available
is_valid, conflicting_aliases = await self.validate_room_aliases([room_name], evt) is_valid, conflicting_aliases = await self.validate_room_aliases([room_name], evt)
@@ -2244,15 +2323,57 @@ class CommunityBot(Plugin):
# and space membership # and space membership
if is_space: if is_space:
# Create a new space instead of a regular room # Create a new space instead of a regular room
new_room_id, new_room_alias = await self.create_space(room_name, evt) # For spaces, we need to pass power_level_override to ensure proper creation
# Get power levels from the old space to use as a template
try:
power_level_override = await self.client.get_state_event(room_id, EventType.ROOM_POWER_LEVELS)
self.log.info(f"Using power levels from old space for new space creation")
# remove the bot's explicit power level
# since creators have unlimited power in modern rooms
if self.is_modern_room_version(self.config["room_version"]):
if power_level_override.users:
power_level_override.users.pop(self.client.mxid, None)
self.log.info(f"Removed bot since they are creator")
except Exception as e:
self.log.warning(f"Could not get power levels from old space, using defaults: {e}")
power_level_override = None
self.log.info(f"Calling create_space with room_name='{room_name}', power_level_override={power_level_override is not None}")
new_room_id, new_room_alias = await self.create_space(room_name, evt, power_level_override)
self.log.info(f"create_space returned: room_id={new_room_id}, alias={new_room_alias}")
else: else:
# Create a regular room # Create a regular room
self.log.info(f"Calling create_room with room_name='{room_name}'")
new_room_id, new_room_alias = await self.create_room(room_name, evt) new_room_id, new_room_alias = await self.create_room(room_name, evt)
self.log.info(f"create_room returned: room_id={new_room_id}, alias={new_room_alias}")
if not new_room_id: if not new_room_id:
await evt.respond("Failed to create new room") await evt.respond("Failed to create new room")
return return
# Ensure the new space is NOT added to the old space as a child room
if is_space:
try:
# Check if the old space has any m.space.parent events pointing to it
# and ensure the new space doesn't get added as a child
old_space_parent_events = []
state_events = await self.client.get_state(room_id)
for event in state_events:
if event.type == EventType.SPACE_PARENT:
old_space_parent_events.append(event.state_key)
if old_space_parent_events:
self.log.info(f"Old space has {len(old_space_parent_events)} parent space references - ensuring new space is not added as child")
await evt.respond(f"Note: Old space has {len(old_space_parent_events)} parent space references - new space will be independent")
# Also check if the old space is a child of the community parent space
# and ensure the new space doesn't automatically inherit that relationship
if room_id == self.config.get("parent_room"):
self.log.info("Old space is the community parent space - new space will be independent")
await evt.respond("Note: Old space is the community parent space - new space will be independent and may need manual configuration")
except Exception as e:
self.log.warning(f"Could not check old space parent references: {e}")
# Check bot permissions in the new room # Check bot permissions in the new room
has_perms, error_msg, _ = await self.check_bot_permissions( has_perms, error_msg, _ = await self.check_bot_permissions(
new_room_id, evt, ["state", "tombstone", "power_levels"] new_room_id, evt, ["state", "tombstone", "power_levels"]
@@ -2263,61 +2384,76 @@ class CommunityBot(Plugin):
) )
return return
# Transfer the aliases to the new room # Transfer the aliases to the new room/space
for alias in aliases_to_transfer: if aliases_to_transfer:
localpart = alias.split(":")[0][1:] # Remove # and get localpart await evt.respond(f"Transferring {len(aliases_to_transfer)} aliases to new {'space' if is_space else 'room'}...")
server = alias.split(":")[1]
try:
await self.client.add_room_alias(new_room_id, localpart)
self.log.info(
f"Successfully transferred alias {alias} to new room {new_room_id}"
)
except Exception as e:
# If transfer failed, try to create a modified alias
modified_alias = f"{localpart}NEW"
try:
await self.client.add_room_alias(new_room_id, modified_alias)
self.log.info(
f"Successfully transferred modified alias {modified_alias} to new room {new_room_id}"
)
except Exception as e2:
self.log.error(
f"Failed to transfer modified alias {modified_alias}: {e2}"
)
# Get the room avatar from the old room for alias in aliases_to_transfer:
localpart = alias.split(":")[0][1:] # Remove # and get localpart
server = alias.split(":")[1]
try:
await self.client.add_room_alias(new_room_id, localpart)
self.log.info(
f"Successfully transferred alias {alias} to new {'space' if is_space else 'room'} {new_room_id}"
)
except Exception as e:
# If transfer failed, try to create a modified alias
modified_alias = f"{localpart}NEW"
try:
await self.client.add_room_alias(new_room_id, modified_alias)
self.log.info(
f"Successfully transferred modified alias {modified_alias} to new {'space' if is_space else 'room'} {new_room_id}"
)
except Exception as e2:
self.log.error(
f"Failed to transfer modified alias {modified_alias}: {e2}"
)
await evt.respond(f"Successfully transferred {len(aliases_to_transfer)} aliases to new {'space' if is_space else 'room'}")
else:
await evt.respond("No aliases to transfer")
# Get the room avatar from the old room/space
try: try:
old_room_avatar = await self.client.get_state_event( old_room_avatar = await self.client.get_state_event(
room_id, EventType.ROOM_AVATAR room_id, EventType.ROOM_AVATAR
) )
if old_room_avatar and old_room_avatar.url: if old_room_avatar and old_room_avatar.url:
# Set the same avatar in the new room # Set the same avatar in the new room/space
await self.client.send_state_event( await self.client.send_state_event(
new_room_id, EventType.ROOM_AVATAR, {"url": old_room_avatar.url} new_room_id, EventType.ROOM_AVATAR, {"url": old_room_avatar.url}
) )
self.log.info( self.log.info(
f"Successfully copied room avatar to new room {new_room_id}" f"Successfully copied {'space' if is_space else 'room'} avatar to new {'space' if is_space else 'room'} {new_room_id}"
) )
await evt.respond(f"Copied avatar to new {'space' if is_space else 'room'}")
except Exception as e: except Exception as e:
self.log.error(f"Failed to copy room avatar to new room: {e}") self.log.error(f"Failed to copy {'space' if is_space else 'room'} avatar to new {'space' if is_space else 'room'}: {e}")
# await evt.respond(f"Failed to copy room avatar to new room: {e}") # await evt.respond(f"Failed to copy {'space' if is_space else 'room'} avatar to new {'space' if is_space else 'room'}: {e}")
# Set the room topic in the new room # Set the room topic in the new room/space
try: if room_topic:
await self.client.send_state_event( try:
new_room_id, EventType.ROOM_TOPIC, {"topic": room_topic} await self.client.send_state_event(
) new_room_id, EventType.ROOM_TOPIC, {"topic": room_topic}
self.log.info(f"Successfully copied room topic to new room {new_room_id}") )
except Exception as e: self.log.info(f"Successfully copied {'space' if is_space else 'room'} topic to new {'space' if is_space else 'room'} {new_room_id}")
self.log.error(f"Failed to copy room topic to new room: {e}") await evt.respond(f"Copied topic to new {'space' if is_space else 'room'}")
# await evt.respond(f"Failed to copy room topic to new room: {e}") except Exception as e:
self.log.error(f"Failed to copy {'space' if is_space else 'room'} topic to new {'space' if is_space else 'room'}: {e}")
# await evt.respond(f"Failed to copy {'space' if is_space else 'room'} topic to new {'space' if is_space else 'room'}: {e}")
else:
await evt.respond("No topic to copy")
# Archive the old room with a pointer to the new room # Archive the old room/space with a pointer to the new room/space
await evt.respond(f"Archiving old {'space' if is_space else 'room'}...")
success = await self.do_archive_room(room_id, evt, new_room_id) success = await self.do_archive_room(room_id, evt, new_room_id)
if not success: if not success:
await evt.respond( await evt.respond(
"Failed to archive old room, but new room has been created" f"Failed to archive old {'space' if is_space else 'room'}, but new {'space' if is_space else 'room'} has been created"
) )
else:
await evt.respond(f"Successfully archived old {'space' if is_space else 'room'}")
# If we're replacing a space, we need to handle child room relationships # If we're replacing a space, we need to handle child room relationships
if is_space: if is_space:
@@ -2331,6 +2467,8 @@ class CommunityBot(Plugin):
if old_child_rooms: if old_child_rooms:
self.log.info(f"Found {len(old_child_rooms)} child rooms in old space") self.log.info(f"Found {len(old_child_rooms)} child rooms in old space")
await evt.respond(f"Migrating {len(old_child_rooms)} child rooms from old space to new space...")
# Update child rooms to point to the new space # Update child rooms to point to the new space
for child_room_id in old_child_rooms: for child_room_id in old_child_rooms:
try: try:
@@ -2366,8 +2504,13 @@ class CommunityBot(Plugin):
await asyncio.sleep(self.config["sleep"]) await asyncio.sleep(self.config["sleep"])
except Exception as e: except Exception as e:
self.log.error(f"Failed to update child room {child_room_id}: {e}") self.log.error(f"Failed to update child room {child_room_id}: {e}")
await evt.respond(f"Successfully migrated {len(old_child_rooms)} child rooms to new space")
else:
await evt.respond("No child rooms found in old space")
except Exception as e: except Exception as e:
self.log.error(f"Failed to handle child room relationships: {e}") self.log.error(f"Failed to handle child room relationships: {e}")
await evt.respond(f"Warning: Failed to handle child room relationships: {e}")
# update instances of the old room id in any config values that use it # update instances of the old room id in any config values that use it
config_keys = [ config_keys = [
@@ -2400,6 +2543,20 @@ class CommunityBot(Plugin):
# Save the updated config # Save the updated config
self.config.save() self.config.save()
# Final success message
if is_space:
await evt.respond(
f"✅ Space replacement completed successfully!\n"
f"New space: {new_room_alias}\n"
f"Old space has been archived with a pointer to the new space."
)
else:
await evt.respond(
f"✅ Room replacement completed successfully!\n"
f"New room: {new_room_alias}\n"
f"Old room has been archived with a pointer to the new room."
)
@community.subcommand( @community.subcommand(
"guests", "guests",
help="generate a list of members in a room who are not members of the parent space", help="generate a list of members in a room who are not members of the parent space",