diff --git a/mautrix_telegram/abstract_user.py b/mautrix_telegram/abstract_user.py index 04554a32..4199b5d2 100644 --- a/mautrix_telegram/abstract_user.py +++ b/mautrix_telegram/abstract_user.py @@ -136,7 +136,7 @@ class AbstractUser: async def update_pinned_messages(self, update): portal = po.Portal.get_by_tgid(update.channel_id) if portal and portal.mxid: - await portal.update_telegram_pin(self, update.id) + await portal.receive_telegram_pin_id(update.id) async def update_participants(self, update): portal = po.Portal.get_by_tgid(update.participants.chat_id) diff --git a/mautrix_telegram/matrix.py b/mautrix_telegram/matrix.py index 42c079b8..aca86ec7 100644 --- a/mautrix_telegram/matrix.py +++ b/mautrix_telegram/matrix.py @@ -222,6 +222,18 @@ class MatrixHandler: return await handler(sender, content[content_key]) + async def handle_room_pin(self, room, sender, new_events, old_events): + portal = Portal.get_by_mxid(room) + sender = await User.get_by_mxid(sender).ensure_started() + if sender.has_full_access and portal: + events = new_events - old_events + if len(events) > 0: + # New event pinned, set that as pinned in Telegram. + await portal.handle_matrix_pin(sender, events.pop()) + elif len(new_events) == 0: + # All pinned events removed, remove pinned event in Telegram. + await portal.handle_matrix_pin(sender, None) + def filter_matrix_event(self, event): return (event["sender"] == self.az.bot_mxid or Puppet.get_id_from_mxid(event["sender"]) is not None) @@ -250,3 +262,10 @@ class MatrixHandler: evt["prev_content"]) elif type in ("m.room.name", "m.room.avatar", "m.room.topic"): await self.handle_room_meta(type, evt["room_id"], evt["sender"], evt["content"]) + elif type == "m.room.pinned_events": + new_events = set(evt["content"]["pinned"]) + try: + old_events = set(evt["unsigned"]["prev_content"]["pinned"]) + except KeyError: + old_events = set() + await self.handle_room_pin(evt["room_id"], evt["sender"], new_events, old_events) diff --git a/mautrix_telegram/portal.py b/mautrix_telegram/portal.py index 0c248de0..778dc8ee 100644 --- a/mautrix_telegram/portal.py +++ b/mautrix_telegram/portal.py @@ -66,6 +66,8 @@ class Portal: self._main_intent = None self._room_create_lock = asyncio.Lock() + self._temp_pinned_message_id = None + self._temp_pinned_message_sender = None self._dedup = deque() self._dedup_mxid = {} @@ -637,6 +639,20 @@ class Portal: mxid=event_id)) self.db.commit() + async def handle_matrix_pin(self, sender, pinned_message): + if self.peer_type != "channel": + return + try: + if not pinned_message: + await sender.client(UpdatePinnedMessageRequest(channel=self.peer, id=0)) + else: + message = DBMessage.query.filter(DBMessage.mxid == pinned_message, + DBMessage.tg_space == self.tgid, + DBMessage.mx_room == self.mxid).one_or_none() + await sender.client(UpdatePinnedMessageRequest(channel=self.peer, id=message.tgid)) + except ChatNotModifiedError: + pass + async def handle_matrix_deletion(self, deleter, event_id): space = self.tgid if self.peer_type == "channel" else deleter.tgid message = DBMessage.query.filter(DBMessage.mxid == event_id, @@ -657,7 +673,7 @@ class Portal: edit_messages=moderator, delete_messages=moderator, ban_users=moderator, invite_users=moderator, invite_link=moderator, pin_messages=moderator, - add_admins=admin, manage_call=moderator) + add_admins=admin) await sender.client( EditAdminRequest(channel=await self.get_input_entity(sender), user_id=user_id, admin_rights=rights)) @@ -1036,7 +1052,6 @@ class Portal: or self.is_duplicate_action(update)) if should_ignore: return - # TODO figure out how to see changes to about text / channel username if isinstance(action, MessageActionChatEditTitle): await self.update_title(action.title, save=True) @@ -1054,6 +1069,8 @@ class Portal: self.peer_type = "channel" self.migrate_and_save(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) else: self.log.debug("Unhandled Telegram action in %s: %s", self.title, action) @@ -1068,13 +1085,30 @@ class Portal: levels["users"][puppet.mxid] = 50 await self.main_intent.set_power_levels(self.mxid, levels) - async def update_telegram_pin(self, source, id): - space = self.tgid if self.peer_type == "channel" else source.tgid - message = DBMessage.query.get((id, space)) + async def receive_telegram_pin_sender(self, sender): + self._temp_pinned_message_sender = sender + if self._temp_pinned_message_id: + await self.update_telegram_pin() + + async def update_telegram_pin(self): + intent = (self._temp_pinned_message_sender.intent + if self._temp_pinned_message_sender else self.main_intent) + id = self._temp_pinned_message_id + self._temp_pinned_message_id = None + self._temp_pinned_message_sender = None + + message = DBMessage.query.get((id, self.tgid)) if message: - await self.main_intent.set_pinned_messages(self.mxid, [message.mxid]) + await intent.set_pinned_messages(self.mxid, [message.mxid]) else: - await self.main_intent.set_pinned_messages(self.mxid, []) + await intent.set_pinned_messages(self.mxid, []) + + async def receive_telegram_pin_id(self, id): + if id == 0: + return await self.update_telegram_pin() + self._temp_pinned_message_id = id + if self._temp_pinned_message_sender: + await self.update_telegram_pin() @staticmethod def _get_level_from_participant(participant, _):