Bot API 5.1 (#519)

* version update

* added ChatMemberUpdated class

* added ChatInviteLink class

* 2.x version update

* update types added

* added methods createChatInviteLink,  editChatInviteLink,  revokeChatInviteLink

* Voice Chat types added

* added Message fields: voice_chat_started, voice_chat_ended, voice_chat_participants_invited

* can_manage_voice_chats added

* chat links shortcuts added

* bowling dice support

* reordered ChatMembers params (no changes)

* Added can_manage_chat to the class ChatMember and parameter can_manage_chat to the method promoteChatMember

* kick_chat_member refactored + docs update

* Added the parameter revoke_messages to the method kickChatMember

* updated kick_chat_member shortcut for Chat

* Added the type MessageAutoDeleteTimerChanged and the field message_auto_delete_timer_changed to the class Message

* feat: add methods to register my_chat_member and chat_member handlers

* Updated filters for new event types

Co-authored-by: Alex Root Junior <jroot.junior@gmail.com>
This commit is contained in:
Oleg A 2021-03-14 19:05:17 +03:00 committed by GitHub
parent 75222b8af0
commit 24fb07d3fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 510 additions and 49 deletions

View file

@ -43,5 +43,5 @@ __all__ = (
'utils', 'utils',
) )
__version__ = '2.11.3' __version__ = '2.12'
__api_version__ = '5.0' __api_version__ = '5.1'

View file

@ -189,7 +189,7 @@ class Methods(Helper):
""" """
Helper for Telegram API Methods listed on https://core.telegram.org/bots/api Helper for Telegram API Methods listed on https://core.telegram.org/bots/api
List is updated to Bot API 5.0 List is updated to Bot API 5.1
""" """
mode = HelperMode.lowerCamelCase mode = HelperMode.lowerCamelCase
@ -231,6 +231,9 @@ class Methods(Helper):
SET_CHAT_ADMINISTRATOR_CUSTOM_TITLE = Item() # setChatAdministratorCustomTitle SET_CHAT_ADMINISTRATOR_CUSTOM_TITLE = Item() # setChatAdministratorCustomTitle
SET_CHAT_PERMISSIONS = Item() # setChatPermissions SET_CHAT_PERMISSIONS = Item() # setChatPermissions
EXPORT_CHAT_INVITE_LINK = Item() # exportChatInviteLink EXPORT_CHAT_INVITE_LINK = Item() # exportChatInviteLink
CREATE_CHAT_INVITE_LINK = Item() # createChatInviteLink
EDIT_CHAT_INVITE_LINK = Item() # editChatInviteLink
REVOKE_CHAT_INVITE_LINK = Item() # revokeChatInviteLink
SET_CHAT_PHOTO = Item() # setChatPhoto SET_CHAT_PHOTO = Item() # setChatPhoto
DELETE_CHAT_PHOTO = Item() # deleteChatPhoto DELETE_CHAT_PHOTO = Item() # deleteChatPhoto
SET_CHAT_TITLE = Item() # setChatTitle SET_CHAT_TITLE = Item() # setChatTitle

View file

@ -1550,28 +1550,43 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
result = await self.request(api.Methods.GET_FILE, payload) result = await self.request(api.Methods.GET_FILE, payload)
return types.File(**result) return types.File(**result)
async def kick_chat_member(self, chat_id: typing.Union[base.Integer, base.String], user_id: base.Integer, async def kick_chat_member(self,
until_date: typing.Union[ chat_id: typing.Union[base.Integer, base.String],
base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean: user_id: base.Integer,
until_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None] = None,
revoke_messages: typing.Optional[base.Boolean] = None,
) -> base.Boolean:
""" """
Use this method to kick a user from a group, a supergroup or a channel. Use this method to kick a user from a group, a supergroup or a channel.
In the case of supergroups and channels, the user will not be able to return to the group In the case of supergroups and channels, the user will not be able to return
on their own using invite links, etc., unless unbanned first. to the chat on their own using invite links, etc., unless unbanned first.
The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. The bot must be an administrator in the chat for this to work and must have
the appropriate admin rights.
Note: In regular groups (non-supergroups), this method will only work if the All Members Are Admins setting
is off in the target group.
Otherwise members may only be removed by the group's creator or by the member that added them.
Source: https://core.telegram.org/bots/api#kickchatmember Source: https://core.telegram.org/bots/api#kickchatmember
:param chat_id: Unique identifier for the target group or username of the target supergroup or channel :param chat_id: Unique identifier for the target group or username of the
target supergroup or channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]` :type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param user_id: Unique identifier of the target user :param user_id: Unique identifier of the target user
:type user_id: :obj:`base.Integer` :type user_id: :obj:`base.Integer`
:param until_date: Date when the user will be unbanned, unix time
:type until_date: :obj:`typing.Optional[base.Integer]` :param until_date: Date when the user will be unbanned. If user is banned
for more than 366 days or less than 30 seconds from the current time they
are considered to be banned forever. Applied for supergroups and channels
only.
:type until_date: :obj:`typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None`
:param revoke_messages: Pass True to delete all messages from the chat for
the user that is being removed. If False, the user will be able to see
messages in the group that were sent before the user was removed. Always
True for supergroups and channels.
:type revoke_messages: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success :return: Returns True on success
:rtype: :obj:`base.Boolean` :rtype: :obj:`base.Boolean`
""" """
@ -1675,10 +1690,12 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
chat_id: typing.Union[base.Integer, base.String], chat_id: typing.Union[base.Integer, base.String],
user_id: base.Integer, user_id: base.Integer,
is_anonymous: typing.Optional[base.Boolean] = None, is_anonymous: typing.Optional[base.Boolean] = None,
can_manage_chat: typing.Optional[base.Boolean] = None,
can_change_info: typing.Optional[base.Boolean] = None, can_change_info: typing.Optional[base.Boolean] = None,
can_post_messages: typing.Optional[base.Boolean] = None, can_post_messages: typing.Optional[base.Boolean] = None,
can_edit_messages: typing.Optional[base.Boolean] = None, can_edit_messages: typing.Optional[base.Boolean] = None,
can_delete_messages: typing.Optional[base.Boolean] = None, can_delete_messages: typing.Optional[base.Boolean] = None,
can_manage_voice_chats: typing.Optional[base.Boolean] = None,
can_invite_users: typing.Optional[base.Boolean] = None, can_invite_users: typing.Optional[base.Boolean] = None,
can_restrict_members: typing.Optional[base.Boolean] = None, can_restrict_members: typing.Optional[base.Boolean] = None,
can_pin_messages: typing.Optional[base.Boolean] = None, can_pin_messages: typing.Optional[base.Boolean] = None,
@ -1700,6 +1717,11 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param is_anonymous: Pass True, if the administrator's presence in the chat is hidden :param is_anonymous: Pass True, if the administrator's presence in the chat is hidden
:type is_anonymous: :obj:`typing.Optional[base.Boolean]` :type is_anonymous: :obj:`typing.Optional[base.Boolean]`
:param can_manage_chat: Pass True, if the administrator can access the chat event log, chat statistics,
message statistics in channels, see channel members, see anonymous administrators in supergroups
and ignore slow mode. Implied by any other administrator privilege
:type can_manage_chat: :obj:`typing.Optional[base.Boolean]`
:param can_change_info: Pass True, if the administrator can change chat title, photo and other settings :param can_change_info: Pass True, if the administrator can change chat title, photo and other settings
:type can_change_info: :obj:`typing.Optional[base.Boolean]` :type can_change_info: :obj:`typing.Optional[base.Boolean]`
@ -1712,6 +1734,9 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param can_delete_messages: Pass True, if the administrator can delete messages of other users :param can_delete_messages: Pass True, if the administrator can delete messages of other users
:type can_delete_messages: :obj:`typing.Optional[base.Boolean]` :type can_delete_messages: :obj:`typing.Optional[base.Boolean]`
:param can_manage_voice_chats: Pass True, if the administrator can manage voice chats, supergroups only
:type can_manage_voice_chats: :obj:`typing.Optional[base.Boolean]`
:param can_invite_users: Pass True, if the administrator can invite new users to the chat :param can_invite_users: Pass True, if the administrator can invite new users to the chat
:type can_invite_users: :obj:`typing.Optional[base.Boolean]` :type can_invite_users: :obj:`typing.Optional[base.Boolean]`
@ -1789,6 +1814,100 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
result = await self.request(api.Methods.EXPORT_CHAT_INVITE_LINK, payload) result = await self.request(api.Methods.EXPORT_CHAT_INVITE_LINK, payload)
return result return result
async def create_chat_invite_link(self,
chat_id: typing.Union[base.Integer, base.String],
expire_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None],
member_limit: typing.Optional[base.Integer],
) -> types.ChatInviteLink:
"""
Use this method to create an additional invite link for a chat.
The bot must be an administrator in the chat for this to work and must have
the appropriate admin rights. The link can be revoked using the method
revokeChatInviteLink.
Source: https://core.telegram.org/bots/api#createchatinvitelink
:param chat_id: Unique identifier for the target chat or username of the
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param expire_date: Point in time when the link will expire
:type expire_date: :obj:`typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None]`
:param member_limit: Maximum number of users that can be members of the chat
simultaneously after joining the chat via this invite link; 1-99999
:type member_limit: :obj:`typing.Optional[base.Integer]`
:return: the new invite link as ChatInviteLink object.
:rtype: :obj:`types.ChatInviteLink`
"""
expire_date = prepare_arg(expire_date)
payload = generate_payload(**locals())
result = await self.request(api.Methods.CREATE_CHAT_INVITE_LINK, payload)
return result
async def edit_chat_invite_link(self,
chat_id: typing.Union[base.Integer, base.String],
invite_link: base.String,
expire_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None],
member_limit: typing.Optional[base.Integer],
) -> types.ChatInviteLink:
"""
Use this method to edit a non-primary invite link created by the bot.
The bot must be an administrator in the chat for this to work and must have
the appropriate admin rights.
Source: https://core.telegram.org/bots/api#editchatinvitelink
:param chat_id: Unique identifier for the target chat or username of the
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param invite_link: The invite link to edit
:type invite_link: :obj:`base.String`
:param expire_date: Point in time (Unix timestamp) when the link will expire
:type expire_date: :obj:`typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None]`
:param member_limit: Maximum number of users that can be members of the chat
simultaneously after joining the chat via this invite link; 1-99999
:type member_limit: :obj:`typing.Optional[base.Integer]`
:return: edited invite link as a ChatInviteLink object.
"""
expire_date = prepare_arg(expire_date)
payload = generate_payload(**locals())
result = await self.request(api.Methods.EDIT_CHAT_INVITE_LINK, payload)
return result
async def revoke_chat_invite_link(self,
chat_id: typing.Union[base.Integer, base.String],
invite_link: base.String,
) -> types.ChatInviteLink:
"""
Use this method to revoke an invite link created by the bot.
If the primary link is revoked, a new link is automatically generated.
The bot must be an administrator in the chat for this to work and must have
the appropriate admin rights.
Source: https://core.telegram.org/bots/api#revokechatinvitelink
:param chat_id: Unique identifier for the target chat or username of the
target channel (in the format @channelusername)
:param invite_link: The invite link to revoke
:return: the revoked invite link as ChatInviteLink object
"""
payload = generate_payload(**locals())
result = await self.request(api.Methods.REVOKE_CHAT_INVITE_LINK, payload)
return result
async def set_chat_photo(self, chat_id: typing.Union[base.Integer, base.String], async def set_chat_photo(self, chat_id: typing.Union[base.Integer, base.String],
photo: base.InputFile) -> base.Boolean: photo: base.InputFile) -> base.Boolean:
""" """

View file

@ -160,6 +160,26 @@ class LoggingMiddleware(BaseMiddleware):
self.logger.debug(f"{HANDLED_STR[bool(len(results))]} poll answer [ID:{poll_answer.poll_id}] " self.logger.debug(f"{HANDLED_STR[bool(len(results))]} poll answer [ID:{poll_answer.poll_id}] "
f"from user [ID:{poll_answer.user.id}]") f"from user [ID:{poll_answer.user.id}]")
async def on_pre_process_my_chat_member(self, my_chat_member_update, data):
self.logger.info(f"Received chat member update "
f"for user [ID:{my_chat_member_update.from_user.id}]. "
f"Old state: {my_chat_member_update.old_chat_member.to_python()} "
f"New state: {my_chat_member_update.new_chat_member.to_python()} ")
async def on_post_process_my_chat_member(self, my_chat_member_update, results, data):
self.logger.debug(f"{HANDLED_STR[bool(len(results))]} my_chat_member "
f"for user [ID:{my_chat_member_update.from_user.id}]")
async def on_pre_process_chat_member(self, chat_member_update, data):
self.logger.info(f"Received chat member update "
f"for user [ID:{chat_member_update.from_user.id}]. "
f"Old state: {chat_member_update.old_chat_member.to_python()} "
f"New state: {chat_member_update.new_chat_member.to_python()} ")
async def on_post_process_chat_member(self, chat_member_update, results, data):
self.logger.debug(f"{HANDLED_STR[bool(len(results))]} chat_member "
f"for user [ID:{chat_member_update.from_user.id}]")
class LoggingFilter(logging.Filter): class LoggingFilter(logging.Filter):
""" """

View file

@ -78,6 +78,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
self.pre_checkout_query_handlers = Handler(self, middleware_key='pre_checkout_query') self.pre_checkout_query_handlers = Handler(self, middleware_key='pre_checkout_query')
self.poll_handlers = Handler(self, middleware_key='poll') self.poll_handlers = Handler(self, middleware_key='poll')
self.poll_answer_handlers = Handler(self, middleware_key='poll_answer') self.poll_answer_handlers = Handler(self, middleware_key='poll_answer')
self.my_chat_member_handlers = Handler(self, middleware_key='my_chat_member')
self.chat_member_handlers = Handler(self, middleware_key='chat_member')
self.errors_handlers = Handler(self, once=False, middleware_key='error') self.errors_handlers = Handler(self, once=False, middleware_key='error')
self.middleware = MiddlewareManager(self) self.middleware = MiddlewareManager(self)
@ -163,6 +165,7 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
self.edited_channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers, self.callback_query_handlers,
self.inline_query_handlers, self.inline_query_handlers,
self.chat_member_handlers,
]) ])
filters_factory.bind(IDFilter, event_handlers=[ filters_factory.bind(IDFilter, event_handlers=[
self.message_handlers, self.message_handlers,
@ -171,6 +174,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
self.edited_channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers, self.callback_query_handlers,
self.inline_query_handlers, self.inline_query_handlers,
self.chat_member_handlers,
self.my_chat_member_handlers,
]) ])
filters_factory.bind(IsReplyFilter, event_handlers=[ filters_factory.bind(IsReplyFilter, event_handlers=[
self.message_handlers, self.message_handlers,
@ -196,6 +201,8 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
self.channel_post_handlers, self.channel_post_handlers,
self.edited_channel_post_handlers, self.edited_channel_post_handlers,
self.callback_query_handlers, self.callback_query_handlers,
self.my_chat_member_handlers,
self.chat_member_handlers
]) ])
def __del__(self): def __del__(self):
@ -286,6 +293,14 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
types.PollAnswer.set_current(update.poll_answer) types.PollAnswer.set_current(update.poll_answer)
types.User.set_current(update.poll_answer.user) types.User.set_current(update.poll_answer.user)
return await self.poll_answer_handlers.notify(update.poll_answer) return await self.poll_answer_handlers.notify(update.poll_answer)
if update.my_chat_member:
types.ChatMemberUpdated.set_current(update.my_chat_member)
types.User.set_current(update.my_chat_member.from_user)
return await self.my_chat_member_handlers.notify(update.my_chat_member)
if update.chat_member:
types.ChatMemberUpdated.set_current(update.chat_member)
types.User.set_current(update.chat_member.from_user)
return await self.chat_member_handlers.notify(update.chat_member)
except Exception as e: except Exception as e:
err = await self.errors_handlers.notify(update, e) err = await self.errors_handlers.notify(update, e)
if err: if err:
@ -1005,6 +1020,118 @@ class Dispatcher(DataMixin, ContextInstanceMixin):
return decorator return decorator
def register_my_chat_member_handler(self,
callback: typing.Callable,
*custom_filters,
run_task: typing.Optional[bool] = None,
**kwargs) -> None:
"""
Register handler for my_chat_member
Example:
.. code-block:: python3
dp.register_my_chat_member_handler(some_my_chat_member_handler)
:param callback:
:param custom_filters:
:param run_task: run callback in task (no wait results)
:param kwargs:
"""
filters_set = self.filters_factory.resolve(
self.my_chat_member_handlers,
*custom_filters,
**kwargs,
)
self.my_chat_member_handlers.register(
handler=self._wrap_async_task(callback, run_task),
filters=filters_set,
)
def my_chat_member_handler(self, *custom_filters, run_task=None, **kwargs):
"""
Decorator for my_chat_member handler
Example:
.. code-block:: python3
@dp.my_chat_member_handler()
async def some_handler(my_chat_member: types.ChatMemberUpdated)
:param custom_filters:
:param run_task: run callback in task (no wait results)
:param kwargs:
"""
def decorator(callback):
self.register_my_chat_member_handler(
callback,
*custom_filters,
run_task=run_task,
**kwargs,
)
return callback
return decorator
def register_chat_member_handler(self,
callback: typing.Callable,
*custom_filters,
run_task: typing.Optional[bool] = None,
**kwargs) -> None:
"""
Register handler for chat_member
Example:
.. code-block:: python3
dp.register_chat_member_handler(some_chat_member_handler)
:param callback:
:param custom_filters:
:param run_task: run callback in task (no wait results)
:param kwargs:
"""
filters_set = self.filters_factory.resolve(
self.chat_member_handlers,
*custom_filters,
**kwargs,
)
self.chat_member_handlers.register(
handler=self._wrap_async_task(callback, run_task),
filters=filters_set,
)
def chat_member_handler(self, *custom_filters, run_task=None, **kwargs):
"""
Decorator for chat_member handler
Example:
.. code-block:: python3
@dp.chat_member_handler()
async def some_handler(chat_member: types.ChatMemberUpdated)
:param custom_filters:
:param run_task: run callback in task (no wait results)
:param kwargs:
"""
def decorator(callback):
self.register_chat_member_handler(
callback,
*custom_filters,
run_task=run_task,
**kwargs,
)
return callback
return decorator
def register_errors_handler(self, callback, *custom_filters, exception=None, run_task=None, **kwargs): def register_errors_handler(self, callback, *custom_filters, exception=None, run_task=None, **kwargs):
""" """
Register handler for errors Register handler for errors

View file

@ -10,7 +10,7 @@ from babel.support import LazyProxy
from aiogram import types from aiogram import types
from aiogram.dispatcher.filters.filters import BoundFilter, Filter from aiogram.dispatcher.filters.filters import BoundFilter, Filter
from aiogram.types import CallbackQuery, ChatType, InlineQuery, Message, Poll from aiogram.types import CallbackQuery, ChatType, InlineQuery, Message, Poll, ChatMemberUpdated
ChatIDArgumentType = typing.Union[typing.Iterable[typing.Union[int, str]], str, int] ChatIDArgumentType = typing.Union[typing.Iterable[typing.Union[int, str]], str, int]
@ -604,7 +604,7 @@ class IDFilter(Filter):
return result return result
async def check(self, obj: Union[Message, CallbackQuery, InlineQuery]): async def check(self, obj: Union[Message, CallbackQuery, InlineQuery, ChatMemberUpdated]):
if isinstance(obj, Message): if isinstance(obj, Message):
user_id = None user_id = None
if obj.from_user is not None: if obj.from_user is not None:
@ -619,6 +619,9 @@ class IDFilter(Filter):
elif isinstance(obj, InlineQuery): elif isinstance(obj, InlineQuery):
user_id = obj.from_user.id user_id = obj.from_user.id
chat_id = None chat_id = None
elif isinstance(obj, ChatMemberUpdated):
user_id = obj.from_user.id
chat_id = obj.chat.id
else: else:
return False return False
@ -663,19 +666,21 @@ class AdminFilter(Filter):
return result return result
async def check(self, obj: Union[Message, CallbackQuery, InlineQuery]) -> bool: async def check(self, obj: Union[Message, CallbackQuery, InlineQuery, ChatMemberUpdated]) -> bool:
user_id = obj.from_user.id user_id = obj.from_user.id
if self._check_current: if self._check_current:
if isinstance(obj, Message): if isinstance(obj, Message):
message = obj chat = obj.chat
elif isinstance(obj, CallbackQuery) and obj.message: elif isinstance(obj, CallbackQuery) and obj.message:
message = obj.message chat = obj.message.chat
elif isinstance(obj, ChatMemberUpdated):
chat = obj.chat
else: else:
return False return False
if message.chat.type == ChatType.PRIVATE: # there is no admin in private chats if chat.type == ChatType.PRIVATE: # there is no admin in private chats
return False return False
chat_ids = [message.chat.id] chat_ids = [chat.id]
else: else:
chat_ids = self._chat_ids chat_ids = self._chat_ids
@ -719,11 +724,13 @@ class ChatTypeFilter(BoundFilter):
self.chat_type: typing.Set[str] = set(chat_type) self.chat_type: typing.Set[str] = set(chat_type)
async def check(self, obj: Union[Message, CallbackQuery]): async def check(self, obj: Union[Message, CallbackQuery, ChatMemberUpdated]):
if isinstance(obj, Message): if isinstance(obj, Message):
obj = obj.chat obj = obj.chat
elif isinstance(obj, CallbackQuery): elif isinstance(obj, CallbackQuery):
obj = obj.message.chat obj = obj.message.chat
elif isinstance(obj, ChatMemberUpdated):
obj = obj.chat
else: else:
warnings.warn("ChatTypeFilter doesn't support %s as input", type(obj)) warnings.warn("ChatTypeFilter doesn't support %s as input", type(obj))
return False return False

View file

@ -7,8 +7,10 @@ from .bot_command import BotCommand
from .callback_game import CallbackGame from .callback_game import CallbackGame
from .callback_query import CallbackQuery from .callback_query import CallbackQuery
from .chat import Chat, ChatActions, ChatType from .chat import Chat, ChatActions, ChatType
from .chat_invite_link import ChatInviteLink
from .chat_location import ChatLocation from .chat_location import ChatLocation
from .chat_member import ChatMember, ChatMemberStatus from .chat_member import ChatMember, ChatMemberStatus
from .chat_member_updated import ChatMemberUpdated
from .chat_permissions import ChatPermissions from .chat_permissions import ChatPermissions
from .chat_photo import ChatPhoto from .chat_photo import ChatPhoto
from .chosen_inline_result import ChosenInlineResult from .chosen_inline_result import ChosenInlineResult
@ -40,6 +42,7 @@ from .location import Location
from .login_url import LoginUrl from .login_url import LoginUrl
from .mask_position import MaskPosition from .mask_position import MaskPosition
from .message import ContentType, ContentTypes, Message, ParseMode from .message import ContentType, ContentTypes, Message, ParseMode
from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged
from .message_entity import MessageEntity, MessageEntityType from .message_entity import MessageEntity, MessageEntityType
from .message_id import MessageId from .message_id import MessageId
from .order_info import OrderInfo from .order_info import OrderInfo
@ -67,6 +70,9 @@ from .venue import Venue
from .video import Video from .video import Video
from .video_note import VideoNote from .video_note import VideoNote
from .voice import Voice from .voice import Voice
from .voice_chat_ended import VoiceChatEnded
from .voice_chat_participants_invited import VoiceChatParticipantsInvited
from .voice_chat_started import VoiceChatStarted
from .webhook_info import WebhookInfo from .webhook_info import WebhookInfo
__all__ = ( __all__ = (
@ -79,9 +85,11 @@ __all__ = (
'CallbackQuery', 'CallbackQuery',
'Chat', 'Chat',
'ChatActions', 'ChatActions',
'ChatInviteLink',
'ChatLocation', 'ChatLocation',
'ChatMember', 'ChatMember',
'ChatMemberStatus', 'ChatMemberStatus',
'ChatMemberUpdated',
'ChatPermissions', 'ChatPermissions',
'ChatPhoto', 'ChatPhoto',
'ChatType', 'ChatType',
@ -143,6 +151,7 @@ __all__ = (
'MaskPosition', 'MaskPosition',
'MediaGroup', 'MediaGroup',
'Message', 'Message',
'MessageAutoDeleteTimerChanged',
'MessageEntity', 'MessageEntity',
'MessageEntityType', 'MessageEntityType',
'MessageId', 'MessageId',
@ -180,6 +189,9 @@ __all__ = (
'Video', 'Video',
'VideoNote', 'VideoNote',
'Voice', 'Voice',
'VoiceChatEnded',
'VoiceChatParticipantsInvited',
'VoiceChatStarted',
'WebhookInfo', 'WebhookInfo',
'base', 'base',
'fields', 'fields',

View file

@ -5,6 +5,7 @@ import datetime
import typing import typing
from . import base, fields from . import base, fields
from .chat_invite_link import ChatInviteLink
from .chat_location import ChatLocation from .chat_location import ChatLocation
from .chat_member import ChatMember from .chat_member import ChatMember
from .chat_permissions import ChatPermissions from .chat_permissions import ChatPermissions
@ -185,30 +186,47 @@ class Chat(base.TelegramObject):
""" """
return await self.bot.set_chat_description(self.id, description) return await self.bot.set_chat_description(self.id, description)
async def kick(self, user_id: base.Integer, async def kick(self,
until_date: typing.Union[ user_id: base.Integer,
base.Integer, datetime.datetime, datetime.timedelta, None] = None) -> base.Boolean: until_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None] = None,
revoke_messages: typing.Optional[base.Boolean] = None,
) -> base.Boolean:
""" """
Use this method to kick a user from a group, a supergroup or a channel. Use this method to kick a user from a group, a supergroup or a channel.
In the case of supergroups and channels, the user will not be able to return to the group In the case of supergroups and channels, the user will not be able to return
on their own using invite links, etc., unless unbanned first. to the chat on their own using invite links, etc., unless unbanned first.
The bot must be an administrator in the chat for this to work and must have the appropriate admin rights. The bot must be an administrator in the chat for this to work and must have
the appropriate admin rights.
Note: In regular groups (non-supergroups), this method will only work if the All Members Are Admins setting
is off in the target group.
Otherwise members may only be removed by the group's creator or by the member that added them.
Source: https://core.telegram.org/bots/api#kickchatmember Source: https://core.telegram.org/bots/api#kickchatmember
:param user_id: Unique identifier of the target user :param user_id: Unique identifier of the target user
:type user_id: :obj:`base.Integer` :type user_id: :obj:`base.Integer`
:param until_date: Date when the user will be unbanned, unix time.
:type until_date: :obj:`typing.Optional[base.Integer]` :param until_date: Date when the user will be unbanned. If user is banned
:return: Returns True on success. for more than 366 days or less than 30 seconds from the current time they
are considered to be banned forever. Applied for supergroups and channels
only.
:type until_date: :obj:`typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None`
:param revoke_messages: Pass True to delete all messages from the chat for
the user that is being removed. If False, the user will be able to see
messages in the group that were sent before the user was removed. Always
True for supergroups and channels.
:type revoke_messages: :obj:`typing.Optional[base.Boolean]`
:return: Returns True on success
:rtype: :obj:`base.Boolean` :rtype: :obj:`base.Boolean`
""" """
return await self.bot.kick_chat_member(self.id, user_id=user_id, until_date=until_date) return await self.bot.kick_chat_member(
chat_id=self.id,
user_id=user_id,
until_date=until_date,
revoke_messages=revoke_messages,
)
async def unban(self, async def unban(self,
user_id: base.Integer, user_id: base.Integer,
@ -554,6 +572,41 @@ class Chat(base.TelegramObject):
return self.invite_link return self.invite_link
async def create_invite_link(self,
expire_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None],
member_limit: typing.Optional[base.Integer],
) -> ChatInviteLink:
""" Shortcut for createChatInviteLink method. """
return await self.bot.create_chat_invite_link(
chat_id=self.id,
expire_date=expire_date,
member_limit=member_limit,
)
async def edit_invite_link(self,
invite_link: base.String,
expire_date: typing.Union[base.Integer, datetime.datetime,
datetime.timedelta, None],
member_limit: typing.Optional[base.Integer],
) -> ChatInviteLink:
""" Shortcut for editChatInviteLink method. """
return await self.bot.edit_chat_invite_link(
chat_id=self.id,
invite_link=invite_link,
expire_date=expire_date,
member_limit=member_limit,
)
async def revoke_invite_link(self,
invite_link: base.String,
) -> ChatInviteLink:
""" Shortcut for revokeChatInviteLink method. """
return await self.bot.revoke_chat_invite_link(
chat_id=self.id,
invite_link=invite_link,
)
def __int__(self): def __int__(self):
return self.id return self.id

View file

@ -0,0 +1,20 @@
from datetime import datetime
from . import base
from . import fields
from .user import User
class ChatInviteLink(base.TelegramObject):
"""
Represents an invite link for a chat.
https://core.telegram.org/bots/api#chatinvitelink
"""
invite_link: base.String = fields.Field()
creator: User = fields.Field(base=User)
is_primary: base.Boolean = fields.Field()
is_revoked: base.Boolean = fields.Field()
expire_date: datetime = fields.DateTimeField()
member_limit: base.Integer = fields.Field()

View file

@ -16,22 +16,24 @@ class ChatMember(base.TelegramObject):
status: base.String = fields.Field() status: base.String = fields.Field()
custom_title: base.String = fields.Field() custom_title: base.String = fields.Field()
is_anonymous: base.Boolean = fields.Field() is_anonymous: base.Boolean = fields.Field()
until_date: datetime.datetime = fields.DateTimeField()
can_be_edited: base.Boolean = fields.Field() can_be_edited: base.Boolean = fields.Field()
can_change_info: base.Boolean = fields.Field() can_manage_chat: base.Boolean = fields.Field()
can_post_messages: base.Boolean = fields.Field() can_post_messages: base.Boolean = fields.Field()
can_edit_messages: base.Boolean = fields.Field() can_edit_messages: base.Boolean = fields.Field()
can_delete_messages: base.Boolean = fields.Field() can_delete_messages: base.Boolean = fields.Field()
can_invite_users: base.Boolean = fields.Field() can_manage_voice_chats: base.Boolean = fields.Field()
can_restrict_members: base.Boolean = fields.Field() can_restrict_members: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
can_promote_members: base.Boolean = fields.Field() can_promote_members: base.Boolean = fields.Field()
can_change_info: base.Boolean = fields.Field()
can_invite_users: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
is_member: base.Boolean = fields.Field() is_member: base.Boolean = fields.Field()
can_send_messages: base.Boolean = fields.Field() can_send_messages: base.Boolean = fields.Field()
can_send_media_messages: base.Boolean = fields.Field() can_send_media_messages: base.Boolean = fields.Field()
can_send_polls: base.Boolean = fields.Field() can_send_polls: base.Boolean = fields.Field()
can_send_other_messages: base.Boolean = fields.Field() can_send_other_messages: base.Boolean = fields.Field()
can_add_web_page_previews: base.Boolean = fields.Field() can_add_web_page_previews: base.Boolean = fields.Field()
until_date: datetime.datetime = fields.DateTimeField()
def is_chat_creator(self) -> bool: def is_chat_creator(self) -> bool:
return ChatMemberStatus.is_chat_creator(self.status) return ChatMemberStatus.is_chat_creator(self.status)

View file

@ -0,0 +1,22 @@
import datetime
from . import base
from . import fields
from .chat import Chat
from .chat_invite_link import ChatInviteLink
from .chat_member import ChatMember
from .user import User
class ChatMemberUpdated(base.TelegramObject):
"""
This object represents changes in the status of a chat member.
https://core.telegram.org/bots/api#chatmemberupdated
"""
chat: Chat = fields.Field(base=Chat)
from_user: User = fields.Field(base=User)
date: datetime.datetime = fields.DateTimeField()
old_chat_member: ChatMember = fields.Field(base=ChatMember)
new_chat_member: ChatMember = fields.Field(base=ChatMember)
invite_link: ChatInviteLink = fields.Field(base=ChatInviteLink)

View file

@ -3,9 +3,7 @@ from . import base, fields
class Dice(base.TelegramObject): class Dice(base.TelegramObject):
""" """
This object represents a dice with random value from 1 to 6. This object represents an animated emoji that displays a random value.
(Yes, we're aware of the “proper” singular of die.
But it's awkward, and we decided to help it change. One dice at a time!)
https://core.telegram.org/bots/api#dice https://core.telegram.org/bots/api#dice
""" """
@ -19,3 +17,4 @@ class DiceEmoji:
BASKETBALL = '🏀' BASKETBALL = '🏀'
FOOTBALL = '' FOOTBALL = ''
SLOT_MACHINE = '🎰' SLOT_MACHINE = '🎰'
BOWLING = '🎳'

View file

@ -4,10 +4,6 @@ import datetime
import functools import functools
import typing import typing
from ..utils import helper
from ..utils import markdown as md
from ..utils.deprecated import deprecated
from ..utils.text_decorations import html_decoration, markdown_decoration
from . import base, fields from . import base, fields
from .animation import Animation from .animation import Animation
from .audio import Audio from .audio import Audio
@ -21,6 +17,7 @@ from .inline_keyboard import InlineKeyboardMarkup
from .input_media import InputMedia, MediaGroup from .input_media import InputMedia, MediaGroup
from .invoice import Invoice from .invoice import Invoice
from .location import Location from .location import Location
from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged
from .message_entity import MessageEntity from .message_entity import MessageEntity
from .message_id import MessageId from .message_id import MessageId
from .passport_data import PassportData from .passport_data import PassportData
@ -35,6 +32,13 @@ from .venue import Venue
from .video import Video from .video import Video
from .video_note import VideoNote from .video_note import VideoNote
from .voice import Voice from .voice import Voice
from .voice_chat_ended import VoiceChatEnded
from .voice_chat_participants_invited import VoiceChatParticipantsInvited
from .voice_chat_started import VoiceChatStarted
from ..utils import helper
from ..utils import markdown as md
from ..utils.deprecated import deprecated
from ..utils.text_decorations import html_decoration, markdown_decoration
class Message(base.TelegramObject): class Message(base.TelegramObject):
@ -86,6 +90,7 @@ class Message(base.TelegramObject):
group_chat_created: base.Boolean = fields.Field() group_chat_created: base.Boolean = fields.Field()
supergroup_chat_created: base.Boolean = fields.Field() supergroup_chat_created: base.Boolean = fields.Field()
channel_chat_created: base.Boolean = fields.Field() channel_chat_created: base.Boolean = fields.Field()
message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = fields.Field(base=MessageAutoDeleteTimerChanged)
migrate_to_chat_id: base.Integer = fields.Field() migrate_to_chat_id: base.Integer = fields.Field()
migrate_from_chat_id: base.Integer = fields.Field() migrate_from_chat_id: base.Integer = fields.Field()
pinned_message: Message = fields.Field(base="Message") pinned_message: Message = fields.Field(base="Message")
@ -94,6 +99,9 @@ class Message(base.TelegramObject):
connected_website: base.String = fields.Field() connected_website: base.String = fields.Field()
passport_data: PassportData = fields.Field(base=PassportData) passport_data: PassportData = fields.Field(base=PassportData)
proximity_alert_triggered: ProximityAlertTriggered = fields.Field(base=ProximityAlertTriggered) proximity_alert_triggered: ProximityAlertTriggered = fields.Field(base=ProximityAlertTriggered)
voice_chat_started: VoiceChatStarted = fields.Field(base=VoiceChatStarted)
voice_chat_ended: VoiceChatEnded = fields.Field(base=VoiceChatEnded)
voice_chat_participants_invited: VoiceChatParticipantsInvited = fields.Field(base=VoiceChatParticipantsInvited)
reply_markup: InlineKeyboardMarkup = fields.Field(base=InlineKeyboardMarkup) reply_markup: InlineKeyboardMarkup = fields.Field(base=InlineKeyboardMarkup)
@property @property
@ -139,6 +147,8 @@ class Message(base.TelegramObject):
return ContentType.SUCCESSFUL_PAYMENT return ContentType.SUCCESSFUL_PAYMENT
if self.connected_website: if self.connected_website:
return ContentType.CONNECTED_WEBSITE return ContentType.CONNECTED_WEBSITE
if self.message_auto_delete_timer_changed:
return ContentType.MESSAGE_AUTO_DELETE_TIMER_CHANGED
if self.migrate_from_chat_id: if self.migrate_from_chat_id:
return ContentType.MIGRATE_FROM_CHAT_ID return ContentType.MIGRATE_FROM_CHAT_ID
if self.migrate_to_chat_id: if self.migrate_to_chat_id:
@ -157,6 +167,12 @@ class Message(base.TelegramObject):
return ContentType.PASSPORT_DATA return ContentType.PASSPORT_DATA
if self.proximity_alert_triggered: if self.proximity_alert_triggered:
return ContentType.PROXIMITY_ALERT_TRIGGERED return ContentType.PROXIMITY_ALERT_TRIGGERED
if self.voice_chat_started:
return ContentType.VOICE_CHAT_STARTED
if self.voice_chat_ended:
return ContentType.VOICE_CHAT_ENDED
if self.voice_chat_participants_invited:
return ContentType.VOICE_CHAT_PARTICIPANTS_INVITED
return ContentType.UNKNOWN return ContentType.UNKNOWN
@ -2980,6 +2996,7 @@ class ContentType(helper.Helper):
INVOICE = helper.Item() # invoice INVOICE = helper.Item() # invoice
SUCCESSFUL_PAYMENT = helper.Item() # successful_payment SUCCESSFUL_PAYMENT = helper.Item() # successful_payment
CONNECTED_WEBSITE = helper.Item() # connected_website CONNECTED_WEBSITE = helper.Item() # connected_website
MESSAGE_AUTO_DELETE_TIMER_CHANGED = helper.Item() # message_auto_delete_timer_changed
MIGRATE_TO_CHAT_ID = helper.Item() # migrate_to_chat_id MIGRATE_TO_CHAT_ID = helper.Item() # migrate_to_chat_id
MIGRATE_FROM_CHAT_ID = helper.Item() # migrate_from_chat_id MIGRATE_FROM_CHAT_ID = helper.Item() # migrate_from_chat_id
PINNED_MESSAGE = helper.Item() # pinned_message PINNED_MESSAGE = helper.Item() # pinned_message
@ -2989,6 +3006,9 @@ class ContentType(helper.Helper):
GROUP_CHAT_CREATED = helper.Item() # group_chat_created GROUP_CHAT_CREATED = helper.Item() # group_chat_created
PASSPORT_DATA = helper.Item() # passport_data PASSPORT_DATA = helper.Item() # passport_data
PROXIMITY_ALERT_TRIGGERED = helper.Item() # proximity_alert_triggered PROXIMITY_ALERT_TRIGGERED = helper.Item() # proximity_alert_triggered
VOICE_CHAT_STARTED = helper.Item() # voice_chat_started
VOICE_CHAT_ENDED = helper.Item() # voice_chat_ended
VOICE_CHAT_PARTICIPANTS_INVITED = helper.Item() # voice_chat_participants_invited
UNKNOWN = helper.Item() # unknown UNKNOWN = helper.Item() # unknown
ANY = helper.Item() # any ANY = helper.Item() # any

View file

@ -0,0 +1,11 @@
from . import base
from . import fields
class MessageAutoDeleteTimerChanged(base.TelegramObject):
"""
This object represents a service message about a change in auto-delete timer settings.
https://core.telegram.org/bots/api#messageautodeletetimerchanged
"""
message_auto_delete_time: base.Integer = fields.Field()

View file

@ -3,6 +3,7 @@ from __future__ import annotations
from . import base from . import base
from . import fields from . import fields
from .callback_query import CallbackQuery from .callback_query import CallbackQuery
from .chat_member_updated import ChatMemberUpdated
from .chosen_inline_result import ChosenInlineResult from .chosen_inline_result import ChosenInlineResult
from .inline_query import InlineQuery from .inline_query import InlineQuery
from .message import Message from .message import Message
@ -31,6 +32,8 @@ class Update(base.TelegramObject):
pre_checkout_query: PreCheckoutQuery = fields.Field(base=PreCheckoutQuery) pre_checkout_query: PreCheckoutQuery = fields.Field(base=PreCheckoutQuery)
poll: Poll = fields.Field(base=Poll) poll: Poll = fields.Field(base=Poll)
poll_answer: PollAnswer = fields.Field(base=PollAnswer) poll_answer: PollAnswer = fields.Field(base=PollAnswer)
my_chat_member: ChatMemberUpdated = fields.Field(base=ChatMemberUpdated)
chat_member: ChatMemberUpdated = fields.Field(base=ChatMemberUpdated)
def __hash__(self): def __hash__(self):
return self.update_id return self.update_id
@ -61,6 +64,8 @@ class AllowedUpdates(helper.Helper):
PRE_CHECKOUT_QUERY = helper.ListItem() # pre_checkout_query PRE_CHECKOUT_QUERY = helper.ListItem() # pre_checkout_query
POLL = helper.ListItem() # poll POLL = helper.ListItem() # poll
POLL_ANSWER = helper.ListItem() # poll_answer POLL_ANSWER = helper.ListItem() # poll_answer
MY_CHAT_MEMBER = helper.ListItem() # my_chat_member
CHAT_MEMBER = helper.ListItem() # chat_member
CHOSEN_INLINE_QUERY = deprecated.DeprecatedReadOnlyClassVar( CHOSEN_INLINE_QUERY = deprecated.DeprecatedReadOnlyClassVar(
"`CHOSEN_INLINE_QUERY` is a deprecated value for allowed update. " "`CHOSEN_INLINE_QUERY` is a deprecated value for allowed update. "

View file

@ -0,0 +1,13 @@
from . import base
from . import fields
from . import mixins
class VoiceChatEnded(base.TelegramObject, mixins.Downloadable):
"""
This object represents a service message about a voice chat ended in the chat.
https://core.telegram.org/bots/api#voicechatended
"""
duration: base.Integer = fields.Field()

View file

@ -0,0 +1,16 @@
import typing
from . import base
from . import fields
from . import mixins
from .user import User
class VoiceChatParticipantsInvited(base.TelegramObject, mixins.Downloadable):
"""
This object represents a service message about new members invited to a voice chat.
https://core.telegram.org/bots/api#voicechatparticipantsinvited
"""
users: typing.List[User] = fields.ListField(base=User)

View file

@ -0,0 +1,12 @@
from . import base
from . import mixins
class VoiceChatStarted(base.TelegramObject, mixins.Downloadable):
"""
This object represents a service message about a voice chat started in the chat.
Currently holds no information.
https://core.telegram.org/bots/api#voicechatstarted
"""
pass