From dff3d993e18d8035f09ff9633ff7cc60a0afd5ac Mon Sep 17 00:00:00 2001
From: Dan <14043624+delivrance@users.noreply.github.com>
Date: Wed, 17 Mar 2021 15:11:23 +0100
Subject: [PATCH] Add support for updates about chat member status changes
---
compiler/docs/compiler.py | 4 +
docs/source/api/decorators.rst | 2 +
docs/source/api/handlers.rst | 2 +
pyrogram/dispatcher.py | 15 +++-
pyrogram/handlers/__init__.py | 1 +
.../handlers/chat_member_updated_handler.py | 47 ++++++++++
pyrogram/methods/decorators/__init__.py | 4 +-
.../decorators/on_chat_member_updated.py | 56 ++++++++++++
pyrogram/types/user_and_chats/__init__.py | 4 +-
.../user_and_chats/chat_member_updated.py | 89 +++++++++++++++++++
10 files changed, 219 insertions(+), 5 deletions(-)
create mode 100644 pyrogram/handlers/chat_member_updated_handler.py
create mode 100644 pyrogram/methods/decorators/on_chat_member_updated.py
create mode 100644 pyrogram/types/user_and_chats/chat_member_updated.py
diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py
index 78328459..0a34b206 100644
--- a/compiler/docs/compiler.py
+++ b/compiler/docs/compiler.py
@@ -349,6 +349,7 @@ def pyrogram_api():
ChatAdminWithInviteLinks
ChatEvent
ChatEventFilter
+ ChatMemberUpdated
Dialog
Restriction
""",
@@ -373,6 +374,9 @@ def pyrogram_api():
Poll
PollOption
Dice
+ VoiceChatStarted
+ VoiceChatEnded
+ VoiceChatMembersInvited
""",
bots_keyboard="""
Bots & Keyboards
diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst
index 13bfc9e4..c859063a 100644
--- a/docs/source/api/decorators.rst
+++ b/docs/source/api/decorators.rst
@@ -43,6 +43,7 @@ Index
- :meth:`~Client.on_callback_query`
- :meth:`~Client.on_inline_query`
- :meth:`~Client.on_chosen_inline_result`
+ - :meth:`~Client.on_chat_member_updated`
- :meth:`~Client.on_deleted_messages`
- :meth:`~Client.on_user_status`
- :meth:`~Client.on_poll`
@@ -59,6 +60,7 @@ Details
.. autodecorator:: pyrogram.Client.on_callback_query()
.. autodecorator:: pyrogram.Client.on_inline_query()
.. autodecorator:: pyrogram.Client.on_chosen_inline_result()
+.. autodecorator:: pyrogram.Client.on_chat_member_updated()
.. autodecorator:: pyrogram.Client.on_deleted_messages()
.. autodecorator:: pyrogram.Client.on_user_status()
.. autodecorator:: pyrogram.Client.on_poll()
diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst
index 4e79d139..b06ebbed 100644
--- a/docs/source/api/handlers.rst
+++ b/docs/source/api/handlers.rst
@@ -41,6 +41,7 @@ Index
- :class:`CallbackQueryHandler`
- :class:`InlineQueryHandler`
- :class:`ChosenInlineResultHandler`
+ - :class:`ChatMemberUpdated`
- :class:`UserStatusHandler`
- :class:`PollHandler`
- :class:`DisconnectHandler`
@@ -57,6 +58,7 @@ Details
.. autoclass:: CallbackQueryHandler()
.. autoclass:: InlineQueryHandler()
.. autoclass:: ChosenInlineResultHandler()
+.. autoclass:: ChatMemberUpdated()
.. autoclass:: UserStatusHandler()
.. autoclass:: PollHandler()
.. autoclass:: DisconnectHandler()
diff --git a/pyrogram/dispatcher.py b/pyrogram/dispatcher.py
index f4b818a4..0f46d642 100644
--- a/pyrogram/dispatcher.py
+++ b/pyrogram/dispatcher.py
@@ -26,7 +26,7 @@ from pyrogram import utils
from pyrogram.handlers import (
CallbackQueryHandler, MessageHandler, DeletedMessagesHandler,
UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler,
- ChosenInlineResultHandler
+ ChosenInlineResultHandler, ChatMemberUpdatedHandler
)
from pyrogram.raw.types import (
UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage,
@@ -34,7 +34,7 @@ from pyrogram.raw.types import (
UpdateDeleteMessages, UpdateDeleteChannelMessages,
UpdateBotCallbackQuery, UpdateInlineBotCallbackQuery,
UpdateUserStatus, UpdateBotInlineQuery, UpdateMessagePoll,
- UpdateBotInlineSend
+ UpdateBotInlineSend, UpdateChatParticipant, UpdateChannelParticipant
)
log = logging.getLogger(__name__)
@@ -62,6 +62,11 @@ class Dispatcher:
UpdateInlineBotCallbackQuery
)
+ CHAT_MEMBER_UPDATES = (
+ UpdateChatParticipant,
+ UpdateChannelParticipant
+ )
+
MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES
def __init__(self, client: "pyrogram.Client"):
@@ -98,6 +103,9 @@ class Dispatcher:
async def chosen_inline_result_parser(update, users, chats):
return pyrogram.types.ChosenInlineResult._parse(self.client, update, users), ChosenInlineResultHandler
+ async def chat_member_updated_parser(update, users, chats):
+ return pyrogram.types.ChatMemberUpdated._parse(self.client, update, users, chats), ChatMemberUpdatedHandler
+
self.update_parsers = {
Dispatcher.MESSAGE_UPDATES: message_parser,
Dispatcher.DELETE_MESSAGES_UPDATES: deleted_messages_parser,
@@ -105,7 +113,8 @@ class Dispatcher:
(UpdateUserStatus,): user_status_parser,
(UpdateBotInlineQuery,): inline_query_parser,
(UpdateMessagePoll,): poll_parser,
- (UpdateBotInlineSend,): chosen_inline_result_parser
+ (UpdateBotInlineSend,): chosen_inline_result_parser,
+ Dispatcher.CHAT_MEMBER_UPDATES: chat_member_updated_parser
}
self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple}
diff --git a/pyrogram/handlers/__init__.py b/pyrogram/handlers/__init__.py
index 74e230a4..71ecab72 100644
--- a/pyrogram/handlers/__init__.py
+++ b/pyrogram/handlers/__init__.py
@@ -17,6 +17,7 @@
# along with Pyrogram. If not, see .
from .callback_query_handler import CallbackQueryHandler
+from .chat_member_updated_handler import ChatMemberUpdatedHandler
from .chosen_inline_result_handler import ChosenInlineResultHandler
from .deleted_messages_handler import DeletedMessagesHandler
from .disconnect_handler import DisconnectHandler
diff --git a/pyrogram/handlers/chat_member_updated_handler.py b/pyrogram/handlers/chat_member_updated_handler.py
new file mode 100644
index 00000000..d03eae11
--- /dev/null
+++ b/pyrogram/handlers/chat_member_updated_handler.py
@@ -0,0 +1,47 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2021 Dan
+#
+# 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 ChatMemberUpdatedHandler(Handler):
+ """The ChatMemberUpdated handler class. Used to handle changes in the status of a chat member.
+ It is intended to be used with :meth:`~pyrogram.Client.add_handler`.
+
+ For a nicer way to register this handler, have a look at the
+ :meth:`~pyrogram.Client.on_chat_member_updated` decorator.
+
+ Parameters:
+ callback (``callable``):
+ Pass a function that will be called when a new ChatMemberUpdated event arrives. It takes
+ *(client, chat_member_updated)* 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 updates to be passed in your callback function.
+
+ Other parameters:
+ client (:obj:`~pyrogram.Client`):
+ The Client itself, useful when you want to call other API methods inside the handler.
+
+ chat_member_updated (:obj:`~pyrogram.types.ChatMemberUpdated`):
+ The received chat member update.
+ """
+
+ def __init__(self, callback: callable, filters=None):
+ super().__init__(callback, filters)
diff --git a/pyrogram/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py
index fe96ed13..01ddffce 100644
--- a/pyrogram/methods/decorators/__init__.py
+++ b/pyrogram/methods/decorators/__init__.py
@@ -17,6 +17,7 @@
# along with Pyrogram. If not, see .
from .on_callback_query import OnCallbackQuery
+from .on_chat_member_updated import OnChatMemberUpdated
from .on_chosen_inline_result import OnChosenInlineResult
from .on_deleted_messages import OnDeletedMessages
from .on_disconnect import OnDisconnect
@@ -36,6 +37,7 @@ class Decorators(
OnUserStatus,
OnInlineQuery,
OnPoll,
- OnChosenInlineResult
+ OnChosenInlineResult,
+ OnChatMemberUpdated
):
pass
diff --git a/pyrogram/methods/decorators/on_chat_member_updated.py b/pyrogram/methods/decorators/on_chat_member_updated.py
new file mode 100644
index 00000000..e184bbef
--- /dev/null
+++ b/pyrogram/methods/decorators/on_chat_member_updated.py
@@ -0,0 +1,56 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2021 Dan
+#
+# 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 typing import Callable
+
+import pyrogram
+from pyrogram.filters import Filter
+from pyrogram.scaffold import Scaffold
+
+
+class OnChatMemberUpdated(Scaffold):
+ def on_chat_member_updated(
+ self=None,
+ filters=None,
+ group: int = 0
+ ) -> callable:
+ """Decorator for handling event changes on chat members.
+
+ This does the same thing as :meth:`~pyrogram.Client.add_handler` using the
+ :obj:`~pyrogram.handlers.ChatMemberUpdated`.
+
+ Parameters:
+ filters (:obj:`~pyrogram.filters`, *optional*):
+ Pass one or more filters to allow only a subset of updates to be passed in your function.
+
+ group (``int``, *optional*):
+ The group identifier, defaults to 0.
+ """
+
+ def decorator(func: Callable) -> Callable:
+ if isinstance(self, pyrogram.Client):
+ self.add_handler(pyrogram.handlers.ChatMemberUpdatedHandler(func, filters), group)
+ elif isinstance(self, Filter) or self is None:
+ func.handler = (
+ pyrogram.handlers.ChatMemberUpdatedHandler(func, self),
+ group if filters is None else filters
+ )
+
+ return func
+
+ return decorator
diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py
index 3fc4eeaf..f3022e37 100644
--- a/pyrogram/types/user_and_chats/__init__.py
+++ b/pyrogram/types/user_and_chats/__init__.py
@@ -22,6 +22,7 @@ from .chat_event import ChatEvent
from .chat_event_filter import ChatEventFilter
from .chat_invite_link import ChatInviteLink
from .chat_member import ChatMember
+from .chat_member_updated import ChatMemberUpdated
from .chat_permissions import ChatPermissions
from .chat_photo import ChatPhoto
from .chat_preview import ChatPreview
@@ -49,5 +50,6 @@ __all__ = [
"ChatAdminWithInviteLinks",
"VoiceChatStarted",
"VoiceChatEnded",
- "VoiceChatMembersInvited"
+ "VoiceChatMembersInvited",
+ "ChatMemberUpdated"
]
diff --git a/pyrogram/types/user_and_chats/chat_member_updated.py b/pyrogram/types/user_and_chats/chat_member_updated.py
new file mode 100644
index 00000000..5794069f
--- /dev/null
+++ b/pyrogram/types/user_and_chats/chat_member_updated.py
@@ -0,0 +1,89 @@
+# Pyrogram - Telegram MTProto API Client Library for Python
+# Copyright (C) 2017-2021 Dan
+#
+# 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 typing import Dict, Union
+
+import pyrogram
+from pyrogram import raw
+from pyrogram import types
+from ..object import Object
+from ..update import Update
+
+
+class ChatMemberUpdated(Object, Update):
+ """Represents changes in the status of a chat member.
+
+ Parameters:
+ chat (:obj:`~pyrogram.types.Chat`):
+ Chat the user belongs to.
+
+ from_user (:obj:`~pyrogram.types.User`):
+ Performer of the action, which resulted in the change.
+
+ date (``int``):
+ Date the change was done in Unix time.
+
+ old_chat_member (:obj:`~pyrogram.types.ChatMember`):
+ Previous information about the chat member.
+
+ new_chat_member (:obj:`~pyrogram.types.ChatMember`):
+ New information about the chat member.
+
+ invite_link (:obj:`~pyrogram.types.ChatInviteLink`, *optional*):
+ Chat invite link, which was used by the user to join the chat; for joining by invite link events only.
+ """
+
+ def __init__(
+ self,
+ *,
+ client: "pyrogram.Client" = None,
+ chat: "types.Chat",
+ from_user: "types.User",
+ date: int,
+ old_chat_member: "types.ChatMember",
+ new_chat_member: "types.ChatMember",
+ invite_link: "types.ChatInviteLink" = None,
+ ):
+ super().__init__(client)
+
+ self.chat = chat
+ self.from_user = from_user
+ self.date = date
+ self.old_chat_member = old_chat_member
+ self.new_chat_member = new_chat_member
+ self.invite_link = invite_link
+
+ @staticmethod
+ def _parse(
+ client: "pyrogram.Client",
+ update: Union["raw.types.UpdateChatParticipant", "raw.types.UpdateChannelParticipant"],
+ users: Dict[int, "raw.types.User"],
+ chats: Dict[int, "raw.types.Chat"]
+ ) -> "ChatMemberUpdated":
+ chat_id = getattr(update, "chat_id", None) or getattr(update, "channel_id")
+ invite_link = types.ChatInviteLink._parse(client, update.invite, users) if update.invite else None
+
+ return ChatMemberUpdated(
+ chat=types.Chat._parse_chat(client, chats[chat_id]),
+ from_user=types.User._parse(client, users[update.actor_id]),
+ date=update.date,
+ old_chat_member=types.ChatMember._parse(client, update.prev_participant, users),
+ new_chat_member=types.ChatMember._parse(client, update.new_participant, users),
+ invite_link=invite_link,
+ client=client
+ )