Merge branch 'telethon-1.18'

This commit is contained in:
Tulir Asokan
2020-12-02 11:59:39 +02:00
6 changed files with 63 additions and 43 deletions
+9 -8
View File
@@ -25,8 +25,8 @@ from telethon.network import (ConnectionTcpMTProxyRandomizedIntermediate, Connec
Connection) Connection)
from telethon.tl.patched import MessageService, Message from telethon.tl.patched import MessageService, Message
from telethon.tl.types import ( from telethon.tl.types import (
Channel, Chat, MessageActionChannelMigrateFrom, PeerUser, TypeUpdate, UpdateChatPinnedMessage, Channel, Chat, MessageActionChannelMigrateFrom, PeerUser, TypeUpdate, UpdatePinnedMessages,
UpdateChannelPinnedMessage, UpdateChatParticipantAdmin, UpdateChatParticipants, PeerChat, UpdatePinnedChannelMessages, UpdateChatParticipantAdmin, UpdateChatParticipants, PeerChat,
UpdateChatUserTyping, UpdateDeleteChannelMessages, UpdateNewMessage, UpdateDeleteMessages, UpdateChatUserTyping, UpdateDeleteChannelMessages, UpdateNewMessage, UpdateDeleteMessages,
UpdateEditChannelMessage, UpdateEditMessage, UpdateNewChannelMessage, UpdateReadHistoryOutbox, UpdateEditChannelMessage, UpdateEditMessage, UpdateNewChannelMessage, UpdateReadHistoryOutbox,
UpdateShortChatMessage, UpdateShortMessage, UpdateUserName, UpdateUserPhoto, UpdateUserStatus, UpdateShortChatMessage, UpdateShortMessage, UpdateUserName, UpdateUserPhoto, UpdateUserStatus,
@@ -252,7 +252,7 @@ class AbstractUser(ABC):
await self.update_admin(update) await self.update_admin(update)
elif isinstance(update, UpdateChatParticipants): elif isinstance(update, UpdateChatParticipants):
await self.update_participants(update) await self.update_participants(update)
elif isinstance(update, (UpdateChannelPinnedMessage, UpdateChatPinnedMessage)): elif isinstance(update, (UpdatePinnedMessages, UpdatePinnedChannelMessages)):
await self.update_pinned_messages(update) await self.update_pinned_messages(update)
elif isinstance(update, (UpdateUserName, UpdateUserPhoto)): elif isinstance(update, (UpdateUserName, UpdateUserPhoto)):
await self.update_others_info(update) await self.update_others_info(update)
@@ -263,14 +263,15 @@ class AbstractUser(ABC):
else: else:
self.log.trace("Unhandled update: %s", update) self.log.trace("Unhandled update: %s", update)
async def update_pinned_messages(self, update: Union[UpdateChannelPinnedMessage, async def update_pinned_messages(self, update: Union[UpdatePinnedMessages,
UpdateChatPinnedMessage]) -> None: UpdatePinnedChannelMessages]) -> None:
if isinstance(update, UpdateChatPinnedMessage): if isinstance(update, UpdatePinnedMessages):
portal = po.Portal.get_by_tgid(TelegramID(update.chat_id)) portal = po.Portal.get_by_entity(update.peer, receiver_id=self.tgid)
else: else:
portal = po.Portal.get_by_tgid(TelegramID(update.channel_id)) portal = po.Portal.get_by_tgid(TelegramID(update.channel_id))
if portal and portal.mxid: if portal and portal.mxid:
await portal.receive_telegram_pin_id(update.id, self.tgid) await portal.receive_telegram_pin_ids(update.messages, self.tgid,
remove=not update.pinned)
@staticmethod @staticmethod
async def update_participants(update: UpdateChatParticipants) -> None: async def update_participants(update: UpdateChatParticipants) -> None:
+13 -1
View File
@@ -13,7 +13,7 @@
# #
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
from typing import Optional, Iterator from typing import Optional, Iterator, List
from sqlalchemy import Column, UniqueConstraint, Integer, String, and_, func, desc, select from sqlalchemy import Column, UniqueConstraint, Integer, String, and_, func, desc, select
@@ -51,6 +51,12 @@ class Message(Base):
return cls._select_one_or_none(cls.c.tgid == tgid, cls.c.tg_space == tg_space, return cls._select_one_or_none(cls.c.tgid == tgid, cls.c.tg_space == tg_space,
cls.c.edit_index == edit_index) cls.c.edit_index == edit_index)
@classmethod
def get_first_by_tgids(cls, tgids: List[TelegramID], tg_space: TelegramID
) -> Iterator['Message']:
return cls._select_all(cls.c.tgid.in_(tgids), cls.c.tg_space == tg_space,
cls.c.edit_index == 0)
@classmethod @classmethod
def count_spaces_by_mxid(cls, mxid: EventID, mx_room: RoomID) -> int: def count_spaces_by_mxid(cls, mxid: EventID, mx_room: RoomID) -> int:
rows = cls.db.execute(select([func.count(cls.c.tg_space)]) rows = cls.db.execute(select([func.count(cls.c.tg_space)])
@@ -77,6 +83,12 @@ class Message(Base):
return cls._select_one_or_none(cls.c.mxid == mxid, cls.c.mx_room == mx_room, return cls._select_one_or_none(cls.c.mxid == mxid, cls.c.mx_room == mx_room,
cls.c.tg_space == tg_space) cls.c.tg_space == tg_space)
@classmethod
def get_by_mxids(cls, mxids: List[EventID], mx_room: RoomID, tg_space: TelegramID
) -> Iterator['Message']:
return cls._select_all(cls.c.mxid.in_(mxids), cls.c.mx_room == mx_room,
cls.c.tg_space == tg_space)
@classmethod @classmethod
def update_by_tgid(cls, s_tgid: TelegramID, s_tg_space: TelegramID, s_edit_index: int, def update_by_tgid(cls, s_tgid: TelegramID, s_tg_space: TelegramID, s_edit_index: int,
**values) -> None: **values) -> None:
+6 -7
View File
@@ -281,13 +281,12 @@ class MatrixHandler(BaseMatrixHandler):
portal = po.Portal.get_by_mxid(room_id) portal = po.Portal.get_by_mxid(room_id)
sender = await u.User.get_by_mxid(sender_mxid).ensure_started() sender = await u.User.get_by_mxid(sender_mxid).ensure_started()
if await sender.has_full_access(allow_bot=True) and portal: if await sender.has_full_access(allow_bot=True) and portal:
events = new_events - old_events if not new_events:
if len(events) > 0: await portal.handle_matrix_unpin_all(sender)
# New event pinned, set that as pinned in Telegram. else:
await portal.handle_matrix_pin(sender, EventID(events.pop()), event_id) changes = {event_id: event_id in new_events
elif len(new_events) == 0: for event_id in new_events ^ old_events}
# All pinned events removed, remove pinned event in Telegram. await portal.handle_matrix_pin(sender, changes, event_id)
await portal.handle_matrix_pin(sender, None, event_id)
@staticmethod @staticmethod
async def handle_room_upgrade(room_id: RoomID, sender: UserID, new_room_id: RoomID, async def handle_room_upgrade(room_id: RoomID, sender: UserID, new_room_id: RoomID,
+2
View File
@@ -104,6 +104,7 @@ class BasePortal(MautrixBasePortal, ABC):
dedup: PortalDedup dedup: PortalDedup
send_lock: PortalSendLock send_lock: PortalSendLock
_pin_lock: asyncio.Lock
_db_instance: DBPortal _db_instance: DBPortal
_main_intent: Optional[IntentAPI] _main_intent: Optional[IntentAPI]
@@ -138,6 +139,7 @@ class BasePortal(MautrixBasePortal, ABC):
self.dedup = PortalDedup(self) self.dedup = PortalDedup(self)
self.send_lock = PortalSendLock() self.send_lock = PortalSendLock()
self._pin_lock = asyncio.Lock()
if tgid: if tgid:
self.by_tgid[self.tgid_full] = self self.by_tgid[self.tgid_full] = self
+19 -20
View File
@@ -22,11 +22,10 @@ import magic
from telethon.tl.functions.messages import (EditChatPhotoRequest, EditChatTitleRequest, from telethon.tl.functions.messages import (EditChatPhotoRequest, EditChatTitleRequest,
UpdatePinnedMessageRequest, SetTypingRequest, UpdatePinnedMessageRequest, SetTypingRequest,
EditChatAboutRequest) EditChatAboutRequest, UnpinAllMessagesRequest)
from telethon.tl.functions.channels import EditPhotoRequest, EditTitleRequest, JoinChannelRequest from telethon.tl.functions.channels import EditPhotoRequest, EditTitleRequest, JoinChannelRequest
from telethon.errors import (ChatNotModifiedError, PhotoExtInvalidError, from telethon.errors import (ChatNotModifiedError, PhotoExtInvalidError, MessageIdInvalidError,
PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, RPCError)
RPCError)
from telethon.tl.patched import Message, MessageService from telethon.tl.patched import Message, MessageService
from telethon.tl.types import (DocumentAttributeFilename, DocumentAttributeImageSize, GeoPoint, from telethon.tl.types import (DocumentAttributeFilename, DocumentAttributeImageSize, GeoPoint,
InputChatUploadedPhoto, MessageActionChatEditPhoto, MessageMediaGeo, InputChatUploadedPhoto, MessageActionChatEditPhoto, MessageMediaGeo,
@@ -412,23 +411,23 @@ class PortalMatrix(BasePortal, ABC):
else: else:
self.log.trace("Unhandled Matrix event: %s", content) self.log.trace("Unhandled Matrix event: %s", content)
async def handle_matrix_pin(self, sender: 'u.User', pinned_message: Optional[EventID], async def handle_matrix_unpin_all(self, sender: 'u.User', pin_event_id: EventID) -> None:
await sender.client(UnpinAllMessagesRequest(peer=self.peer))
await self._send_delivery_receipt(pin_event_id)
async def handle_matrix_pin(self, sender: 'u.User', changes: Dict[EventID, bool],
pin_event_id: EventID) -> None: pin_event_id: EventID) -> None:
if self.peer_type != "chat" and self.peer_type != "channel": tg_space = self.tgid if self.peer_type == "channel" else sender.tgid
return ids = {msg.mxid: msg.tgid
try: for msg in DBMessage.get_by_mxids(list(changes.keys()),
if not pinned_message: mx_room=self.mxid, tg_space=tg_space)}
await sender.client(UpdatePinnedMessageRequest(peer=self.peer, id=0)) for event_id, pinned in changes.items():
else: try:
tg_space = self.tgid if self.peer_type == "channel" else sender.tgid await sender.client(UpdatePinnedMessageRequest(peer=self.peer, id=ids[event_id],
message = DBMessage.get_by_mxid(pinned_message, self.mxid, tg_space) unpin=not pinned))
if message is None: except (ChatNotModifiedError, MessageIdInvalidError, KeyError):
self.log.warning(f"Could not find pinned {pinned_message} in {self.mxid}") pass
return await self._send_delivery_receipt(pin_event_id)
await sender.client(UpdatePinnedMessageRequest(peer=self.peer, id=message.tgid))
await self._send_delivery_receipt(pin_event_id)
except ChatNotModifiedError:
pass
async def handle_matrix_deletion(self, deleter: 'u.User', event_id: EventID, async def handle_matrix_deletion(self, deleter: 'u.User', event_id: EventID,
redaction_event_id: EventID) -> None: redaction_event_id: EventID) -> None:
+14 -7
View File
@@ -694,13 +694,20 @@ class PortalTelegram(BasePortal, ABC):
levels.users[puppet.mxid] = 50 levels.users[puppet.mxid] = 50
await self.main_intent.set_power_levels(self.mxid, levels) await self.main_intent.set_power_levels(self.mxid, levels)
async def receive_telegram_pin_id(self, msg_id: TelegramID, receiver: TelegramID) -> None: async def receive_telegram_pin_ids(self, msg_ids: List[TelegramID], receiver: TelegramID,
tg_space = receiver if self.peer_type != "channel" else self.tgid remove: bool) -> None:
message = DBMessage.get_one_by_tgid(msg_id, tg_space) if msg_id != 0 else None async with self._pin_lock:
if message: tg_space = receiver if self.peer_type != "channel" else self.tgid
await self.main_intent.set_pinned_messages(self.mxid, [message.mxid]) previously_pinned = await self.main_intent.get_pinned_messages(self.mxid)
else: currently_pinned_dict = {event_id: True for event_id in previously_pinned}
await self.main_intent.set_pinned_messages(self.mxid, []) for message in DBMessage.get_first_by_tgids(msg_ids, tg_space):
if remove:
currently_pinned_dict.pop(message.mxid, None)
else:
currently_pinned_dict[message.mxid] = True
currently_pinned = list(currently_pinned_dict.keys())
if currently_pinned != previously_pinned:
await self.main_intent.set_pinned_messages(self.mxid, currently_pinned)
async def set_telegram_admins_enabled(self, enabled: bool) -> None: async def set_telegram_admins_enabled(self, enabled: bool) -> None:
level = 50 if enabled else 10 level = 50 if enabled else 10