From 598ecdb588bf14b05f42023d3fbcd7aac3fc428e Mon Sep 17 00:00:00 2001 From: Oleg A Date: Sat, 4 Feb 2023 03:29:40 +0300 Subject: [PATCH] Telegram API 6.5 (#1111) * docs: telegram api version bump * feat: add KeyboardButtonRequestUser and KeyboardButtonRequestChat * feat: added the classes UserShared, ChatShared * feat: added the parameter use_independent_chat_permissions * fix: permissions field is mandatory for restrictChatMember * feat: added the field user_chat_id * feat: replaced the fields can_send_media_messages * docs: add comment with replacement * Update types/__init__.py * Added new content types * Fixed types --------- Co-authored-by: Alex Root Junior --- aiogram/__init__.py | 4 +- aiogram/bot/bot.py | 50 ++++++++++++++----- aiogram/types/__init__.py | 17 +++++-- aiogram/types/chat_join_request.py | 1 + aiogram/types/chat_member.py | 9 ++++ aiogram/types/chat_shared.py | 12 +++++ aiogram/types/message.py | 31 ++++++++---- aiogram/types/reply_keyboard.py | 78 ++++++++++++++++++++++++++++++ aiogram/types/user_shared.py | 12 +++++ 9 files changed, 186 insertions(+), 28 deletions(-) create mode 100644 aiogram/types/chat_shared.py create mode 100644 aiogram/types/user_shared.py diff --git a/aiogram/__init__.py b/aiogram/__init__.py index ea1d5df8..c14b984f 100644 --- a/aiogram/__init__.py +++ b/aiogram/__init__.py @@ -43,5 +43,5 @@ __all__ = ( 'utils', ) -__version__ = '2.24' -__api_version__ = '6.4' +__version__ = '2.25' +__api_version__ = '6.5' diff --git a/aiogram/bot/bot.py b/aiogram/bot/bot.py index 8465fa1e..54aad263 100644 --- a/aiogram/bot/bot.py +++ b/aiogram/bot/bot.py @@ -1900,16 +1900,20 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.UNBAN_CHAT_MEMBER, payload) - async def restrict_chat_member(self, chat_id: typing.Union[base.Integer, base.String], - user_id: base.Integer, - permissions: typing.Optional[types.ChatPermissions] = None, - # permissions argument need to be required after removing other `can_*` arguments - until_date: typing.Union[ - base.Integer, datetime.datetime, datetime.timedelta, None] = None, - can_send_messages: typing.Optional[base.Boolean] = None, - can_send_media_messages: typing.Optional[base.Boolean] = None, - can_send_other_messages: typing.Optional[base.Boolean] = None, - can_add_web_page_previews: typing.Optional[base.Boolean] = None) -> base.Boolean: + async def restrict_chat_member( + self, + chat_id: typing.Union[base.Integer, base.String], + user_id: base.Integer, + permissions: typing.Optional[types.ChatPermissions], + use_independent_chat_permissions: typing.Optional[base.Boolean] = None, + # permissions argument need to be required after removing other `can_*` arguments + until_date: typing.Union[ + base.Integer, datetime.datetime, datetime.timedelta, None] = None, + can_send_messages: typing.Optional[base.Boolean] = None, + can_send_media_messages: typing.Optional[base.Boolean] = None, + can_send_other_messages: typing.Optional[base.Boolean] = None, + can_add_web_page_previews: typing.Optional[base.Boolean] = None, + ) -> base.Boolean: """ Use this method to restrict a user in a supergroup. The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights. @@ -1923,6 +1927,15 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :type user_id: :obj:`base.Integer` :param permissions: New user permissions :type permissions: :obj:`ChatPermissions` + :param use_independent_chat_permissions: Pass True if chat + permissions are set independently. Otherwise, + the can_send_other_messages and can_add_web_page_previews + permissions will imply the can_send_messages, + can_send_audios, can_send_documents, can_send_photos, + can_send_videos, can_send_video_notes, and + can_send_voice_notes permissions; the can_send_polls + permission will imply the can_send_messages permission. + :type use_independent_chat_permissions: :obj:`typing.Optional[base.Boolean]` :param until_date: Date when restrictions will be lifted for the user, unix time :type until_date: :obj:`typing.Optional[base.Integer]` :param can_send_messages: Pass True, if the user can send text messages, contacts, locations and venues @@ -2106,8 +2119,12 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): return await self.request(api.Methods.UNBAN_CHAT_SENDER_CHAT, payload) - async def set_chat_permissions(self, chat_id: typing.Union[base.Integer, base.String], - permissions: types.ChatPermissions) -> base.Boolean: + async def set_chat_permissions( + self, + chat_id: typing.Union[base.Integer, base.String], + permissions: types.ChatPermissions, + use_independent_chat_permissions: base.Boolean = None, + ) -> base.Boolean: """ Use this method to set default chat permissions for all members. The bot must be an administrator in the group or a supergroup for this to work and must have the @@ -2117,6 +2134,15 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin): :param chat_id: Unique identifier for the target chat or username of the target supergroup :param permissions: New default chat permissions + :param use_independent_chat_permissions: Pass True if chat + permissions are set independently. Otherwise, + the can_send_other_messages and can_add_web_page_previews + permissions will imply the can_send_messages, + can_send_audios, can_send_documents, can_send_photos, + can_send_videos, can_send_video_notes, and + can_send_voice_notes permissions; the can_send_polls + permission will imply the can_send_messages permission. + :type use_independent_chat_permissions: :obj:`typing.Optional[base.Boolean]` :return: True on success. """ permissions = prepare_arg(permissions) diff --git a/aiogram/types/__init__.py b/aiogram/types/__init__.py index a75b76c0..9d99880f 100644 --- a/aiogram/types/__init__.py +++ b/aiogram/types/__init__.py @@ -21,6 +21,7 @@ from .chat_member import ChatMember, ChatMemberAdministrator, ChatMemberBanned, from .chat_member_updated import ChatMemberUpdated from .chat_permissions import ChatPermissions from .chat_photo import ChatPhoto +from .chat_shared import ChatShared from .chosen_inline_result import ChosenInlineResult from .contact import Contact from .dice import Dice, DiceEmoji @@ -71,7 +72,8 @@ from .photo_size import PhotoSize from .poll import PollOption, Poll, PollAnswer, PollType from .pre_checkout_query import PreCheckoutQuery from .proximity_alert_triggered import ProximityAlertTriggered -from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, KeyboardButtonPollType +from .reply_keyboard import KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove, KeyboardButtonPollType, \ + KeyboardButtonRequestChat, KeyboardButtonRequestUser from .response_parameters import ResponseParameters from .sent_web_app_message import SentWebAppMessage from .shipping_address import ShippingAddress @@ -83,6 +85,7 @@ from .successful_payment import SuccessfulPayment from .update import AllowedUpdates, Update from .user import User from .user_profile_photos import UserProfilePhotos +from .user_shared import UserShared from .venue import Venue from .video import Video from .video_chat_ended import VideoChatEnded @@ -189,6 +192,8 @@ __all__ = ( 'Invoice', 'KeyboardButton', 'KeyboardButtonPollType', + 'KeyboardButtonRequestChat', + 'KeyboardButtonRequestUser', 'LabeledPrice', 'Location', 'LoginUrl', @@ -252,10 +257,12 @@ __all__ = ( 'ForumTopicCreated', 'ForumTopicClosed', 'ForumTopicReopened', - "ForumTopicEdited", - "GeneralForumTopicHidden", - "GeneralForumTopicUnhidden", - "WriteAccessAllowed", + 'ForumTopicEdited', + 'GeneralForumTopicHidden', + 'GeneralForumTopicUnhidden', + 'WriteAccessAllowed', + "ChatShared", + "UserShared", 'base', 'fields', ) diff --git a/aiogram/types/chat_join_request.py b/aiogram/types/chat_join_request.py index 3f8ce846..6a523dbe 100644 --- a/aiogram/types/chat_join_request.py +++ b/aiogram/types/chat_join_request.py @@ -16,6 +16,7 @@ class ChatJoinRequest(base.TelegramObject): chat: Chat = fields.Field(base=Chat) from_user: User = fields.Field(alias="from", base=User) + user_chat_id: base.Integer = fields.Field() date: datetime = fields.DateTimeField() bio: base.String = fields.Field() invite_link: ChatInviteLink = fields.Field(base=ChatInviteLink) diff --git a/aiogram/types/chat_member.py b/aiogram/types/chat_member.py index 6424025f..7586acc6 100644 --- a/aiogram/types/chat_member.py +++ b/aiogram/types/chat_member.py @@ -189,7 +189,16 @@ class ChatMemberRestricted(ChatMember): can_pin_messages: base.Boolean = fields.Field() can_manage_topics: base.Boolean = fields.Field() can_send_messages: base.Boolean = fields.Field() + can_send_audios: base.Boolean = fields.Field() + can_send_documents: base.Boolean = fields.Field() + can_send_photos: base.Boolean = fields.Field() + can_send_videos: base.Boolean = fields.Field() + can_send_video_notes: base.Boolean = fields.Field() + can_send_voice_notes: base.Boolean = fields.Field() + + # warning! field was replaced: https://core.telegram.org/bots/api#february-3-2023 can_send_media_messages: base.Boolean = fields.Field() + can_send_polls: base.Boolean = fields.Field() can_send_other_messages: base.Boolean = fields.Field() can_add_web_page_previews: base.Boolean = fields.Field() diff --git a/aiogram/types/chat_shared.py b/aiogram/types/chat_shared.py new file mode 100644 index 00000000..b6d18673 --- /dev/null +++ b/aiogram/types/chat_shared.py @@ -0,0 +1,12 @@ +from . import base, fields + + +class ChatShared(base.TelegramObject): + """ + This object contains information about the chat whose identifier was + shared with the bot using a KeyboardButtonRequestChat button. + + https://core.telegram.org/bots/api#chatshared + """ + request_id: base.Integer = fields.Field() + user_id: base.Integer = fields.Field() diff --git a/aiogram/types/message.py b/aiogram/types/message.py index e8051169..4313cdf4 100644 --- a/aiogram/types/message.py +++ b/aiogram/types/message.py @@ -8,6 +8,7 @@ from . import base, fields from .animation import Animation from .audio import Audio from .chat import Chat, ChatType +from .chat_shared import ChatShared from .contact import Contact from .dice import Dice from .document import Document @@ -34,6 +35,7 @@ from .reply_keyboard import ReplyKeyboardMarkup, ReplyKeyboardRemove from .sticker import Sticker from .successful_payment import SuccessfulPayment from .user import User +from .user_shared import UserShared from .venue import Venue from .video import Video from .video_chat_ended import VideoChatEnded @@ -112,6 +114,8 @@ class Message(base.TelegramObject): pinned_message: Message = fields.Field(base="Message") invoice: Invoice = fields.Field(base=Invoice) successful_payment: SuccessfulPayment = fields.Field(base=SuccessfulPayment) + user_shared: UserShared = fields.Field(base=UserShared) + chat_shared: ChatShared = fields.Field(base=ChatShared) connected_website: base.String = fields.Field() passport_data: PassportData = fields.Field(base=PassportData) proximity_alert_triggered: ProximityAlertTriggered = fields.Field(base=ProximityAlertTriggered) @@ -229,6 +233,10 @@ class Message(base.TelegramObject): return ContentType.GENERAL_FORUM_TOPIC_UNHIDDEN if self.write_access_allowed: return ContentType.WRITE_ACCESS_ALLOWED + if self.chat_shared: + return ContentType.CHAT_SHARED + if self.user_shared: + return ContentType.USER_SHARED return ContentType.UNKNOWN @@ -3366,6 +3374,9 @@ class ContentType(helper.Helper): GENERAL_FORUM_TOPIC_HIDDEN = helper.Item() # general_forum_topic_hidden GENERAL_FORUM_TOPIC_UNHIDDEN = helper.Item() # general_forum_topic_unhidden WRITE_ACCESS_ALLOWED = helper.Item() # write_access_allowed + CHAT_SHARED = helper.Item() # chat_shared + USER_SHARED = helper.Item() # user_shared + UNKNOWN = helper.Item() # unknown ANY = helper.Item() # any @@ -3431,18 +3442,20 @@ class ContentTypes(helper.Helper): DELETE_CHAT_PHOTO = helper.ListItem() # delete_chat_photo GROUP_CHAT_CREATED = helper.ListItem() # group_chat_created PASSPORT_DATA = helper.ListItem() # passport_data - WEB_APP_DATA = helper.Item() # web_app_data + WEB_APP_DATA = helper.ListItem() # web_app_data FORUM_TOPIC_CREATED = helper.ListItem() # forum_topic_created FORUM_TOPIC_CLOSED = helper.ListItem() # forum_topic_closed FORUM_TOPIC_REOPENED = helper.ListItem() # forum_topic_reopened - VIDEO_CHAT_SCHEDULED = helper.Item() # video_chat_scheduled - VIDEO_CHAT_STARTED = helper.Item() # video_chat_started - VIDEO_CHAT_ENDED = helper.Item() # video_chat_ended - VIDEO_CHAT_PARTICIPANTS_INVITED = helper.Item() # video_chat_participants_invited - FORUM_TOPIC_EDITED = helper.Item() # forum_topic_edited - GENERAL_FORUM_TOPIC_HIDDEN = helper.Item() # general_forum_topic_hidden - GENERAL_FORUM_TOPIC_UNHIDDEN = helper.Item() # general_forum_topic_unhidden - WRITE_ACCESS_ALLOWED = helper.Item() # write_access_allowed + VIDEO_CHAT_SCHEDULED = helper.ListItem() # video_chat_scheduled + VIDEO_CHAT_STARTED = helper.ListItem() # video_chat_started + VIDEO_CHAT_ENDED = helper.ListItem() # video_chat_ended + VIDEO_CHAT_PARTICIPANTS_INVITED = helper.ListItem() # video_chat_participants_invited + FORUM_TOPIC_EDITED = helper.ListItem() # forum_topic_edited + GENERAL_FORUM_TOPIC_HIDDEN = helper.ListItem() # general_forum_topic_hidden + GENERAL_FORUM_TOPIC_UNHIDDEN = helper.ListItem() # general_forum_topic_unhidden + WRITE_ACCESS_ALLOWED = helper.ListItem() # write_access_allowed + CHAT_SHARED = helper.ListItem() # chat_shared + USER_SHARED = helper.ListItem() # user_shared UNKNOWN = helper.ListItem() # unknown ANY = helper.ListItem() # any diff --git a/aiogram/types/reply_keyboard.py b/aiogram/types/reply_keyboard.py index 5a28f3f4..e48bacc9 100644 --- a/aiogram/types/reply_keyboard.py +++ b/aiogram/types/reply_keyboard.py @@ -2,6 +2,7 @@ import typing from . import base from . import fields +from .chat_administrator_rights import ChatAdministratorRights from .web_app_info import WebAppInfo @@ -105,6 +106,76 @@ class ReplyKeyboardMarkup(base.TelegramObject): return self + +class KeyboardButtonRequestUser(base.TelegramObject): + """ + This object defines the criteria used to request a suitable user. + The identifier of the selected user will be shared with the bot when + the corresponding button is pressed. + + https://core.telegram.org/bots/api#keyboardbuttonrequestuser + """ + request_id: base.Integer = fields.Field() + user_is_bot: base.Boolean = fields.Field() + user_is_premium: base.Boolean = fields.Field() + + def __init__( + self, + request_id: base.Integer, + user_is_bot: typing.Optional[base.Boolean] = None, + user_is_premium: typing.Optional[base.Boolean] = None, + **kwargs, + ): + super().__init__( + request_id=request_id, + user_is_bot=user_is_bot, + user_is_premium=user_is_premium, + **kwargs, + ) + + +class KeyboardButtonRequestChat(base.TelegramObject): + """ + This object defines the criteria used to request a suitable chat. + The identifier of the selected chat will be shared with the bot when + the corresponding button is pressed. + + https://core.telegram.org/bots/api#keyboardbuttonrequestchat + """ + request_id: base.Integer = fields.Field() + chat_is_channel: base.Boolean = fields.Field() + chat_is_forum: base.Boolean = fields.Field() + chat_has_username: base.Boolean = fields.Field() + chat_is_created: base.Boolean = fields.Field() + user_administrator_rights: ChatAdministratorRights = fields.Field() + bot_administrator_rights: ChatAdministratorRights = fields.Field() + bot_is_member: base.Boolean = fields.Field() + + def __init__( + self, + request_id: base.Integer, + chat_is_channel: base.Boolean, + chat_is_forum: typing.Optional[base.Boolean] = None, + chat_has_username: typing.Optional[base.Boolean] = None, + chat_is_created: typing.Optional[base.Boolean] = None, + user_administrator_rights: typing.Optional[ChatAdministratorRights] = None, + bot_administrator_rights: typing.Optional[ChatAdministratorRights] = None, + bot_is_member: typing.Optional[base.Boolean] = None, + **kwargs, + ): + super().__init__( + request_id=request_id, + chat_is_channel=chat_is_channel, + chat_is_forum=chat_is_forum, + chat_has_username=chat_has_username, + chat_is_created=chat_is_created, + user_administrator_rights=user_administrator_rights, + bot_administrator_rights=bot_administrator_rights, + bot_is_member=bot_is_member, + **kwargs, + ) + + class KeyboardButton(base.TelegramObject): """ This object represents one button of the reply keyboard. @@ -118,18 +189,24 @@ class KeyboardButton(base.TelegramObject): https://core.telegram.org/bots/api#keyboardbutton """ text: base.String = fields.Field() + request_user: KeyboardButtonRequestUser = fields.Field() + request_chat: KeyboardButtonRequestChat = fields.Field() request_contact: base.Boolean = fields.Field() request_location: base.Boolean = fields.Field() request_poll: KeyboardButtonPollType = fields.Field() web_app: WebAppInfo = fields.Field(base=WebAppInfo) def __init__(self, text: base.String, + request_user: typing.Optional[KeyboardButtonRequestUser] = None, + request_chat: typing.Optional[KeyboardButtonRequestChat] = None, request_contact: base.Boolean = None, request_location: base.Boolean = None, request_poll: KeyboardButtonPollType = None, web_app: WebAppInfo = None, **kwargs): super(KeyboardButton, self).__init__(text=text, + request_user=request_user, + request_chat=request_chat, request_contact=request_contact, request_location=request_location, request_poll=request_poll, @@ -137,6 +214,7 @@ class KeyboardButton(base.TelegramObject): **kwargs) + class ReplyKeyboardRemove(base.TelegramObject): """ Upon receiving a message with this object, Telegram clients will remove the current custom keyboard diff --git a/aiogram/types/user_shared.py b/aiogram/types/user_shared.py new file mode 100644 index 00000000..dcbf74de --- /dev/null +++ b/aiogram/types/user_shared.py @@ -0,0 +1,12 @@ +from . import base, fields + + +class UserShared(base.TelegramObject): + """ + This object contains information about the user whose identifier was + shared with the bot using a KeyboardButtonRequestUser button. + + https://core.telegram.org/bots/api#usershared + """ + request_id: base.Integer = fields.Field() + user_id: base.Integer = fields.Field()