From 24cd014410280748252d3e50c034e81a1344306f Mon Sep 17 00:00:00 2001 From: _run Date: Fri, 30 Dec 2022 18:52:00 +0400 Subject: [PATCH 01/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8c4a6c84..5eb412ce7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

A simple, but extensible Python implementation for the Telegram Bot API.

Both synchronous and asynchronous.

-##

Supported Bot API version: 6.3! +##

Supported Bot API version: 6.4!

Official documentation

From f0a1cefdda5b846ff3bb28c8042215d26b7d09e0 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 19:08:37 +0400 Subject: [PATCH 02/13] Added the field is_persistent to the class ReplyKeyboardMarkup Added the field is_persistent to the class ReplyKeyboardMarkup, allowing to control when the keyboard is shown. --- telebot/types.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 5e843d286..b510962f5 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -2055,13 +2055,21 @@ class ReplyKeyboardMarkup(JsonSerializable): replies to the request with a keyboard to select the new language. Other users in the group don't see the keyboard. :type selective: :obj:`bool` + :param is_persistent: Optional. Use this parameter if you want to show the keyboard to specific users only. + Targets: 1) users that are @mentioned in the text of the Message object; 2) if the bot's message is a + reply (has reply_to_message_id), sender of the original message. + + Example: A user requests to change the bot's language, bot replies to the request with a keyboard to + select the new language. Other users in the group don't see the keyboard. + :return: Instance of the class :rtype: :class:`telebot.types.ReplyKeyboardMarkup` """ max_row_keys = 12 def __init__(self, resize_keyboard: Optional[bool]=None, one_time_keyboard: Optional[bool]=None, - selective: Optional[bool]=None, row_width: int=3, input_field_placeholder: Optional[str]=None): + selective: Optional[bool]=None, row_width: int=3, input_field_placeholder: Optional[str]=None, + is_persistent: Optional[bool]=None): if row_width > self.max_row_keys: # Todo: Will be replaced with Exception in future releases if not DISABLE_KEYLEN_ERROR: @@ -2074,6 +2082,7 @@ def __init__(self, resize_keyboard: Optional[bool]=None, one_time_keyboard: Opti self.row_width: int = row_width self.input_field_placeholder: str = input_field_placeholder self.keyboard: List[List[KeyboardButton]] = [] + self.is_persistent: bool = is_persistent def add(self, *args, row_width=None): """ @@ -2139,6 +2148,8 @@ def to_json(self): json_dict['selective'] = self.selective if self.input_field_placeholder: json_dict['input_field_placeholder'] = self.input_field_placeholder + if self.is_persistent is not None: + json_dict['is_persistent'] = self.is_persistent return json.dumps(json_dict) From 4d11e97c25b8920492e8e2ac7c525629e8085568 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 19:20:23 +0400 Subject: [PATCH 03/13] has_spoiler parameter Added the parameter has_spoiler to the methods sendPhoto, sendVideo, and sendAnimation. --- telebot/__init__.py | 24 ++++++++++++++++++------ telebot/apihelper.py | 13 ++++++++++--- telebot/async_telebot.py | 24 ++++++++++++++++++------ telebot/asyncio_helper.py | 13 ++++++++++--- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 6a4dd7ba1..bf94fd530 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -1763,7 +1763,8 @@ def send_photo( allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send photos. On success, the sent Message is returned. @@ -1808,6 +1809,9 @@ def send_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` + + :param has_spoiler: Pass True, if the photo should be sent as a spoiler + :type has_spoiler: :obj:`bool` :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` @@ -1821,7 +1825,7 @@ def send_photo( apihelper.send_photo( self.token, chat_id, photo, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply, protect_content, message_thread_id)) + allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) # TODO: Rewrite this method like in API. def send_audio( @@ -2171,7 +2175,8 @@ def send_video( reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, data: Optional[Union[Any, str]]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -2233,6 +2238,9 @@ def send_video( :param message_thread_id: Identifier of a message thread, in which the video will be sent :type message_thread_id: :obj:`int` + :param has_spoiler: Pass True, if the video should be sent as a spoiler + :type has_spoiler: :obj:`bool` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2249,7 +2257,7 @@ def send_video( apihelper.send_video( self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup, parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, - caption_entities, allow_sending_without_reply, protect_content, message_thread_id)) + caption_entities, allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) def send_animation( self, chat_id: Union[int, str], animation: Union[Any, str], @@ -2266,7 +2274,8 @@ def send_animation( allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -2327,6 +2336,9 @@ def send_animation( :param message_thread_id: Identifier of a message thread, in which the video will be sent :type message_thread_id: :obj:`int` + :param has_spoiler: Pass True, if the animation should be sent as a spoiler + :type has_spoiler: :obj:`bool` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -2339,7 +2351,7 @@ def send_animation( apihelper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, thumb, - caption_entities, allow_sending_without_reply, protect_content, width, height, message_thread_id)) + caption_entities, allow_sending_without_reply, protect_content, width, height, message_thread_id, has_spoiler)) # TODO: Rewrite this method like in API. def send_video_note( diff --git a/telebot/apihelper.py b/telebot/apihelper.py index b25e0365e..005ac337e 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -459,7 +459,7 @@ def send_photo( caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None, - message_thread_id=None): + message_thread_id=None, has_spoiler=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -489,6 +489,8 @@ def send_photo( payload['protect_content'] = protect_content if message_thread_id is not None: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return _make_request(token, method_url, params=payload, files=files, method='post') @@ -666,7 +668,7 @@ def send_chat_action(token, chat_id, action, timeout=None): def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None, thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None, - message_thread_id=None): + message_thread_id=None, has_spoiler=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -710,13 +712,16 @@ def send_video(token, chat_id, data, duration=None, caption=None, reply_to_messa payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return _make_request(token, method_url, params=payload, files=files, method='post') def send_animation( token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None, - allow_sending_without_reply=None, protect_content=None, width=None, height=None, message_thread_id=None): + allow_sending_without_reply=None, protect_content=None, width=None, height=None, message_thread_id=None, + has_spoiler=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -758,6 +763,8 @@ def send_animation( payload['height'] = height if message_thread_id: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return _make_request(token, method_url, params=payload, files=files, method='post') diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index e8249fc86..bbaeb539c 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -2627,7 +2627,8 @@ async def send_photo( allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send photos. On success, the sent Message is returned. @@ -2672,6 +2673,9 @@ async def send_photo( :param message_thread_id: Identifier of a message thread, in which the message will be sent :type message_thread_id: :obj:`int` + + :param has_spoiler: Pass True, if the photo should be sent as a spoiler + :type has_spoiler: :obj:`bool` :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` @@ -2685,7 +2689,7 @@ async def send_photo( await asyncio_helper.send_photo( self.token, chat_id, photo, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, caption_entities, - allow_sending_without_reply, protect_content, message_thread_id)) + allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) async def send_audio( self, chat_id: Union[int, str], audio: Union[Any, str], @@ -3031,7 +3035,8 @@ async def send_video( reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, data: Optional[Union[Any, str]]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send video files, Telegram clients support mp4 videos (other formats may be sent as Document). @@ -3093,6 +3098,9 @@ async def send_video( :param message_thread_id: Identifier of a message thread, in which the video will be sent :type message_thread_id: :obj:`int` + :param has_spoiler: Pass True, if the video should be sent as a spoiler + :type has_spoiler: :obj:`bool` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3110,7 +3118,7 @@ async def send_video( await asyncio_helper.send_video( self.token, chat_id, video, duration, caption, reply_to_message_id, reply_markup, parse_mode, supports_streaming, disable_notification, timeout, thumb, width, height, - caption_entities, allow_sending_without_reply, protect_content, message_thread_id)) + caption_entities, allow_sending_without_reply, protect_content, message_thread_id, has_spoiler)) async def send_animation( self, chat_id: Union[int, str], animation: Union[Any, str], @@ -3127,7 +3135,8 @@ async def send_animation( allow_sending_without_reply: Optional[bool]=None, reply_markup: Optional[REPLY_MARKUP_TYPES]=None, timeout: Optional[int]=None, - message_thread_id: Optional[int]=None) -> types.Message: + message_thread_id: Optional[int]=None, + has_spoiler: Optional[bool]=None) -> types.Message: """ Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On success, the sent Message is returned. Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future. @@ -3188,6 +3197,9 @@ async def send_animation( :param message_thread_id: Identifier of a message thread, in which the video will be sent :type message_thread_id: :obj:`int` + :param has_spoiler: Pass True, if the animation should be sent as a spoiler + :type has_spoiler: :obj:`bool` + :return: On success, the sent Message is returned. :rtype: :class:`telebot.types.Message` """ @@ -3200,7 +3212,7 @@ async def send_animation( await asyncio_helper.send_animation( self.token, chat_id, animation, duration, caption, reply_to_message_id, reply_markup, parse_mode, disable_notification, timeout, thumb, - caption_entities, allow_sending_without_reply, width, height, protect_content, message_thread_id)) + caption_entities, allow_sending_without_reply, width, height, protect_content, message_thread_id, has_spoiler)) async def send_video_note( self, chat_id: Union[int, str], data: Union[Any, str], diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 9f5b59a71..2ae19341d 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -453,7 +453,7 @@ async def send_photo( caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, caption_entities=None, allow_sending_without_reply=None, protect_content=None, - message_thread_id=None): + message_thread_id=None, has_spoiler=None): method_url = r'sendPhoto' payload = {'chat_id': chat_id} files = None @@ -483,6 +483,8 @@ async def send_photo( payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return await _process_request(token, method_url, params=payload, files=files, method='post') @@ -658,7 +660,7 @@ async def send_chat_action(token, chat_id, action, timeout=None): async def send_video(token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, supports_streaming=None, disable_notification=None, timeout=None, thumb=None, width=None, height=None, caption_entities=None, allow_sending_without_reply=None, - protect_content=None, message_thread_id=None): + protect_content=None, message_thread_id=None, has_spoiler=None): method_url = r'sendVideo' payload = {'chat_id': chat_id} files = None @@ -702,13 +704,16 @@ async def send_video(token, chat_id, data, duration=None, caption=None, reply_to payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return await _process_request(token, method_url, params=payload, files=files, method='post') async def send_animation( token, chat_id, data, duration=None, caption=None, reply_to_message_id=None, reply_markup=None, parse_mode=None, disable_notification=None, timeout=None, thumb=None, caption_entities=None, - allow_sending_without_reply=None, width=None, height=None, protect_content=None, message_thread_id=None): + allow_sending_without_reply=None, width=None, height=None, protect_content=None, message_thread_id=None, + has_spoiler=None): method_url = r'sendAnimation' payload = {'chat_id': chat_id} files = None @@ -750,6 +755,8 @@ async def send_animation( payload['protect_content'] = protect_content if message_thread_id: payload['message_thread_id'] = message_thread_id + if has_spoiler is not None: + payload['has_spoiler'] = has_spoiler return await _process_request(token, method_url, params=payload, files=files, method='post') From 4537b237c80ce7f257c721dffdd4e554e62dc32e Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 19:27:38 +0400 Subject: [PATCH 04/13] has_spoiler for types.py Added the field has_spoiler to the classes InputMediaPhoto, InputMediaVideo, and InputMediaAnimation. --- telebot/types.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/telebot/types.py b/telebot/types.py index b510962f5..bf1c8b153 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -5792,18 +5792,26 @@ class InputMediaPhoto(InputMedia): instead of parse_mode :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` + :param has_spoiler: Optional. True, if the uploaded photo is a spoiler + :type has_spoiler: :obj:`bool` + :return: Instance of the class :rtype: :class:`telebot.types.InputMediaPhoto` """ - def __init__(self, media, caption=None, parse_mode=None, caption_entities=None): + def __init__(self, media, caption=None, parse_mode=None, caption_entities=None, has_spoiler=None): if util.is_pil_image(media): media = util.pil_image_to_file(media) super(InputMediaPhoto, self).__init__( type="photo", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) + self.has_spoiler: Optional[bool] = has_spoiler + def to_dict(self): - return super(InputMediaPhoto, self).to_dict() + ret = super(InputMediaPhoto, self).to_dict() + if self.has_spoiler: + ret['has_spoiler'] = self.has_spoiler + return ret class InputMediaVideo(InputMedia): @@ -5847,11 +5855,14 @@ class InputMediaVideo(InputMedia): :param supports_streaming: Optional. Pass True, if the uploaded video is suitable for streaming :type supports_streaming: :obj:`bool` + :param has_spoiler: Optional. True, if the uploaded video is a spoiler + :type has_spoiler: :obj:`bool` + :return: Instance of the class :rtype: :class:`telebot.types.InputMediaVideo` """ def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, - width=None, height=None, duration=None, supports_streaming=None): + width=None, height=None, duration=None, supports_streaming=None, has_spoiler=None): super(InputMediaVideo, self).__init__( type="video", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) self.thumb = thumb @@ -5859,6 +5870,7 @@ def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_ent self.height = height self.duration = duration self.supports_streaming = supports_streaming + self.has_spoiler: Optional[bool] = has_spoiler def to_dict(self): ret = super(InputMediaVideo, self).to_dict() @@ -5872,6 +5884,8 @@ def to_dict(self): ret['duration'] = self.duration if self.supports_streaming: ret['supports_streaming'] = self.supports_streaming + if self.has_spoiler: + ret['has_spoiler'] = self.has_spoiler return ret @@ -5913,17 +5927,21 @@ class InputMediaAnimation(InputMedia): :param duration: Optional. Animation duration in seconds :type duration: :obj:`int` + :param has_spoiler: Optional. True, if the uploaded animation is a spoiler + :type has_spoiler: :obj:`bool` + :return: Instance of the class :rtype: :class:`telebot.types.InputMediaAnimation` """ def __init__(self, media, thumb=None, caption=None, parse_mode=None, caption_entities=None, - width=None, height=None, duration=None): + width=None, height=None, duration=None, has_spoiler=None): super(InputMediaAnimation, self).__init__( type="animation", media=media, caption=caption, parse_mode=parse_mode, caption_entities=caption_entities) self.thumb = thumb self.width = width self.height = height self.duration = duration + self.has_spoiler: Optional[bool] = has_spoiler def to_dict(self): ret = super(InputMediaAnimation, self).to_dict() @@ -5935,6 +5953,8 @@ def to_dict(self): ret['height'] = self.height if self.duration: ret['duration'] = self.duration + if self.has_spoiler: + ret['has_spoiler'] = self.has_spoiler return ret From 9f5d9861a489fa2d1e924e0556ca4a74010aac3d Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 19:41:46 +0400 Subject: [PATCH 05/13] Added the field has_media_spoiler to the class Message. Added the field has_media_spoiler to the class Message. --- telebot/types.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index bf1c8b153..266f80cfd 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -812,6 +812,9 @@ class Message(JsonDeserializable): commands, etc. that appear in the caption :type caption_entities: :obj:`list` of :class:`telebot.types.MessageEntity` + :param has_media_spoiler: Optional. True, if the message media is covered by a spoiler animation + :type has_media_spoiler: :obj:`bool` + :param contact: Optional. Message is a shared contact, information about the contact :type contact: :class:`telebot.types.Contact` @@ -1110,6 +1113,8 @@ def de_json(cls, json_string): if 'forum_topic_reopened' in obj: opts['forum_topic_reopened'] = ForumTopicReopened.de_json(obj['forum_topic_reopened']) content_type = 'forum_topic_reopened' + if 'has_media_spoiler' in obj: + opts['has_media_spoiler'] = obj['has_media_spoiler'] return cls(message_id, from_user, date, chat, content_type, opts, json_string) @classmethod @@ -1200,6 +1205,7 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso self.forum_topic_created: Optional[ForumTopicCreated] = None self.forum_topic_closed: Optional[ForumTopicClosed] = None self.forum_topic_reopened: Optional[ForumTopicReopened] = None + self.has_media_spoiler: Optional[bool] = None for key in options: setattr(self, key, options[key]) self.json = json_string From 107f92314bcd161c7d31a7bad621af13b43d4343 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 19:50:14 +0400 Subject: [PATCH 06/13] icon_custom_emoji_id and name parameters made optional for edit_forum_topic The parameters name and icon_custom_emoji_id of the method editForumTopic are now optional. If they are omitted, the existing values are kept. --- telebot/__init__.py | 11 +++++++---- telebot/apihelper.py | 8 ++++++-- telebot/async_telebot.py | 11 +++++++---- telebot/asyncio_helper.py | 8 ++++++-- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index bf94fd530..95ec9364a 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -4648,8 +4648,8 @@ def create_forum_topic(self, def edit_forum_topic( self, chat_id: Union[int, str], - message_thread_id: int, name: str, - icon_custom_emoji_id: str, + message_thread_id: int, name: Optional[str]=None, + icon_custom_emoji_id: Optional[str]=None ) -> bool: """ Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an @@ -4664,10 +4664,13 @@ def edit_forum_topic( :param message_thread_id: Identifier of the topic to edit :type message_thread_id: :obj:`int` - :param name: New name of the topic, 1-128 characters + :param name: Optional, New name of the topic, 1-128 characters. If not specififed or empty, + the current name of the topic will be kept :type name: :obj:`str` - :param icon_custom_emoji_id: New custom emoji for the topic icon. Must be an emoji of type “tgs” and must be exactly 1 character long + :param icon_custom_emoji_id: Optional, New unique identifier of the custom emoji shown as the topic icon. + Use getForumTopicIconStickers to get all allowed custom emoji identifiers. Pass an empty string to remove the + icon. If not specified, the current icon will be kept :type icon_custom_emoji_id: :obj:`str` :return: On success, True is returned. diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 005ac337e..4f5670578 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1773,9 +1773,13 @@ def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_emoji_ payload['icon_custom_emoji_id'] = icon_custom_emoji_id return _make_request(token, method_url, params=payload) -def edit_forum_topic(token, chat_id, message_thread_id, name, icon_custom_emoji_id): +def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None): method_url = r'editForumTopic' - payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id, 'name': name, 'icon_custom_emoji_id': icon_custom_emoji_id} + payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id} + if name is not None: + payload['name'] = name + if icon_custom_emoji_id is not None: + payload['icon_custom_emoji_id'] = icon_custom_emoji_id return _make_request(token, method_url, params=payload) def close_forum_topic(token, chat_id, message_thread_id): diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index bbaeb539c..65accb8dc 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -5514,8 +5514,8 @@ async def create_forum_topic(self, async def edit_forum_topic( self, chat_id: Union[int, str], - message_thread_id: int, name: str, - icon_custom_emoji_id: str, + message_thread_id: int, name: Optional[str]=None, + icon_custom_emoji_id: Optional[str]=None ) -> bool: """ Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must be an @@ -5530,10 +5530,13 @@ async def edit_forum_topic( :param message_thread_id: Identifier of the topic to edit :type message_thread_id: :obj:`int` - :param name: New name of the topic, 1-128 characters + :param name: Optional, New name of the topic, 1-128 characters. If not specififed or empty, + the current name of the topic will be kept :type name: :obj:`str` - :param icon_custom_emoji_id: New custom emoji for the topic icon. Must be an emoji of type “tgs” and must be exactly 1 character long + :param icon_custom_emoji_id: Optional, New unique identifier of the custom emoji shown as the topic icon. + Use getForumTopicIconStickers to get all allowed custom emoji identifiers. Pass an empty string to remove the + icon. If not specified, the current icon will be kept :type icon_custom_emoji_id: :obj:`str` :return: On success, True is returned. diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 2ae19341d..8bbdc3daa 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1764,9 +1764,13 @@ async def create_forum_topic(token, chat_id, name, icon_color=None, icon_custom_ payload['icon_custom_emoji_id'] = icon_custom_emoji_id return await _process_request(token, method_url, params=payload) -async def edit_forum_topic(token, chat_id, message_thread_id, name, icon_custom_emoji_id): +async def edit_forum_topic(token, chat_id, message_thread_id, name=None, icon_custom_emoji_id=None): method_url = r'editForumTopic' - payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id, 'name': name, 'icon_custom_emoji_id': icon_custom_emoji_id} + payload = {'chat_id': chat_id, 'message_thread_id': message_thread_id} + if name is not None: + payload['name'] = name + if icon_custom_emoji_id is not None: + payload['icon_custom_emoji_id'] = icon_custom_emoji_id return await _process_request(token, method_url, params=payload) async def close_forum_topic(token, chat_id, message_thread_id): From a20a3ae32179489fc7d2d345316c891a830c1cdd Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 20:07:38 +0400 Subject: [PATCH 07/13] topic events and write_access_allowed Added the classes ForumTopicEdited, GeneralForumTopicHidden, GeneralForumTopicUnhidden, and WriteAccessAllowed and the fields forum_topic_edited, general_forum_topic_hidden, general_forum_topic_unhidden, and write_access_allowed to the class Message. --- telebot/types.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index 266f80cfd..015947769 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -895,6 +895,10 @@ class Message(JsonDeserializable): Telegram Login » :type connected_website: :obj:`str` + :param write_access_allowed: Optional. Service message: the user allowed the bot added to the attachment + menu to write messages + :type write_access_allowed: :class:`telebot.types.WriteAccessAllowed` + :param passport_data: Optional. Telegram Passport data :type passport_data: :class:`telebot.types.PassportData` @@ -905,12 +909,21 @@ class Message(JsonDeserializable): :param forum_topic_created: Optional. Service message: forum topic created :type forum_topic_created: :class:`telebot.types.ForumTopicCreated` + :param forum_topic_edited: Optional. Service message: forum topic edited + :type forum_topic_edited: :class:`telebot.types.ForumTopicEdited` + :param forum_topic_closed: Optional. Service message: forum topic closed :type forum_topic_closed: :class:`telebot.types.ForumTopicClosed` :param forum_topic_reopened: Optional. Service message: forum topic reopened :type forum_topic_reopened: :class:`telebot.types.ForumTopicReopened` + :param general_forum_topic_hidden: Optional. Service message: the 'General' forum topic hidden + :type general_forum_topic_hidden: :class:`telebot.types.GeneralForumTopicHidden` + + :param general_forum_topic_unhidden: Optional. Service message: the 'General' forum topic unhidden + :type general_forum_topic_unhidden: :class:`telebot.types.GeneralForumTopicUnhidden` + :param video_chat_scheduled: Optional. Service message: video chat scheduled :type video_chat_scheduled: :class:`telebot.types.VideoChatScheduled` @@ -1115,6 +1128,18 @@ def de_json(cls, json_string): content_type = 'forum_topic_reopened' if 'has_media_spoiler' in obj: opts['has_media_spoiler'] = obj['has_media_spoiler'] + if 'forum_topic_edited' in obj: + opts['forum_topic_edited'] = ForumTopicEdited.de_json(obj['forum_topic_edited']) + content_type = 'forum_topic_edited' + if 'general_forum_topic_hidden' in obj: + opts['general_forum_topic_hidden'] = GeneralForumTopicHidden.de_json(obj['general_forum_topic_hidden']) + content_type = 'general_forum_topic_hidden' + if 'general_forum_topic_unhidden' in obj: + opts['general_forum_topic_unhidden'] = GeneralForumTopicUnhidden.de_json(obj['general_forum_topic_unhidden']) + content_type = 'general_forum_topic_unhidden' + if 'write_access_allowed' in obj: + opts['write_access_allowed'] = WriteAccessAllowed.de_json(obj['write_access_allowed']) + content_type = 'write_access_allowed' return cls(message_id, from_user, date, chat, content_type, opts, json_string) @classmethod @@ -1206,6 +1231,10 @@ def __init__(self, message_id, from_user, date, chat, content_type, options, jso self.forum_topic_closed: Optional[ForumTopicClosed] = None self.forum_topic_reopened: Optional[ForumTopicReopened] = None self.has_media_spoiler: Optional[bool] = None + self.forum_topic_edited: Optional[ForumTopicEdited] = None + self.general_forum_topic_hidden: Optional[GeneralForumTopicHidden] = None + self.general_forum_topic_unhidden: Optional[GeneralForumTopicUnhidden] = None + self.write_access_allowed: Optional[WriteAccessAllowed] = None for key in options: setattr(self, key, options[key]) self.json = json_string @@ -6866,6 +6895,61 @@ def de_json(cls, json_string): def __init__(self) -> None: pass +class ForumTopicEdited(JsonDeserializable): + """ + This object represents a service message about an edited forum topic. + + Telegram documentation: https://core.telegram.org/bots/api#forumtopicedited + + :param name: Optional, Name of the topic(if updated) + :type name: :obj:`str` + + :param icon_custom_emoji_id: Optional. New identifier of the custom emoji shown as the topic icon, if it was edited; + an empty string if the icon was removed + :type icon_custom_emoji_id: :obj:`str` + """ + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + def __init__(self, name: Optional[str]=None, icon_custom_emoji_id: Optional[str]=None) -> None: + self.name: Optional[str] = name + self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id + + +class GeneralForumTopicHidden(JsonDeserializable): + """ + This object represents a service message about General forum topic hidden in the chat. + Currently holds no information. + + Telegram documentation: https://core.telegram.org/bots/api#generalforumtopichidden + """ + @classmethod + def de_json(cls, json_string): + return cls() + + def __init__(self) -> None: + pass + + +class GeneralForumTopicUnhidden(JsonDeserializable): + """ + This object represents a service message about General forum topic unhidden in the chat. + Currently holds no information. + + Telegram documentation: https://core.telegram.org/bots/api#generalforumtopicunhidden + """ + + @classmethod + def de_json(cls, json_string): + return cls() + + def __init__(self) -> None: + pass + + class ForumTopic(JsonDeserializable): """ @@ -6902,6 +6986,19 @@ def __init__(self, message_thread_id: int, name: str, icon_color: int, icon_cust self.icon_custom_emoji_id: Optional[str] = icon_custom_emoji_id +class WriteAccessAllowed(JsonDeserializable): + """ + This object represents a service message about a user allowed to post messages in the chat. + Currently holds no information. + + Telegram documentation: https://core.telegram.org/bots/api#writeaccessallowed + """ + @classmethod + def de_json(cls, json_string): + return cls() + + def __init__(self) -> None: + pass From f297ad23c7511f50223a46c9fe00384a13ad2abd Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 20:19:50 +0400 Subject: [PATCH 08/13] Added methods for topic management Added the methods editGeneralForumTopic, closeGeneralForumTopic, reopenGeneralForumTopic, hideGeneralForumTopic, unhideGeneralForumTopic for managing the General topic in forums. --- telebot/__init__.py | 69 +++++++++++++++++++++++++++++++++++++++ telebot/apihelper.py | 25 ++++++++++++++ telebot/async_telebot.py | 69 +++++++++++++++++++++++++++++++++++++++ telebot/asyncio_helper.py | 25 ++++++++++++++ 4 files changed, 188 insertions(+) diff --git a/telebot/__init__.py b/telebot/__init__.py index 95ec9364a..fa0c11b82 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -4754,6 +4754,75 @@ def unpin_all_forum_topic_messages(self, chat_id: Union[str, int], message_threa """ return apihelper.unpin_all_forum_topic_messages(self.token, chat_id, message_thread_id) + def edit_general_forum_topic(self, chat_id: Union[int, str], name: str) -> bool: + """ + Use this method to edit the name of the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#editgeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + + :param name: New topic name, 1-128 characters + :type name: :obj:`str` + """ + + return apihelper.edit_general_forum_topic(self.token, chat_id, name) + + def close_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to close the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#closegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return apihelper.close_general_forum_topic(self.token, chat_id) + + def reopen_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to reopen the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#reopengeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return apihelper.reopen_general_forum_topic(self.token, chat_id) + + def hide_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to hide the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#hidegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return apihelper.hide_general_forum_topic(self.token, chat_id) + + def unhide_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to unhide the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#unhidegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return apihelper.unhide_general_forum_topic(self.token, chat_id) + def get_forum_topic_icon_stickers(self) -> List[types.Sticker]: """ Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 4f5670578..f1fdb7cfb 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1813,6 +1813,31 @@ def stop_poll(token, chat_id, message_id, reply_markup=None): payload['reply_markup'] = _convert_markup(reply_markup) return _make_request(token, method_url, params=payload) +def edit_general_forum_topic(token, chat_id, name): + method_url = r'editGeneralForumTopic' + payload = {'chat_id': chat_id, 'name': name} + return _make_request(token, method_url, params=payload) + +def close_general_forum_topic(token, chat_id): + method_url = r'closeGeneralForumTopic' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload) + +def reopen_general_forum_topic(token, chat_id): + method_url = r'reopenGeneralForumTopic' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload) + +def hide_general_forum_topic(token, chat_id): + method_url = r'hideGeneralForumTopic' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload) + +def unhide_general_forum_topic(token, chat_id): + method_url = r'unhideGeneralForumTopic' + payload = {'chat_id': chat_id} + return _make_request(token, method_url, params=payload) + def _convert_list_json_serializable(results): ret = '' diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 65accb8dc..0ee8f0623 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -5620,6 +5620,75 @@ async def unpin_all_forum_topic_messages(self, chat_id: Union[str, int], message """ return await asyncio_helper.unpin_all_forum_topic_messages(self.token, chat_id, message_thread_id) + async def edit_general_forum_topic(self, chat_id: Union[int, str], name: str) -> bool: + """ + Use this method to edit the name of the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#editgeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + + :param name: New topic name, 1-128 characters + :type name: :obj:`str` + """ + + return await asyncio_helper.edit_general_forum_topic(self.token, chat_id, name) + + async def close_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to close the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#closegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return await asyncio_helper.close_general_forum_topic(self.token, chat_id) + + async def reopen_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to reopen the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#reopengeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return await asyncio_helper.reopen_general_forum_topic(self.token, chat_id) + + async def hide_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to hide the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#hidegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return await asyncio_helper.hide_general_forum_topic(self.token, chat_id) + + async def unhide_general_forum_topic(self, chat_id: Union[int, str]) -> bool: + """ + Use this method to unhide the 'General' topic in a forum supergroup chat. + The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights. + Returns True on success. + + Telegram documentation: https://core.telegram.org/bots/api#unhidegeneralforumtopic + + :param chat_id: Unique identifier for the target chat or username of the target channel (in the format @channelusername) + :type chat_id: :obj:`int` or :obj:`str` + """ + return await asyncio_helper.unhide_general_forum_topic(self.token, chat_id) + async def get_forum_topic_icon_stickers(self) -> List[types.Sticker]: """ Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user. diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 8bbdc3daa..86468d04c 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1797,6 +1797,31 @@ async def get_forum_topic_icon_stickers(token): method_url = r'getForumTopicIconStickers' return await _process_request(token, method_url) +async def edit_general_forum_topic(token, chat_id, name): + method_url = r'editGeneralForumTopic' + payload = {'chat_id': chat_id, 'name': name} + return await _process_request(token, method_url, params=payload) + +async def close_general_forum_topic(token, chat_id): + method_url = r'closeGeneralForumTopic' + payload = {'chat_id': chat_id} + return await _process_request(token, method_url, params=payload) + +async def reopen_general_forum_topic(token, chat_id): + method_url = r'reopenGeneralForumTopic' + payload = {'chat_id': chat_id} + return await _process_request(token, method_url, params=payload) + +async def hide_general_forum_topic(token, chat_id): + method_url = r'hideGeneralForumTopic' + payload = {'chat_id': chat_id} + return await _process_request(token, method_url, params=payload) + +async def unhide_general_forum_topic(token, chat_id): + method_url = r'unhideGeneralForumTopic' + payload = {'chat_id': chat_id} + return await _process_request(token, method_url, params=payload) + async def _convert_list_json_serializable(results): ret = '' for r in results: From 9f8256607afa58472b78eb1cb46fdd0a87abf330 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 20:23:53 +0400 Subject: [PATCH 09/13] Added the parameter message_thread_id to the method sendChatAction for sending chat actions to a specific message thread or a forum topic. Added the parameter message_thread_id to the method sendChatAction for sending chat actions to a specific message thread or a forum topic. --- telebot/__init__.py | 7 +++++-- telebot/apihelper.py | 4 +++- telebot/async_telebot.py | 7 +++++-- telebot/asyncio_helper.py | 4 +++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index fa0c11b82..ef8ab7146 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -2806,7 +2806,7 @@ def send_contact( allow_sending_without_reply, protect_content, message_thread_id)) def send_chat_action( - self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None) -> bool: + self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None, message_thread_id: Optional[int]=None) -> bool: """ Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). @@ -2829,10 +2829,13 @@ def send_chat_action( :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` + :param message_thread_id: The thread identifier of a message from which the reply will be sent(supergroups only) + :type message_thread_id: :obj:`int` + :return: Returns True on success. :rtype: :obj:`bool` """ - return apihelper.send_chat_action(self.token, chat_id, action, timeout) + return apihelper.send_chat_action(self.token, chat_id, action, timeout, message_thread_id) @util.deprecated(deprecation_text="Use ban_chat_member instead") def kick_chat_member( diff --git a/telebot/apihelper.py b/telebot/apihelper.py index f1fdb7cfb..1086f54e9 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -657,11 +657,13 @@ def send_contact( return _make_request(token, method_url, params=payload) -def send_chat_action(token, chat_id, action, timeout=None): +def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None): method_url = r'sendChatAction' payload = {'chat_id': chat_id, 'action': action} if timeout: payload['timeout'] = timeout + if message_thread_id is not None: + payload['message_thread_id'] = message_thread_id return _make_request(token, method_url, params=payload) diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 0ee8f0623..6e3ec9ad7 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -3664,7 +3664,7 @@ async def send_contact( ) async def send_chat_action( - self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None) -> bool: + self, chat_id: Union[int, str], action: str, timeout: Optional[int]=None, message_thread_id: Optional[int]=None) -> bool: """ Use this method when you need to tell the user that something is happening on the bot's side. The status is set for 5 seconds or less (when a message arrives from your bot, Telegram clients clear its typing status). @@ -3687,10 +3687,13 @@ async def send_chat_action( :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` + :param message_thread_id: The thread to which the message will be sent(supergroups only) + :type message_thread_id: :obj:`int` + :return: Returns True on success. :rtype: :obj:`bool` """ - return await asyncio_helper.send_chat_action(self.token, chat_id, action, timeout) + return await asyncio_helper.send_chat_action(self.token, chat_id, action, timeout, message_thread_id) async def kick_chat_member( self, chat_id: Union[int, str], user_id: int, diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 86468d04c..437188566 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -649,11 +649,13 @@ async def send_contact( return await _process_request(token, method_url, params=payload) -async def send_chat_action(token, chat_id, action, timeout=None): +async def send_chat_action(token, chat_id, action, timeout=None, message_thread_id=None): method_url = r'sendChatAction' payload = {'chat_id': chat_id, 'action': action} if timeout: payload['timeout'] = timeout + if message_thread_id: + payload['message_thread_id'] = message_thread_id return await _process_request(token, method_url, params=payload) From eed56be59645b9d3c8c9c24982ace3e81c63ef56 Mon Sep 17 00:00:00 2001 From: coder2020official Date: Fri, 30 Dec 2022 20:38:26 +0400 Subject: [PATCH 10/13] Added fields has_hidden_members and has_aggressive_anti_spam_enabled to class Chat --- telebot/types.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 015947769..efcf6de94 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -570,6 +570,14 @@ class Chat(JsonDeserializable): automatically deleted; in seconds. Returned only in getChat. :type message_auto_delete_time: :obj:`int` + :param has_aggressive_anti_spam_enabled: Optional. :obj:`bool`, if the chat has enabled aggressive anti-spam + protection. Returned only in getChat. + :type has_aggressive_anti_spam_enabled: :obj:`bool` + + :param has_hidden_members: Optional. :obj:`bool`, if the chat has enabled hidden members. Returned only in + getChat. + :type has_hidden_members: :obj:`bool` + :param has_protected_content: Optional. :obj:`bool`, if messages from the chat can't be forwarded to other chats. Returned only in getChat. :type has_protected_content: :obj:`bool` @@ -615,7 +623,8 @@ def __init__(self, id, type, title=None, username=None, first_name=None, message_auto_delete_time=None, has_protected_content=None, sticker_set_name=None, can_set_sticker_set=None, linked_chat_id=None, location=None, join_to_send_messages=None, join_by_request=None, has_restricted_voice_and_video_messages=None, - is_forum=None, active_usernames=None, emoji_status_custom_emoji_id=None, **kwargs): + is_forum=None, active_usernames=None, emoji_status_custom_emoji_id=None, + has_hidden_members=None, has_aggressive_anti_spam_enabled=None, **kwargs): self.id: int = id self.type: str = type self.title: str = title @@ -642,6 +651,8 @@ def __init__(self, id, type, title=None, username=None, first_name=None, self.location: ChatLocation = location self.active_usernames: List[str] = active_usernames self.emoji_status_custom_emoji_id: str = emoji_status_custom_emoji_id + self.has_hidden_members: bool = has_hidden_members + self.has_aggressive_anti_spam_enabled: bool = has_aggressive_anti_spam_enabled class MessageID(JsonDeserializable): From 667e82d0736c3b6e7a45b01d66008b4fd96016c3 Mon Sep 17 00:00:00 2001 From: _run Date: Mon, 2 Jan 2023 17:54:35 +0400 Subject: [PATCH 11/13] Update telebot/types.py --- telebot/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index efcf6de94..920fecc96 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -5855,7 +5855,7 @@ def __init__(self, media, caption=None, parse_mode=None, caption_entities=None, def to_dict(self): ret = super(InputMediaPhoto, self).to_dict() - if self.has_spoiler: + if self.has_spoiler is not None: ret['has_spoiler'] = self.has_spoiler return ret From 267a33c3298c76105f2a6d17573d0ee18770b4f4 Mon Sep 17 00:00:00 2001 From: _run Date: Mon, 2 Jan 2023 17:55:14 +0400 Subject: [PATCH 12/13] Update telebot/types.py --- telebot/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 920fecc96..8a5cfa403 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -5930,7 +5930,7 @@ def to_dict(self): ret['duration'] = self.duration if self.supports_streaming: ret['supports_streaming'] = self.supports_streaming - if self.has_spoiler: + if self.has_spoiler is not None: ret['has_spoiler'] = self.has_spoiler return ret From 3be5015f9e79d9b691c9d164cf74633dd9507f59 Mon Sep 17 00:00:00 2001 From: _run Date: Mon, 2 Jan 2023 17:55:30 +0400 Subject: [PATCH 13/13] Update telebot/types.py --- telebot/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telebot/types.py b/telebot/types.py index 8a5cfa403..2938674bb 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -5999,7 +5999,7 @@ def to_dict(self): ret['height'] = self.height if self.duration: ret['duration'] = self.duration - if self.has_spoiler: + if self.has_spoiler is not None: ret['has_spoiler'] = self.has_spoiler return ret