Handle Matrix room upgrades. Fixes #277

This commit is contained in:
Tulir Asokan
2019-02-11 22:32:37 +02:00
parent 05dfe8c4a3
commit 165f286bfd
2 changed files with 67 additions and 16 deletions
+8
View File
@@ -301,6 +301,12 @@ class MatrixHandler:
# All pinned events removed, remove pinned event in Telegram.
await portal.handle_matrix_pin(sender, None)
@staticmethod
async def handle_room_upgrade(room_id: MatrixRoomID, new_room_id: MatrixRoomID) -> None:
portal = po.Portal.get_by_mxid(room_id)
if portal:
await portal.handle_matrix_upgrade(new_room_id)
@staticmethod
async def handle_name_change(room_id: MatrixRoomID, user_id: MatrixUserID, displayname: str,
prev_displayname: str, event_id: MatrixEventID) -> None:
@@ -416,6 +422,8 @@ class MatrixHandler:
except KeyError:
old_events = set()
await self.handle_room_pin(room_id, sender, new_events, old_events)
elif evt_type == "m.room.tombstone":
await self.handle_room_upgrade(room_id, evt["content"]["replacement_room"])
elif evt_type == "m.receipt":
await self.handle_read_receipts(room_id, self.parse_read_receipts(content))
elif evt_type == "m.presence":
+59 -16
View File
@@ -284,7 +284,7 @@ class Portal:
del self._dedup_mxid[self._dedup.popleft()]
return None
def get_input_entity(self, user: 'u.User') -> Awaitable[TypeInputPeer]:
def get_input_entity(self, user: 'AbstractUser') -> Awaitable[TypeInputPeer]:
return user.client.get_input_entity(self.peer)
async def get_entity(self, user: 'AbstractUser') -> TypeChat:
@@ -419,20 +419,23 @@ class Portal:
def _get_base_power_levels(self, levels: dict = None, entity: TypeChat = None) -> dict:
levels = levels or {}
power_level_requirement = (0 if self.peer_type == "chat" and not entity.admins_enabled
else 50)
levels["ban"] = 99
levels["invite"] = power_level_requirement if self.peer_type == "chat" else 75
levels["kick"] = 50
levels["invite"] = 50 if entity.default_banned_rights.invite_users else 0
if "events" not in levels:
levels["events"] = {}
levels["events"]["m.room.name"] = power_level_requirement
levels["events"]["m.room.avatar"] = power_level_requirement
levels["events"]["m.room.topic"] = 50 if self.peer_type == "channel" else 99
levels["events"]["m.room.name"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"]["m.room.avatar"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"]["m.room.topic"] = 50 if entity.default_banned_rights.change_info else 0
levels["events"][
"m.room.pinned_events"] = 50 if entity.default_banned_rights.pin_messages else 0
levels["events"]["m.sticker"] = 50 if entity.default_banned_rights.send_stickers else 0
levels["events"]["m.room.power_levels"] = 75
levels["events"]["m.room.history_visibility"] = 75
levels["state_default"] = 50
levels["users_default"] = 0
levels["events_default"] = (50 if self.peer_type == "channel" and not entity.megagroup
levels["events_default"] = (50 if (self.peer_type == "channel" and not entity.megagroup
or entity.default_banned_rights.send_messages)
else 0)
if "users" not in levels:
levels["users"] = {
@@ -1145,6 +1148,36 @@ class Portal:
self.save()
break
async def handle_matrix_upgrade(self, new_room: MatrixRoomID) -> None:
old_room = self.mxid
self.migrate_and_save_matrix(new_room)
await self.main_intent.join_room(new_room)
entity = None # type: TypeInputPeer
user = None # type: AbstractUser
if self.bot and self.has_bot:
user = self.bot
entity = await self.get_input_entity(self.bot)
if not entity:
user_mxids = await self.main_intent.get_room_members(self.mxid)
for user_str in user_mxids:
user_id = MatrixUserID(user_str)
if user_id == self.az.bot_mxid:
continue
user = u.User.get_by_mxid(user_id, create=False)
if user and user.tgid:
entity = self.get_input_entity(user)
if entity:
break
if not entity:
self.log.error(
"Failed to fully migrate to upgraded Matrix room: no Telegram user found.")
return
users, participants = await self._get_users(self.bot, entity)
await self.sync_telegram_users(user, users)
levels = await self.main_intent.get_power_levels(self.mxid)
await self.update_telegram_participants(participants, levels)
self.log.info(f"Upgraded room from {old_room} to {self.mxid}")
def _register_outgoing_actions_for_dedup(self, response: TypeUpdates) -> None:
for update in response.updates:
check_dedup = (isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage))
@@ -1183,7 +1216,7 @@ class Portal:
if not entity:
raise ValueError("Upgrade may have failed: output channel not found.")
self.peer_type = "channel"
self.migrate_and_save(TelegramID(entity.id))
self.migrate_and_save_telegram(TelegramID(entity.id))
await self.update_info(source, entity)
async def set_telegram_username(self, source: 'u.User', username: str) -> None:
@@ -1659,7 +1692,7 @@ class Portal:
await self.delete_telegram_user(TelegramID(action.user_id), sender)
elif isinstance(action, MessageActionChatMigrateTo):
self.peer_type = "channel"
self.migrate_and_save(TelegramID(action.channel_id))
self.migrate_and_save_telegram(TelegramID(action.channel_id))
await sender.intent.send_emote(self.mxid, "upgraded this group to a supergroup.")
elif isinstance(action, MessageActionPinMessage):
await self.receive_telegram_pin_sender(sender)
@@ -1804,19 +1837,29 @@ class Portal:
title=self.title, about=self.about, photo_id=self.photo_id,
config=json.dumps(self.local_config))
def migrate_and_save(self, new_id: TelegramID) -> None:
self.db.delete(self.db_instance)
self.db.commit()
self._db_instance = None
def migrate_and_save_telegram(self, new_id: TelegramID) -> None:
try:
del self.by_tgid[self.tgid_full]
except KeyError:
pass
self.tgid = new_id
self.tg_receiver = new_id
existing = self.by_tgid[self.tgid_full]
if existing:
existing.delete()
self.by_tgid[self.tgid_full] = self
self.db.add(self.db_instance)
self.db.commit()
self.db_instance.tgid = self.tgid
self.db_instance.tg_receiver = self.tg_receiver
self.save()
def migrate_and_save_matrix(self, new_id: MatrixRoomID) -> None:
try:
del self.by_mxid[self.mxid]
except KeyError:
pass
self.mxid = new_id
self.by_mxid[self.mxid] = self
self.save()
def save(self) -> None:
self.db_instance.mxid = self.mxid