diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 5581b969..531da722 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -38,6 +38,6 @@ from .client.types.reply_markup import ( ) from .client import ( Client, ChatAction, ParseMode, Emoji, - MessageHandler, CallbackQueryHandler, RawUpdateHandler, - DisconnectHandler, Filters + MessageHandler, DeletedMessagesHandler, CallbackQueryHandler, + RawUpdateHandler, DisconnectHandler, Filters ) diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py index 21bde533..b345de94 100644 --- a/pyrogram/client/__init__.py +++ b/pyrogram/client/__init__.py @@ -20,6 +20,7 @@ from .client import Client from .ext import BaseClient, ChatAction, Emoji, ParseMode from .filters import Filters from .handlers import ( - MessageHandler, CallbackQueryHandler, - RawUpdateHandler, DisconnectHandler + MessageHandler, DeletedMessagesHandler, + CallbackQueryHandler, RawUpdateHandler, + DisconnectHandler ) diff --git a/pyrogram/client/dispatcher/dispatcher.py b/pyrogram/client/dispatcher/dispatcher.py index 51be2ebb..ffff16bd 100644 --- a/pyrogram/client/dispatcher/dispatcher.py +++ b/pyrogram/client/dispatcher/dispatcher.py @@ -25,7 +25,7 @@ from threading import Thread import pyrogram from pyrogram.api import types from ..ext import utils -from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler +from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler log = logging.getLogger(__name__) @@ -41,6 +41,11 @@ class Dispatcher: types.UpdateEditChannelMessage ) + DELETE_MESSAGE_UPDATES = ( + types.UpdateDeleteMessages, + types.UpdateDeleteChannelMessages + ) + MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES def __init__(self, client, workers): @@ -97,6 +102,9 @@ class Dispatcher: or update.edited_message or update.edited_channel_post) + deleted_messages = (update.deleted_channel_posts + or update.deleted_messages) + callback_query = update.callback_query if message and isinstance(handler, MessageHandler): @@ -104,6 +112,11 @@ class Dispatcher: continue args = (self.client, message) + elif deleted_messages and isinstance(handler, DeletedMessagesHandler): + if not handler.check(deleted_messages): + continue + + args = (self.client, deleted_messages) elif callback_query and isinstance(handler, CallbackQueryHandler): if not handler.check(callback_query): continue @@ -161,6 +174,22 @@ class Dispatcher: else None) ) ) + + elif isinstance(update, Dispatcher.DELETE_MESSAGE_UPDATES): + is_channel = hasattr(update, 'channel_id') + + messages = utils.parse_deleted_messages( + update.messages, + (update.channel_id if is_channel else None) + ) + + self.dispatch( + pyrogram.Update( + deleted_messages=(messages if not is_channel else None), + deleted_channel_posts=(messages if is_channel else None) + ) + ) + elif isinstance(update, types.UpdateBotCallbackQuery): self.dispatch( pyrogram.Update( diff --git a/pyrogram/client/ext/utils.py b/pyrogram/client/ext/utils.py index d7a09ee1..26017c90 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/client/ext/utils.py @@ -711,6 +711,22 @@ def parse_messages( return parsed_messages if is_list else parsed_messages[0] +def parse_deleted_messages( + messages: list, + channel_id: int +) -> pyrogram_types.Messages: + parsed_messages = [] + + for message in messages: + m = pyrogram_types.Message( + message_id=message, + chat=(pyrogram_types.Chat(id=channel_id, type="channel") if channel_id is not None else None) + ) + parsed_messages.append(m) + + return pyrogram_types.Messages(len(parsed_messages), parsed_messages) + + def get_peer_id(input_peer) -> int: return ( input_peer.user_id if isinstance(input_peer, types.InputPeerUser) diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py index e92948b6..26aa84c8 100644 --- a/pyrogram/client/filters/filters.py +++ b/pyrogram/client/filters/filters.py @@ -89,13 +89,13 @@ class Filters: venue = build("Venue", lambda _, m: bool(m.venue)) """Filter messages that contain :obj:`Venue ` objects.""" - private = build("Private", lambda _, m: bool(m.chat.type == "private")) + private = build("Private", lambda _, m: bool(m.chat and m.chat.type == "private")) """Filter messages sent in private chats.""" - group = build("Group", lambda _, m: bool(m.chat.type in {"group", "supergroup"})) + group = build("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"})) """Filter messages sent in group or supergroup chats.""" - channel = build("Channel", lambda _, m: bool(m.chat.type == "channel")) + channel = build("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel")) """Filter messages sent in channels.""" new_chat_members = build("NewChatMembers", lambda _, m: bool(m.new_chat_members)) diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/client/handlers/__init__.py index 38a8aeeb..d06b2a76 100644 --- a/pyrogram/client/handlers/__init__.py +++ b/pyrogram/client/handlers/__init__.py @@ -19,4 +19,5 @@ from .callback_query_handler import CallbackQueryHandler from .disconnect_handler import DisconnectHandler from .message_handler import MessageHandler +from .deleted_messages_handler import DeletedMessagesHandler from .raw_update_handler import RawUpdateHandler diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/client/handlers/deleted_messages_handler.py new file mode 100644 index 00000000..2f90d5da --- /dev/null +++ b/pyrogram/client/handlers/deleted_messages_handler.py @@ -0,0 +1,52 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2018 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from .handler import Handler + + +class DeletedMessagesHandler(Handler): + """The Deleted Message handler class. Used to handle deleted messages coming from any chat + (private, group, channel). It is intended to be used with + :meth:`add_handler() ` + + Args: + callback (``callable``): + Pass a function that will be called when a new Message arrives. It takes *(client, message)* + as positional arguments (look at the section below for a detailed description). + + filters (:obj:`Filters `): + Pass one or more filters to allow only a subset of messages to be passed + in your callback function. + + Other parameters: + client (:obj:`Client `): + The Client itself, useful when you want to call other API methods inside the message handler. + + message (:obj:`Message `): + The received message. + """ + + def __init__(self, callback: callable, filters=None): + super().__init__(callback, filters) + + def check(self, messages): + return ( + self.filters(messages.messages[0]) + if self.filters + else True + ) diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/client/methods/decorators/__init__.py index 6ece61ff..f84a922c 100644 --- a/pyrogram/client/methods/decorators/__init__.py +++ b/pyrogram/client/methods/decorators/__init__.py @@ -19,8 +19,9 @@ from .on_callback_query import OnCallbackQuery from .on_disconnect import OnDisconnect from .on_message import OnMessage +from .on_deleted_messages import OnDeletedMessages from .on_raw_update import OnRawUpdate -class Decorators(OnMessage, OnCallbackQuery, OnRawUpdate, OnDisconnect): +class Decorators(OnMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, OnDisconnect): pass diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/client/methods/decorators/on_deleted_messages.py new file mode 100644 index 00000000..4cc2d904 --- /dev/null +++ b/pyrogram/client/methods/decorators/on_deleted_messages.py @@ -0,0 +1,42 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2018 Dan Tès +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import pyrogram +from ...ext import BaseClient + + +class OnDeletedMessages(BaseClient): + def on_deleted_messages(self, filters=None, group: int = 0): + """Use this decorator to automatically register a function for handling + deleted messages. This does the same thing as :meth:`add_handler` using the + DeletedMessagesHandler. + + Args: + filters (:obj:`Filters `): + Pass one or more filters to allow only a subset of messages to be passed + in your function. + + group (``int``, *optional*): + The group identifier, defaults to 0. + """ + + def decorator(func): + self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group) + return func + + return decorator diff --git a/pyrogram/client/types/update.py b/pyrogram/client/types/update.py index edd5d85c..05295285 100644 --- a/pyrogram/client/types/update.py +++ b/pyrogram/client/types/update.py @@ -30,12 +30,18 @@ class Update(Object): edited_message (:obj:`Message `, *optional*): New version of a message that is known to the bot and was edited. + deleted_messages (:obj:`Message `, *optional*): + Deleted messages. + channel_post (:obj:`Message `, *optional*): New incoming channel post of any kind — text, photo, sticker, etc. edited_channel_post (:obj:`Message `, *optional*): New version of a channel post that is known to the bot and was edited. + deleted_channel_posts (:obj:`Message `, *optional*): + Deleted channel posts. + inline_query (:obj:`InlineQuery `, *optional*): New incoming inline query. @@ -60,8 +66,10 @@ class Update(Object): self, message=None, edited_message=None, + deleted_messages=None, channel_post=None, edited_channel_post=None, + deleted_channel_posts=None, inline_query=None, chosen_inline_result=None, callback_query=None, @@ -70,8 +78,10 @@ class Update(Object): ): self.message = message self.edited_message = edited_message + self.deleted_messages = deleted_messages self.channel_post = channel_post self.edited_channel_post = edited_channel_post + self.deleted_channel_posts = deleted_channel_posts self.inline_query = inline_query self.chosen_inline_result = chosen_inline_result self.callback_query = callback_query