def _test(self, input): a = copy_power_levels_contents(input) self.assertEqual(a["ban"], 50) self.assertEqual(a["events"]["m.room.name"], 100) # make sure that changing the copy changes the copy and not the orig a["ban"] = 10 a["events"]["m.room.power_levels"] = 20 self.assertEqual(input["ban"], 50) self.assertEqual(input["events"]["m.room.power_levels"], 100)
def clone_existing_room( self, requester: Requester, old_room_id: str, new_room_id: str, new_room_version: RoomVersion, tombstone_event_id: str, ): """Populate a new room based on an old room Args: requester: the user requesting the upgrade old_room_id : the id of the room to be replaced new_room_id: the id to give the new room (should already have been created with _gemerate_room_id()) new_room_version: the new room version to use tombstone_event_id: the ID of the tombstone event in the old room. Returns: Deferred """ user_id = requester.user.to_string() if not self.spam_checker.user_may_create_room(user_id): raise SynapseError(403, "You are not permitted to create rooms") creation_content = { "room_version": new_room_version.identifier, "predecessor": { "room_id": old_room_id, "event_id": tombstone_event_id }, } # Check if old room was non-federatable # Get old room's create event old_room_create_event = yield self.store.get_create_event_for_room( old_room_id) # Check if the create event specified a non-federatable room if not old_room_create_event.content.get("m.federate", True): # If so, mark the new room as non-federatable as well creation_content["m.federate"] = False initial_state = dict() # Replicate relevant room events types_to_copy = ( (EventTypes.JoinRules, ""), (EventTypes.Name, ""), (EventTypes.Topic, ""), (EventTypes.RoomHistoryVisibility, ""), (EventTypes.GuestAccess, ""), (EventTypes.RoomAvatar, ""), (EventTypes.RoomEncryption, ""), (EventTypes.ServerACL, ""), (EventTypes.RelatedGroups, ""), (EventTypes.PowerLevels, ""), ) old_room_state_ids = yield self.store.get_filtered_current_state_ids( old_room_id, StateFilter.from_types(types_to_copy)) # map from event_id to BaseEvent old_room_state_events = yield self.store.get_events( old_room_state_ids.values()) for k, old_event_id in iteritems(old_room_state_ids): old_event = old_room_state_events.get(old_event_id) if old_event: initial_state[k] = old_event.content # deep-copy the power-levels event before we start modifying it # note that if frozen_dicts are enabled, `power_levels` will be a frozen # dict so we can't just copy.deepcopy it. initial_state[(EventTypes.PowerLevels, "")] = power_levels = copy_power_levels_contents( initial_state[(EventTypes.PowerLevels, "")]) # Resolve the minimum power level required to send any state event # We will give the upgrading user this power level temporarily (if necessary) such that # they are able to copy all of the state events over, then revert them back to their # original power level afterwards in _update_upgraded_room_pls # Copy over user power levels now as this will not be possible with >100PL users once # the room has been created # Calculate the minimum power level needed to clone the room event_power_levels = power_levels.get("events", {}) state_default = power_levels.get("state_default", 0) ban = power_levels.get("ban") needed_power_level = max(state_default, ban, max(event_power_levels.values())) # Raise the requester's power level in the new room if necessary current_power_level = power_levels["users"][user_id] if current_power_level < needed_power_level: power_levels["users"][user_id] = needed_power_level yield self._send_events_for_new_room( requester, new_room_id, # we expect to override all the presets with initial_state, so this is # somewhat arbitrary. preset_config=RoomCreationPreset.PRIVATE_CHAT, invite_list=[], initial_state=initial_state, creation_content=creation_content, ) # Transfer membership events old_room_member_state_ids = yield self.store.get_filtered_current_state_ids( old_room_id, StateFilter.from_types([(EventTypes.Member, None)])) # map from event_id to BaseEvent old_room_member_state_events = yield self.store.get_events( old_room_member_state_ids.values()) for k, old_event in iteritems(old_room_member_state_events): # Only transfer ban events if ("membership" in old_event.content and old_event.content["membership"] == "ban"): yield self.room_member_handler.update_membership( requester, UserID.from_string(old_event["state_key"]), new_room_id, "ban", ratelimit=False, content=old_event.content, )
def _update_upgraded_room_pls( self, requester: Requester, old_room_id: str, new_room_id: str, old_room_state: StateMap[str], ): """Send updated power levels in both rooms after an upgrade Args: requester: the user requesting the upgrade old_room_id: the id of the room to be replaced new_room_id: the id of the replacement room old_room_state: the state map for the old room Returns: Deferred """ old_room_pl_event_id = old_room_state.get((EventTypes.PowerLevels, "")) if old_room_pl_event_id is None: logger.warning( "Not supported: upgrading a room with no PL event. Not setting PLs " "in old room.") return old_room_pl_state = yield self.store.get_event(old_room_pl_event_id) # we try to stop regular users from speaking by setting the PL required # to send regular events and invites to 'Moderator' level. That's normally # 50, but if the default PL in a room is 50 or more, then we set the # required PL above that. pl_content = dict(old_room_pl_state.content) users_default = int(pl_content.get("users_default", 0)) restricted_level = max(users_default + 1, 50) updated = False for v in ("invite", "events_default"): current = int(pl_content.get(v, 0)) if current < restricted_level: logger.info( "Setting level for %s in %s to %i (was %i)", v, old_room_id, restricted_level, current, ) pl_content[v] = restricted_level updated = True else: logger.info("Not setting level for %s (already %i)", v, current) if updated: try: yield self.event_creation_handler.create_and_send_nonmember_event( requester, { "type": EventTypes.PowerLevels, "state_key": "", "room_id": old_room_id, "sender": requester.user.to_string(), "content": pl_content, }, ratelimit=False, ) except AuthError as e: logger.warning("Unable to update PLs in old room: %s", e) new_pl_content = copy_power_levels_contents(old_room_pl_state.content) # pre-msc2260 rooms may not have the right setting for aliases. If no other # value is set, set it now. events_default = new_pl_content.get("events_default", 0) new_pl_content.setdefault("events", {}).setdefault(EventTypes.Aliases, events_default) logger.info("Setting correct PLs in new room to %s", new_pl_content) yield self.event_creation_handler.create_and_send_nonmember_event( requester, { "type": EventTypes.PowerLevels, "state_key": "", "room_id": new_room_id, "sender": requester.user.to_string(), "content": new_pl_content, }, ratelimit=False, )