Handle Matrix room upgrades. Fixes #277
This commit is contained in:
@@ -301,6 +301,12 @@ class MatrixHandler:
|
|||||||
# All pinned events removed, remove pinned event in Telegram.
|
# All pinned events removed, remove pinned event in Telegram.
|
||||||
await portal.handle_matrix_pin(sender, None)
|
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
|
@staticmethod
|
||||||
async def handle_name_change(room_id: MatrixRoomID, user_id: MatrixUserID, displayname: str,
|
async def handle_name_change(room_id: MatrixRoomID, user_id: MatrixUserID, displayname: str,
|
||||||
prev_displayname: str, event_id: MatrixEventID) -> None:
|
prev_displayname: str, event_id: MatrixEventID) -> None:
|
||||||
@@ -416,6 +422,8 @@ class MatrixHandler:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
old_events = set()
|
old_events = set()
|
||||||
await self.handle_room_pin(room_id, sender, new_events, old_events)
|
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":
|
elif evt_type == "m.receipt":
|
||||||
await self.handle_read_receipts(room_id, self.parse_read_receipts(content))
|
await self.handle_read_receipts(room_id, self.parse_read_receipts(content))
|
||||||
elif evt_type == "m.presence":
|
elif evt_type == "m.presence":
|
||||||
|
|||||||
+59
-16
@@ -284,7 +284,7 @@ class Portal:
|
|||||||
del self._dedup_mxid[self._dedup.popleft()]
|
del self._dedup_mxid[self._dedup.popleft()]
|
||||||
return None
|
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)
|
return user.client.get_input_entity(self.peer)
|
||||||
|
|
||||||
async def get_entity(self, user: 'AbstractUser') -> TypeChat:
|
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:
|
def _get_base_power_levels(self, levels: dict = None, entity: TypeChat = None) -> dict:
|
||||||
levels = levels or {}
|
levels = levels or {}
|
||||||
power_level_requirement = (0 if self.peer_type == "chat" and not entity.admins_enabled
|
|
||||||
else 50)
|
|
||||||
levels["ban"] = 99
|
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:
|
if "events" not in levels:
|
||||||
levels["events"] = {}
|
levels["events"] = {}
|
||||||
levels["events"]["m.room.name"] = power_level_requirement
|
levels["events"]["m.room.name"] = 50 if entity.default_banned_rights.change_info else 0
|
||||||
levels["events"]["m.room.avatar"] = power_level_requirement
|
levels["events"]["m.room.avatar"] = 50 if entity.default_banned_rights.change_info else 0
|
||||||
levels["events"]["m.room.topic"] = 50 if self.peer_type == "channel" else 99
|
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.power_levels"] = 75
|
||||||
levels["events"]["m.room.history_visibility"] = 75
|
levels["events"]["m.room.history_visibility"] = 75
|
||||||
levels["state_default"] = 50
|
levels["state_default"] = 50
|
||||||
levels["users_default"] = 0
|
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)
|
else 0)
|
||||||
if "users" not in levels:
|
if "users" not in levels:
|
||||||
levels["users"] = {
|
levels["users"] = {
|
||||||
@@ -1145,6 +1148,36 @@ class Portal:
|
|||||||
self.save()
|
self.save()
|
||||||
break
|
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:
|
def _register_outgoing_actions_for_dedup(self, response: TypeUpdates) -> None:
|
||||||
for update in response.updates:
|
for update in response.updates:
|
||||||
check_dedup = (isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage))
|
check_dedup = (isinstance(update, (UpdateNewMessage, UpdateNewChannelMessage))
|
||||||
@@ -1183,7 +1216,7 @@ class Portal:
|
|||||||
if not entity:
|
if not entity:
|
||||||
raise ValueError("Upgrade may have failed: output channel not found.")
|
raise ValueError("Upgrade may have failed: output channel not found.")
|
||||||
self.peer_type = "channel"
|
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)
|
await self.update_info(source, entity)
|
||||||
|
|
||||||
async def set_telegram_username(self, source: 'u.User', username: str) -> None:
|
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)
|
await self.delete_telegram_user(TelegramID(action.user_id), sender)
|
||||||
elif isinstance(action, MessageActionChatMigrateTo):
|
elif isinstance(action, MessageActionChatMigrateTo):
|
||||||
self.peer_type = "channel"
|
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.")
|
await sender.intent.send_emote(self.mxid, "upgraded this group to a supergroup.")
|
||||||
elif isinstance(action, MessageActionPinMessage):
|
elif isinstance(action, MessageActionPinMessage):
|
||||||
await self.receive_telegram_pin_sender(sender)
|
await self.receive_telegram_pin_sender(sender)
|
||||||
@@ -1804,19 +1837,29 @@ class Portal:
|
|||||||
title=self.title, about=self.about, photo_id=self.photo_id,
|
title=self.title, about=self.about, photo_id=self.photo_id,
|
||||||
config=json.dumps(self.local_config))
|
config=json.dumps(self.local_config))
|
||||||
|
|
||||||
def migrate_and_save(self, new_id: TelegramID) -> None:
|
def migrate_and_save_telegram(self, new_id: TelegramID) -> None:
|
||||||
self.db.delete(self.db_instance)
|
|
||||||
self.db.commit()
|
|
||||||
self._db_instance = None
|
|
||||||
try:
|
try:
|
||||||
del self.by_tgid[self.tgid_full]
|
del self.by_tgid[self.tgid_full]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
self.tgid = new_id
|
self.tgid = new_id
|
||||||
self.tg_receiver = 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.by_tgid[self.tgid_full] = self
|
||||||
self.db.add(self.db_instance)
|
self.db_instance.tgid = self.tgid
|
||||||
self.db.commit()
|
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:
|
def save(self) -> None:
|
||||||
self.db_instance.mxid = self.mxid
|
self.db_instance.mxid = self.mxid
|
||||||
|
|||||||
Reference in New Issue
Block a user