Added support for topics in Bot API 6.3 (#1061)

* Added support for topics in Bot API 6.3

* Added the field can_manage_topics

* Added new classes for topics

* Added is_forum field to Chat class

Co-authored-by: katant <katantdev@mail.ru>
This commit is contained in:
KatantDev 2022-11-06 08:51:42 +10:00 committed by GitHub
parent 8604ab7cd0
commit 27dea25c52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 210 additions and 9 deletions

View file

@ -274,6 +274,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
parse_mode: typing.Optional[base.String] = None,
entities: typing.Optional[typing.List[types.MessageEntity]] = None,
disable_web_page_preview: typing.Optional[base.Boolean] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -291,6 +292,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param text: Text of the message to be sent
:type text: :obj:`base.String`
@ -345,6 +350,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
chat_id: typing.Union[base.Integer, base.String],
from_chat_id: typing.Union[base.Integer, base.String],
message_id: base.Integer,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
) -> types.Message:
@ -357,6 +363,11 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param from_chat_id: Unique identifier for the chat where the
original message was sent
:type from_chat_id: :obj:`typing.Union[base.Integer, base.String]`
@ -390,6 +401,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -410,6 +422,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param from_chat_id: Unique identifier for the chat where the original
message was sent (or channel username in the format @channelusername)
:type from_chat_id: :obj:`typing.Union[base.Integer, base.String]`
@ -473,6 +489,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -490,6 +507,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param photo: Photo to send
:type photo: :obj:`typing.Union[base.InputFile, base.String]`
@ -550,6 +571,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
performer: typing.Optional[base.String] = None,
title: typing.Optional[base.String] = None,
thumb: typing.Union[base.InputFile, base.String, None] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -570,6 +592,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param audio: Audio file to send
:type audio: :obj:`typing.Union[base.InputFile, base.String]`
@ -641,6 +667,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
disable_content_type_detection: typing.Optional[base.Boolean] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -662,6 +689,11 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param document: File to send
:type document: :obj:`typing.Union[base.InputFile, base.String]`
@ -735,6 +767,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
supports_streaming: typing.Optional[base.Boolean] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -753,6 +786,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param video: Video to send
:type video: :obj:`typing.Union[base.InputFile, base.String]`
@ -829,6 +866,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
caption: typing.Optional[base.String] = None,
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -850,6 +888,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
(in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param animation: Animation to send. Pass a file_id as String to send an animation that exists
on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation
from the Internet, or upload a new animation using multipart/form-data
@ -923,6 +965,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
parse_mode: typing.Optional[base.String] = None,
caption_entities: typing.Optional[typing.List[types.MessageEntity]] = None,
duration: typing.Optional[base.Integer] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -944,6 +987,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param voice: Audio file to send
:type voice: :obj:`typing.Union[base.InputFile, base.String]`
@ -1002,6 +1049,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
duration: typing.Optional[base.Integer] = None,
length: typing.Optional[base.Integer] = None,
thumb: typing.Union[base.InputFile, base.String, None] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1020,6 +1068,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param video_note: Video note to send
:type video_note: :obj:`typing.Union[base.InputFile, base.String]`
@ -1068,6 +1120,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
async def send_media_group(self,
chat_id: typing.Union[base.Integer, base.String],
media: typing.Union[types.MediaGroup, typing.List],
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1085,6 +1138,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param media: A JSON-serialized array describing messages to be sent, must
include 2-10 items
:type media: :obj:`typing.Union[types.MediaGroup, typing.List]`
@ -1133,6 +1190,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
live_period: typing.Optional[base.Integer] = None,
heading: typing.Optional[base.Integer] = None,
proximity_alert_radius: typing.Optional[base.Integer] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1150,6 +1208,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param latitude: Latitude of the location
:type latitude: :obj:`base.Float`
@ -1305,6 +1367,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
foursquare_type: typing.Optional[base.String] = None,
google_place_id: typing.Optional[base.String] = None,
google_place_type: typing.Optional[base.String] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1323,6 +1386,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param latitude: Latitude of the venue
:type latitude: :obj:`base.Float`
@ -1386,6 +1453,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
phone_number: base.String, first_name: base.String,
last_name: typing.Optional[base.String] = None,
vcard: typing.Optional[base.String] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1403,6 +1471,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param phone_number: Contact's phone number
:type phone_number: :obj:`base.String`
@ -1463,6 +1535,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
datetime.timedelta,
None] = None,
is_closed: typing.Optional[base.Boolean] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -1482,6 +1555,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param question: Poll question, 1-300 characters
:type question: :obj:`base.String`
@ -1569,6 +1646,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
async def send_dice(self,
chat_id: typing.Union[base.Integer, base.String],
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
emoji: typing.Optional[base.String] = None,
@ -1589,6 +1667,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
target channel (in the format @channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param emoji: Emoji on which the dice throw animation is based. Currently,
must be one of 🎲, 🎯, 🏀, , or 🎰. Dice can have values 1-6
for 🎲 and 🎯, values 1-5 for 🏀 and , and values 1-64 for 🎰.
@ -1930,8 +2012,8 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:rtype: :obj:`base.Boolean`
"""
if can_manage_voice_chats:
warnings.warn(
"Argument `can_manage_voice_chats` was renamed to `can_manage_video_chats` and will be removed in aiogram 2.21")
warnings.warn("Argument `can_manage_voice_chats` was renamed to `can_manage_video_chats` and will be "
"removed in aiogram 2.21")
can_manage_video_chats = can_manage_voice_chats
can_manage_voice_chats = None
@ -2954,6 +3036,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
async def send_sticker(self, chat_id: typing.Union[base.Integer, base.String],
sticker: typing.Union[base.InputFile, base.String],
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -2971,6 +3054,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param sticker: Sticker to send
:type sticker: :obj:`typing.Union[base.InputFile, base.String]`
@ -3338,6 +3425,7 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
send_phone_number_to_provider: typing.Optional[base.Boolean] = None,
send_email_to_provider: typing.Optional[base.Boolean] = None,
is_flexible: typing.Optional[base.Boolean] = None,
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
reply_to_message_id: typing.Optional[base.Integer] = None,
@ -3354,6 +3442,10 @@ class Bot(BaseBot, DataMixin, ContextInstanceMixin):
@channelusername)
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param title: Product name, 1-32 characters
:type title: :obj:`base.String`

View file

@ -1450,7 +1450,7 @@ class PromoteChatMember(BaseResponse):
__slots__ = ('chat_id', 'user_id', 'can_change_info', 'can_post_messages', 'can_edit_messages',
'can_delete_messages', 'can_invite_users', 'can_restrict_members', 'can_pin_messages',
'can_promote_members')
'can_manage_topics', 'can_promote_members')
method = api.Methods.PROMOTE_CHAT_MEMBER
@ -1463,6 +1463,7 @@ class PromoteChatMember(BaseResponse):
can_invite_users: Optional[Boolean] = None,
can_restrict_members: Optional[Boolean] = None,
can_pin_messages: Optional[Boolean] = None,
can_manage_topics: Optional[Boolean] = None,
can_promote_members: Optional[Boolean] = None):
"""
:param chat_id: Union[Integer, String] - Unique identifier for the target chat
@ -1477,6 +1478,8 @@ class PromoteChatMember(BaseResponse):
:param can_invite_users: Boolean - Pass True, if the administrator can invite new users to the chat
:param can_restrict_members: Boolean - Pass True, if the administrator can restrict, ban or unban chat members
:param can_pin_messages: Boolean - Pass True, if the administrator can pin messages, supergroups only
:param can_manage_topics: Boolean - Pass True if the user is allowed to create, rename, close, and reopen forum
topics, supergroups only
:param can_promote_members: Boolean - Pass True, if the administrator can add new administrators
with a subset of his own privileges or demote administrators that he has promoted,
directly or indirectly (promoted by administrators that were appointed by him)
@ -1490,6 +1493,7 @@ class PromoteChatMember(BaseResponse):
self.can_invite_users = can_invite_users
self.can_restrict_members = can_restrict_members
self.can_pin_messages = can_pin_messages
self.can_manage_topics = can_manage_topics
self.can_promote_members = can_promote_members
def prepare(self):
@ -1503,6 +1507,7 @@ class PromoteChatMember(BaseResponse):
'can_invite_users': self.can_invite_users,
'can_restrict_members': self.can_restrict_members,
'can_pin_messages': self.can_pin_messages,
'can_manage_topics': self.can_manage_topics,
'can_promote_members': self.can_promote_members
}

View file

@ -29,6 +29,9 @@ from .encrypted_credentials import EncryptedCredentials
from .encrypted_passport_element import EncryptedPassportElement
from .file import File
from .force_reply import ForceReply
from .forum_topic_created import ForumTopicCreated
from .forum_topic_closed import ForumTopicClosed
from .forum_topic_reopened import ForumTopicReopened
from .game import Game
from .game_high_score import GameHighScore
from .inline_keyboard import InlineKeyboardButton, InlineKeyboardMarkup
@ -240,6 +243,9 @@ __all__ = (
'WebAppData',
'WebAppInfo',
'WebhookInfo',
'ForumTopicCreated',
'ForumTopicClosed',
'ForumTopicReopened',
'base',
'fields',
)

View file

@ -27,8 +27,11 @@ class Chat(base.TelegramObject):
username: base.String = fields.Field()
first_name: base.String = fields.Field()
last_name: base.String = fields.Field()
is_forum: base.Boolean = fields.Field()
all_members_are_administrators: base.Boolean = fields.Field()
photo: ChatPhoto = fields.Field(base=ChatPhoto)
active_usernames: typing.List[base.String] = fields.Field()
emoji_status_custom_emoji_id: base.String = fields.Field()
bio: base.String = fields.Field()
has_private_forwards: base.Boolean = fields.Field()
has_restricted_voice_and_video_messages: base.Boolean = fields.Field()

View file

@ -19,6 +19,7 @@ class ChatAdministratorRights(base.TelegramObject):
can_post_messages: base.Boolean = fields.Field()
can_edit_messages: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
can_manage_topics: base.Boolean = fields.Field()
def __init__(self,
is_anonymous: base.Boolean = None,
@ -31,7 +32,8 @@ class ChatAdministratorRights(base.TelegramObject):
can_invite_users: base.Boolean = None,
can_post_messages: base.Boolean = None,
can_edit_messages: base.Boolean = None,
can_pin_messages: base.Boolean = None):
can_pin_messages: base.Boolean = None,
can_manage_topics: base.Boolean = None):
super(ChatAdministratorRights, self).__init__(
is_anonymous=is_anonymous,
can_manage_chat=can_manage_chat,
@ -43,4 +45,5 @@ class ChatAdministratorRights(base.TelegramObject):
can_invite_users=can_invite_users,
can_post_messages=can_post_messages,
can_edit_messages=can_edit_messages,
can_pin_messages=can_pin_messages)
can_pin_messages=can_pin_messages,
can_manage_topics=can_manage_topics)

View file

@ -135,6 +135,7 @@ class ChatMemberOwner(ChatMember):
can_change_info: base.Boolean = fields.ConstField(True)
can_invite_users: base.Boolean = fields.ConstField(True)
can_pin_messages: base.Boolean = fields.ConstField(True)
can_manage_topics: base.Boolean = fields.ConstField(True)
class ChatMemberAdministrator(ChatMember):
@ -159,6 +160,7 @@ class ChatMemberAdministrator(ChatMember):
can_change_info: base.Boolean = fields.Field()
can_invite_users: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
can_manage_topics: base.Boolean = fields.Field()
class ChatMemberMember(ChatMember):
@ -185,6 +187,7 @@ class ChatMemberRestricted(ChatMember):
can_change_info: base.Boolean = fields.Field()
can_invite_users: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
can_manage_topics: base.Boolean = fields.Field()
can_send_messages: base.Boolean = fields.Field()
can_send_media_messages: base.Boolean = fields.Field()
can_send_polls: base.Boolean = fields.Field()

View file

@ -16,6 +16,7 @@ class ChatPermissions(base.TelegramObject):
can_change_info: base.Boolean = fields.Field()
can_invite_users: base.Boolean = fields.Field()
can_pin_messages: base.Boolean = fields.Field()
can_manage_topics: base.Boolean = fields.Field()
def __init__(self,
can_send_messages: base.Boolean = None,
@ -26,6 +27,7 @@ class ChatPermissions(base.TelegramObject):
can_change_info: base.Boolean = None,
can_invite_users: base.Boolean = None,
can_pin_messages: base.Boolean = None,
can_manage_topics: base.Boolean = None,
**kwargs):
super(ChatPermissions, self).__init__(
can_send_messages=can_send_messages,
@ -36,4 +38,5 @@ class ChatPermissions(base.TelegramObject):
can_change_info=can_change_info,
can_invite_users=can_invite_users,
can_pin_messages=can_pin_messages,
can_manage_topics=can_manage_topics,
)

View file

@ -0,0 +1,10 @@
from . import base
class ForumTopicClosed(base.TelegramObject):
"""
This object represents a service message about a forum topic closed in the chat. Currently holds no information.
https://core.telegram.org/bots/api#forumtopicclosed
"""
pass

View file

@ -0,0 +1,13 @@
from . import base
from . import fields
class ForumTopicCreated(base.TelegramObject):
"""
This object represents a service message about a new forum topic created in the chat.
https://core.telegram.org/bots/api#forumtopiccreated
"""
name: base.String = fields.Field()
icon_color: base.Integer = fields.Field()
icon_custom_emoji_id: base.String = fields.Field()

View file

@ -0,0 +1,10 @@
from . import base
class ForumTopicReopened(base.TelegramObject):
"""
This object represents a service message about a forum topic closed in the chat. Currently holds no information.
https://core.telegram.org/bots/api#forumtopicreopened
"""
pass

View file

@ -41,6 +41,9 @@ from .voice_chat_participants_invited import VoiceChatParticipantsInvited
from .voice_chat_scheduled import VoiceChatScheduled
from .voice_chat_started import VoiceChatStarted
from .web_app_data import WebAppData
from .forum_topic_created import ForumTopicCreated
from .forum_topic_closed import ForumTopicClosed
from .forum_topic_reopened import ForumTopicReopened
from ..utils import helper
from ..utils import markdown as md
from ..utils.text_decorations import html_decoration, markdown_decoration
@ -54,6 +57,7 @@ class Message(base.TelegramObject):
"""
message_id: base.Integer = fields.Field()
message_thread_id: base.Integer = fields.Field()
from_user: User = fields.Field(alias="from", base=User)
sender_chat: Chat = fields.Field(base=Chat)
date: datetime.datetime = fields.DateTimeField()
@ -63,6 +67,7 @@ class Message(base.TelegramObject):
forward_from_message_id: base.Integer = fields.Field()
forward_signature: base.String = fields.Field()
forward_date: datetime.datetime = fields.DateTimeField()
is_topic_message: base.Boolean = fields.Field()
is_automatic_forward: base.Boolean = fields.Field()
reply_to_message: Message = fields.Field(base="Message")
via_bot: User = fields.Field(base=User)
@ -112,6 +117,9 @@ class Message(base.TelegramObject):
voice_chat_participants_invited: VoiceChatParticipantsInvited = fields.Field(base=VoiceChatParticipantsInvited)
reply_markup: InlineKeyboardMarkup = fields.Field(base=InlineKeyboardMarkup)
web_app_data: WebAppData = fields.Field(base=WebAppData)
forum_topic_created: ForumTopicCreated = fields.Field(base=ForumTopicCreated)
forum_topic_closed: ForumTopicClosed = fields.Field(base=ForumTopicClosed)
forum_topic_reopened: ForumTopicReopened = fields.Field(base=ForumTopicReopened)
video_chat_scheduled: VideoChatScheduled = fields.Field(base=VideoChatScheduled)
video_chat_started: VideoChatStarted = fields.Field(base=VideoChatStarted)
video_chat_ended: VideoChatEnded = fields.Field(base=VideoChatEnded)
@ -278,7 +286,7 @@ class Message(base.TelegramObject):
:return: int
"""
return self.sender_chat.id if self.sender_chat else self.from_user.id
@property
def md_text(self) -> str:
"""
@ -396,6 +404,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_message(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
text=text,
parse_mode=parse_mode,
entities=entities,
@ -468,6 +477,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_photo(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
photo=photo,
caption=caption,
parse_mode=parse_mode,
@ -560,6 +570,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_audio(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
audio=audio,
caption=caption,
parse_mode=parse_mode,
@ -658,6 +669,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_animation(
self.chat.id,
message_thread_id=self.message_thread_id,
animation=animation,
duration=duration,
width=width,
@ -749,6 +761,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_document(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
thumb=thumb,
document=document,
caption=caption,
@ -807,7 +820,8 @@ class Message(base.TelegramObject):
A thumbnails width and height should not exceed 320.
:type thumb: :obj:`typing.Union[base.InputFile, base.String, None]`
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after
entities parsing
:type caption: :obj:`typing.Optional[base.String]`
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic,
@ -845,6 +859,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_video(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
video=video,
duration=duration,
width=width,
@ -930,6 +945,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_voice(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
voice=voice,
caption=caption,
parse_mode=parse_mode,
@ -1003,6 +1019,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_video_note(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
video_note=video_note,
duration=duration,
length=length,
@ -1053,6 +1070,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_media_group(
self.chat.id,
message_thread_id=self.message_thread_id,
media=media,
disable_notification=disable_notification,
protect_content=protect_content,
@ -1131,6 +1149,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_location(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
latitude=latitude,
longitude=longitude,
horizontal_accuracy=horizontal_accuracy,
@ -1223,6 +1242,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_venue(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
latitude=latitude,
longitude=longitude,
title=title,
@ -1293,6 +1313,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_contact(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
phone_number=phone_number,
first_name=first_name,
last_name=last_name,
@ -1350,6 +1371,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_sticker(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
sticker=sticker,
disable_notification=disable_notification,
protect_content=protect_content,
@ -1463,6 +1485,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_poll(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
question=question,
options=options,
is_anonymous=is_anonymous,
@ -1536,6 +1559,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_dice(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
emoji=emoji,
disable_notification=disable_notification,
protect_content=protect_content,
@ -1627,6 +1651,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_message(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
text=text,
parse_mode=parse_mode,
entities=entities,
@ -1699,6 +1724,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_photo(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
photo=photo,
caption=caption,
parse_mode=parse_mode,
@ -1791,6 +1817,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_audio(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
audio=audio,
caption=caption,
parse_mode=parse_mode,
@ -1889,6 +1916,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_animation(
self.chat.id,
message_thread_id=self.message_thread_id,
animation=animation,
duration=duration,
width=width,
@ -1980,6 +2008,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_document(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
document=document,
thumb=thumb,
caption=caption,
@ -2038,7 +2067,8 @@ class Message(base.TelegramObject):
A thumbnails width and height should not exceed 320.
:type thumb: :obj:`typing.Union[base.InputFile, base.String, None]`
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after entities parsing
:param caption: Video caption (may also be used when resending videos by file_id), 0-1024 characters after
entities parsing
:type caption: :obj:`typing.Optional[base.String]`
:param parse_mode: Send Markdown or HTML, if you want Telegram apps to show bold, italic,
@ -2076,6 +2106,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_video(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
video=video,
duration=duration,
width=width,
@ -2161,6 +2192,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_voice(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
voice=voice,
caption=caption,
parse_mode=parse_mode,
@ -2234,6 +2266,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_video_note(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
video_note=video_note,
duration=duration,
length=length,
@ -2284,6 +2317,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_media_group(
self.chat.id,
message_thread_id=self.message_thread_id,
media=media,
disable_notification=disable_notification,
protect_content=protect_content,
@ -2357,6 +2391,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_location(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
latitude=latitude,
longitude=longitude,
horizontal_accuracy=horizontal_accuracy,
@ -2448,6 +2483,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_venue(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
latitude=latitude,
longitude=longitude,
title=title,
@ -2518,6 +2554,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_contact(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
phone_number=phone_number,
first_name=first_name,
last_name=last_name,
@ -2633,6 +2670,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_poll(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
question=question,
options=options,
is_anonymous=is_anonymous,
@ -2699,6 +2737,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_sticker(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
sticker=sticker,
disable_notification=disable_notification,
protect_content=protect_content,
@ -2761,6 +2800,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.send_dice(
chat_id=self.chat.id,
message_thread_id=self.message_thread_id,
emoji=emoji,
disable_notification=disable_notification,
protect_content=protect_content,
@ -2772,6 +2812,7 @@ class Message(base.TelegramObject):
async def forward(
self,
chat_id: typing.Union[base.Integer, base.String],
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[base.Boolean] = None,
protect_content: typing.Optional[base.Boolean] = None,
) -> Message:
@ -2783,6 +2824,10 @@ class Message(base.TelegramObject):
:param chat_id: Unique identifier for the target chat or username of the target channel
:type chat_id: :obj:`typing.Union[base.Integer, base.String]`
:param message_thread_id: Unique identifier for the target message thread (topic) of the forum; for forum
supergroups only
:type message_thread_id: :obj:`typing.Optional[base.Integer]`
:param disable_notification: Sends the message silently. Users will receive a notification with no sound
:type disable_notification: :obj:`typing.Optional[base.Boolean]`
@ -2795,6 +2840,7 @@ class Message(base.TelegramObject):
"""
return await self.bot.forward_message(
chat_id=chat_id,
message_thread_id=self.message_thread_id,
from_chat_id=self.chat.id,
message_id=self.message_id,
disable_notification=disable_notification,
@ -3059,6 +3105,7 @@ class Message(base.TelegramObject):
async def send_copy(
self: Message,
chat_id: typing.Union[str, int],
message_thread_id: typing.Optional[base.Integer] = None,
disable_notification: typing.Optional[bool] = None,
protect_content: typing.Optional[base.Boolean] = None,
disable_web_page_preview: typing.Optional[bool] = None,
@ -3072,6 +3119,7 @@ class Message(base.TelegramObject):
Send copy of current message
:param chat_id:
:param message_thread_id:
:param disable_notification:
:param protect_content:
:param disable_web_page_preview: for text messages only
@ -3082,6 +3130,7 @@ class Message(base.TelegramObject):
"""
kwargs = {
"chat_id": chat_id,
"message_thread_id": message_thread_id,
"allow_sending_without_reply": allow_sending_without_reply,
"reply_markup": reply_markup or self.reply_markup,
"parse_mode": ParseMode.HTML,

View file

@ -4,7 +4,7 @@ from . import mixins
class VideoChatStarted(base.TelegramObject, mixins.Downloadable):
"""
his object represents a service message about a video chat started in the chat. Currently holds no information.
This object represents a service message about a video chat started in the chat. Currently holds no information.
https://core.telegram.org/bots/api#videochatstarted
"""

View file

@ -61,6 +61,7 @@ CHAT_MEMBER = {
"can_promote_members": False,
"can_manage_voice_chats": True, # Deprecated
"can_manage_video_chats": True,
"can_manage_topics": True,
"is_anonymous": False,
}

View file

@ -41,6 +41,9 @@ def test_privileges():
assert isinstance(chat_member.can_promote_members, bool)
assert chat_member.can_promote_members == CHAT_MEMBER['can_promote_members']
assert isinstance(chat_member.can_manage_topics, bool)
assert chat_member.can_manage_topics == CHAT_MEMBER['can_manage_topics']
def test_int():
assert int(chat_member) == chat_member.user.id