From 76f8b790e0a685c120558cf0e7463de9a9137cd9 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 18 Jun 2024 16:36:01 +0500 Subject: [PATCH 1/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5d13646bf..10694e4b0 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@

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

Both synchronous and asynchronous.

-##

Supported Bot API version: 7.4! +##

Supported Bot API version: 7.5!

Official documentation

Official ru documentation

From eec78c931b1b0cae506fc467779d1282f1534df1 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 18 Jun 2024 16:52:58 +0500 Subject: [PATCH 2/6] Added the classes StarTransactions, StarTransaction, TransactionPartner and RevenueWithdrawalState, containing information about Telegram Star transactions involving the bot. --- telebot/types.py | 242 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index 1438cf762..588e38919 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -10005,3 +10005,245 @@ def de_json(cls, json_string): def __init__(self, type, **kwargs): self.type: BackgroundType = type + + +class RevenueWithdrawalState(JsonDeserializable): + """ + This object describes the state of a revenue withdrawal operation. Currently, it can be one of + RevenueWithdrawalStatePending + RevenueWithdrawalStateSucceeded + RevenueWithdrawalStateFailed + + Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstate + + :param type: Type of the state, always “pending” or “succeeded” or “failed” + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`RevenueWithdrawalStatePending` or :class:`RevenueWithdrawalStateSucceeded` or :class:`RevenueWithdrawalStateFailed` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + if obj["type"] == "pending": + return RevenueWithdrawalStatePending.de_json(obj) + elif obj["type"] == "succeeded": + return RevenueWithdrawalStateSucceeded.de_json(obj) + elif obj["type"] == "failed": + return RevenueWithdrawalStateFailed.de_json(obj) + return None + + +class RevenueWithdrawalStatePending(RevenueWithdrawalState): + """ + The withdrawal is in progress. + + Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatepending + + :param type: Type of the state, always “pending” + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`RevenueWithdrawalStatePending` + """ + + def __init__(self, type, **kwargs): + self.type: str = type + + +class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState): + """ + The withdrawal succeeded. + + Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatesucceeded + + :param type: Type of the state, always “succeeded” + :type type: :obj:`str` + + :param date: Date the withdrawal was completed in Unix time + :type date: :obj:`int` + + :param url: An HTTPS URL that can be used to see transaction details + :type url: :obj:`str` + + :return: Instance of the class + :rtype: :class:`RevenueWithdrawalStateSucceeded` + """ + + def __init__(self, type, date, url, **kwargs): + self.type: str = type + self.date: int = date + self.url: str = url + + +class RevenueWithdrawalStateFailed(RevenueWithdrawalState): + """ + The withdrawal failed and the transaction was refunded. + + Telegram documentation: https://core.telegram.org/bots/api#revenuewithdrawalstatefailed + + :param type: Type of the state, always “failed” + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`RevenueWithdrawalStateFailed` + """ + + def __init__(self, type, **kwargs): + self.type: str = type + + +class TransactionPartner(JsonDeserializable): + """ + This object describes the source of a transaction, or its recipient for outgoing transactions. Currently, it can be one of + TransactionPartnerFragment + TransactionPartnerUser + TransactionPartnerOther + + Telegram documentation: https://core.telegram.org/bots/api#transactionpartner + + :param type: Type of the transaction partner + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`TransactionPartnerFragment` or :class:`TransactionPartnerUser` or :class:`TransactionPartnerOther` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + if obj["type"] == "fragment": + return TransactionPartnerFragment.de_json(obj) + elif obj["type"] == "user": + return TransactionPartnerUser.de_json(obj) + elif obj["type"] == "other": + return TransactionPartnerOther.de_json(obj) + +class TransactionPartnerFragment(TransactionPartner): + """ + Describes a withdrawal transaction with Fragment. + + Telegram documentation: https://core.telegram.org/bots/api#transactionpartnerfragment + + :param type: Type of the transaction partner, always “fragment” + :type type: :obj:`str` + + :param withdrawal_state: Optional. State of the transaction if the transaction is outgoing + :type withdrawal_state: :class:`RevenueWithdrawalState` + + :return: Instance of the class + :rtype: :class:`TransactionPartnerFragment` + + """ + + def __init__(self, type, withdrawal_state=None, **kwargs): + self.type: str = type + self.withdrawal_state: Optional[RevenueWithdrawalState] = withdrawal_state + + +class TransactionPartnerUser(TransactionPartner): + """ + Describes a transaction with a user. + + Telegram documentation: https://core.telegram.org/bots/api#transactionpartneruser + + :param type: Type of the transaction partner, always “user” + :type type: :obj:`str` + + :param user: Information about the user + :type user: :class:`User` + + :return: Instance of the class + :rtype: :class:`TransactionPartnerUser` + """ + + def __init__(self, type, user, **kwargs): + self.type: str = type + self.user: User = user + +class TransactionPartnerOther(TransactionPartner): + """ + Describes a transaction with an unknown source or recipient. + + Telegram documentation: https://core.telegram.org/bots/api#transactionpartnerother + + :param type: Type of the transaction partner, always “other” + :type type: :obj:`str` + + :return: Instance of the class + :rtype: :class:`TransactionPartnerOther` + """ + + def __init__(self, type, **kwargs): + self.type: str = type + + +class StarTransaction(JsonDeserializable): + """ + Describes a Telegram Star transaction. + + Telegram documentation: https://core.telegram.org/bots/api#startransaction + + :param id: Unique identifier of the transaction. Coincides with the identifer of the original transaction for refund transactions. Coincides with SuccessfulPayment.telegram_payment_charge_id for successful incoming payments from users. + :type id: :obj:`str` + + :param amount: Number of Telegram Stars transferred by the transaction + :type amount: :obj:`int` + + :param date: Date the transaction was created in Unix time + :type date: :obj:`int` + + :param source: Optional. Source of an incoming transaction (e.g., a user purchasing goods or services, Fragment refunding a failed withdrawal). Only for incoming transactions + :type source: :class:`TransactionPartner` + + :param receiver: Optional. Receiver of an outgoing transaction (e.g., a user for a purchase refund, Fragment for a withdrawal). Only for outgoing transactions + :type receiver: :class:`TransactionPartner` + + :return: Instance of the class + :rtype: :class:`StarTransaction` + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + if 'source' in obj: + obj['source'] = TransactionPartner.de_json(obj['source']) + if 'receiver' in obj: + obj['receiver'] = TransactionPartner.de_json(obj['receiver']) + return cls(**obj) + + def __init__(self, id, amount, date, source=None, receiver=None, **kwargs): + self.id: str = id + self.amount: int = amount + self.date: int = date + self.source: Optional[TransactionPartner] = source + self.receiver: Optional[TransactionPartner] = receiver + + +class StarTransactions(JsonDeserializable): + """ + Contains a list of Telegram Star transactions. + + Telegram documentation: https://core.telegram.org/bots/api#startransactions + + :param transactions: The list of transactions + :type transactions: :obj:`list` of :class:`StarTransaction` + + :return: Instance of the class + :rtype: :class:`StarTransactions` + + """ + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['transactions'] = [StarTransaction.de_json(transaction) for transaction in obj['transactions']] + return cls(**obj) + + def __init__(self, transactions, **kwargs): + self.transactions: List[StarTransaction] = transactions From dbe9e3232b04242c5da099885d7e3638867a00d1 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 18 Jun 2024 16:59:24 +0500 Subject: [PATCH 3/6] Added the method getStarTransactions that can be used to get the list of all Telegram Star transactions for the bot. --- telebot/__init__.py | 21 +++++++++++++++++++++ telebot/apihelper.py | 10 ++++++++++ telebot/async_telebot.py | 19 +++++++++++++++++++ telebot/asyncio_helper.py | 8 ++++++++ 4 files changed, 58 insertions(+) diff --git a/telebot/__init__.py b/telebot/__init__.py index b70016506..b43ea89c8 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -5478,6 +5478,27 @@ def answer_pre_checkout_query( """ return apihelper.answer_pre_checkout_query( self.token, pre_checkout_query_id, ok, error_message=error_message) + + + def get_star_transactions(self, offset: Optional[int]=None, limit: Optional[int]=None) -> types.StarTransactions: + """ + Returns the bot's Telegram Star transactions in chronological order. On success, returns a StarTransactions object. + + Telegram documentation: https://core.telegram.org/bots/api#getstartransactions + + :param offset: Number of transactions to skip in the response + :type offset: :obj:`int` + + :param limit: The maximum number of transactions to be retrieved. Values between 1-100 are accepted. Defaults to 100. + :type limit: :obj:`int` + + :return: On success, returns a StarTransactions object. + :rtype: :obj:`types.StarTransactions` + """ + return types.StarTransactions.de_json( + apihelper.get_star_transactions(self.token, offset=offset, limit=limit) + ) + def refund_star_payment(self, user_id: int, telegram_payment_charge_id: str) -> bool: """ diff --git a/telebot/apihelper.py b/telebot/apihelper.py index cb0c77467..59039ce56 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1667,6 +1667,16 @@ def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_message=No payload['error_message'] = error_message return _make_request(token, method_url, params=payload) +def get_star_transactions(token, offset=None, limit=None): + method_url = 'getStarTransactions' + payload = {} + if offset: + payload['offset'] = offset + if limit: + payload['limit'] = limit + return _make_request(token, method_url, params=payload) + + def refund_star_payment(token, user_id, telegram_payment_charge_id): method_url = 'refundStarPayment' payload = {'user_id': user_id, 'telegram_payment_charge_id': telegram_payment_charge_id} diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 6a7c5fe08..7fe6e48af 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -6802,6 +6802,25 @@ async def answer_pre_checkout_query( """ return await asyncio_helper.answer_pre_checkout_query(self.token, pre_checkout_query_id, ok, error_message) + + async def get_star_transactions(self, offset: Optional[int]=None, limit: Optional[int]=None) -> types.StarTransactions: + """ + Returns the bot's Telegram Star transactions in chronological order. + + Telegram documentation: https://core.telegram.org/bots/api#getstartransactions + + :param offset: Number of transactions to skip in the response + :type offset: :obj:`int` + + :param limit: The maximum number of transactions to be retrieved. Values between 1-100 are accepted. Defaults to 100. + :type limit: :obj:`int` + + :return: On success, returns a StarTransactions object. + :rtype: :obj:`types.StarTransactions` + """ + + return types.StarTransactions.de_json(await asyncio_helper.get_star_transactions(self.token, offset, limit)) + async def refund_star_payment(self, user_id: int, telegram_payment_charge_id: str) -> bool: """ Refunds a successful payment in Telegram Stars. Returns True on success. diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index e7838fbb4..077ed3e61 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -1646,6 +1646,14 @@ async def answer_pre_checkout_query(token, pre_checkout_query_id, ok, error_mess payload['error_message'] = error_message return await _process_request(token, method_url, params=payload) +async def get_star_transactions(token, offset=None, limit=None): + method_url = 'getStarTransactions' + payload = {} + if offset: + payload['offset'] = offset + if limit: + payload['limit'] = limit + return await _process_request(token, method_url, params=payload) async def refund_star_payment(token, user_id, telegram_payment_charge_id): method_url = 'refundStarPayment' From 67e2ec5fa0f75c05a1c76552969989aa4cf9d234 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 18 Jun 2024 17:10:46 +0500 Subject: [PATCH 4/6] Added the parameter business_connection_id to the methods editMessageText, editMessageMedia, editMessageCaption, editMessageLiveLocation, stopMessageLiveLocation and editMessageReplyMarkup, allowing the bot to edit business messages. --- telebot/__init__.py | 47 ++++++++++++++++++++++++++++++--------- telebot/apihelper.py | 24 +++++++++++++++----- telebot/async_telebot.py | 46 +++++++++++++++++++++++++++++--------- telebot/asyncio_helper.py | 24 +++++++++++++++----- 4 files changed, 107 insertions(+), 34 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index b43ea89c8..369ce77a3 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -3324,6 +3324,7 @@ def edit_message_live_location( heading: Optional[int]=None, proximity_alert_radius: Optional[int]=None, live_period: Optional[int]=None, + business_connection_id: Optional[str]=None ) -> types.Message or bool: """ Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly @@ -3366,6 +3367,9 @@ def edit_message_live_location( :param live_period: New period in seconds during which the location can be updated, starting from the message send date. If 0x7FFFFFFF is specified, then the location can be updated forever. Otherwise, the new value must not exceed the current live_period by more than a day, and the live location expiration date must remain within the next 90 days. If not specified, then live_period remains unchanged :type live_period: :obj:`int` + :param business_connection_id: Identifier of a business connection + :type business_connection_id: :obj:`str` + :return: On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. :rtype: :class:`telebot.types.Message` or bool """ @@ -3373,7 +3377,7 @@ def edit_message_live_location( apihelper.edit_message_live_location( self.token, latitude, longitude, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, reply_markup=reply_markup, timeout=timeout, horizontal_accuracy=horizontal_accuracy, heading=heading, - proximity_alert_radius=proximity_alert_radius, live_period=live_period) + proximity_alert_radius=proximity_alert_radius, live_period=live_period, business_connection_id=business_connection_id) ) @@ -3382,7 +3386,8 @@ def stop_message_live_location( message_id: Optional[int]=None, inline_message_id: Optional[str]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None, - timeout: Optional[int]=None) -> types.Message or bool: + timeout: Optional[int]=None, + business_connection_id: Optional[str]=None) -> types.Message or bool: """ Use this method to stop updating a live location message before live_period expires. On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned. @@ -3405,13 +3410,16 @@ def stop_message_live_location( :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` + :param business_connection_id: Identifier of a business connection + :type business_connection_id: :obj:`str` + :return: On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned. :rtype: :class:`telebot.types.Message` or bool """ return types.Message.de_json( apihelper.stop_message_live_location( self.token, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, - reply_markup=reply_markup, timeout=timeout) + reply_markup=reply_markup, timeout=timeout, business_connection_id=business_connection_id) ) @@ -4645,7 +4653,8 @@ def edit_message_text( entities: Optional[List[types.MessageEntity]]=None, disable_web_page_preview: Optional[bool]=None, # deprecated, for backward compatibility reply_markup: Optional[types.InlineKeyboardMarkup]=None, - link_preview_options : Optional[types.LinkPreviewOptions]=None) -> Union[types.Message, bool]: + link_preview_options : Optional[types.LinkPreviewOptions]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit text and game messages. @@ -4678,6 +4687,9 @@ def edit_message_text( :param link_preview_options: A JSON-serialized object for options used to automatically generate previews for links. :type link_preview_options: :obj:`LinkPreviewOptions` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ @@ -4704,7 +4716,8 @@ def edit_message_text( result = apihelper.edit_message_text( self.token, text, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, - parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options) + parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options, + business_connection_id=business_connection_id) if type(result) == bool: # if edit inline message return is bool not Message. return result @@ -4715,7 +4728,8 @@ def edit_message_media( self, media: Any, chat_id: Optional[Union[int, str]]=None, message_id: Optional[int]=None, inline_message_id: Optional[str]=None, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit animation, audio, document, photo, or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. @@ -4738,12 +4752,15 @@ def edit_message_media( :param reply_markup: A JSON-serialized object for an inline keyboard. :type reply_markup: :obj:`telebot.types.InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ result = apihelper.edit_message_media( self.token, media, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, - reply_markup=reply_markup) + reply_markup=reply_markup, business_connection_id=business_connection_id) if type(result) == bool: # if edit inline message return is bool not Message. return result @@ -4754,7 +4771,8 @@ def edit_message_reply_markup( self, chat_id: Optional[Union[int, str]]=None, message_id: Optional[int]=None, inline_message_id: Optional[str]=None, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit only the reply markup of messages. @@ -4772,12 +4790,15 @@ def edit_message_reply_markup( :param reply_markup: A JSON-serialized object for an inline keyboard. :type reply_markup: :obj:`InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ result = apihelper.edit_message_reply_markup( self.token, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, - reply_markup=reply_markup) + reply_markup=reply_markup, business_connection_id=business_connection_id) if type(result) == bool: return result @@ -5524,7 +5545,8 @@ def edit_message_caption( parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None, - show_caption_above_media: Optional[bool]=None) -> Union[types.Message, bool]: + show_caption_above_media: Optional[bool]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit captions of messages. @@ -5554,6 +5576,9 @@ def edit_message_caption( :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. :type show_caption_above_media: :obj:`bool` + :param business_connection_id: Identifier of the business connection to use for the message + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` | :obj:`bool` """ @@ -5562,7 +5587,7 @@ def edit_message_caption( result = apihelper.edit_message_caption( self.token, caption, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id, parse_mode=parse_mode, caption_entities=caption_entities, reply_markup=reply_markup, - show_caption_above_media=show_caption_above_media) + show_caption_above_media=show_caption_above_media, business_connection_id=business_connection_id) if type(result) == bool: return result diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 59039ce56..3d5d89bf4 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -594,7 +594,7 @@ def send_location( def edit_message_live_location( token, latitude, longitude, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, - timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None): + timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None, business_connection_id=None): method_url = r'editMessageLiveLocation' payload = {'latitude': latitude, 'longitude': longitude} if chat_id: @@ -615,12 +615,14 @@ def edit_message_live_location( payload['reply_markup'] = _convert_markup(reply_markup) if timeout: payload['timeout'] = timeout + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload) def stop_message_live_location( token, chat_id=None, message_id=None, - inline_message_id=None, reply_markup=None, timeout=None): + inline_message_id=None, reply_markup=None, timeout=None, business_connection_id=None): method_url = r'stopMessageLiveLocation' payload = {} if chat_id: @@ -633,6 +635,8 @@ def stop_message_live_location( payload['reply_markup'] = _convert_markup(reply_markup) if timeout: payload['timeout'] = timeout + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload) @@ -1379,7 +1383,7 @@ def unpin_all_chat_messages(token, chat_id): # Updating messages def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, - entities = None, reply_markup=None, link_preview_options=None): + entities = None, reply_markup=None, link_preview_options=None, business_connection_id=None): method_url = r'editMessageText' payload = {'text': text} if chat_id: @@ -1396,11 +1400,13 @@ def edit_message_text(token, text, chat_id=None, message_id=None, inline_message payload['reply_markup'] = _convert_markup(reply_markup) if link_preview_options is not None: payload['link_preview_options'] = link_preview_options.to_json() + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload, method='post') def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, - parse_mode=None, caption_entities=None,reply_markup=None, show_caption_above_media=None): + parse_mode=None, caption_entities=None,reply_markup=None, show_caption_above_media=None, business_connection_id=None): method_url = r'editMessageCaption' payload = {'caption': caption} if chat_id: @@ -1417,10 +1423,12 @@ def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_m payload['reply_markup'] = _convert_markup(reply_markup) if show_caption_above_media is not None: payload['show_caption_above_media'] = show_caption_above_media + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload, method='post') -def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None): +def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None): method_url = r'editMessageMedia' media_json, file = convert_input_media(media) payload = {'media': media_json} @@ -1432,10 +1440,12 @@ def edit_message_media(token, media, chat_id=None, message_id=None, inline_messa payload['inline_message_id'] = inline_message_id if reply_markup: payload['reply_markup'] = _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload, files=file, method='post' if file else 'get') -def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None): +def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None): method_url = r'editMessageReplyMarkup' payload = {} if chat_id: @@ -1446,6 +1456,8 @@ def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_messa payload['inline_message_id'] = inline_message_id if reply_markup: payload['reply_markup'] = _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload, method='post') diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index 7fe6e48af..a6517a7c7 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -4724,6 +4724,7 @@ async def edit_message_live_location( heading: Optional[int]=None, proximity_alert_radius: Optional[int]=None, live_period: Optional[int]=None, + business_connection_id: Optional[str]=None ) -> types.Message: """ Use this method to edit live location messages. A location can be edited until its live_period expires or editing is explicitly @@ -4766,6 +4767,9 @@ async def edit_message_live_location( :param live_period: New period in seconds during which the location can be updated, starting from the message send date. If 0x7FFFFFFF is specified, then the location can be updated forever. Otherwise, the new value must not exceed the current live_period by more than a day, and the live location expiration date must remain within the next 90 days. If not specified, then live_period remains unchanged :type live_period: :obj:`int` + :param business_connection_id: Identifier of a business connection, in which the message will be edited + :type business_connection_id: :obj:`str` + :return: On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. :rtype: :class:`telebot.types.Message` or bool """ @@ -4773,7 +4777,7 @@ async def edit_message_live_location( await asyncio_helper.edit_message_live_location( self.token, latitude, longitude, chat_id, message_id, inline_message_id, reply_markup, timeout, - horizontal_accuracy, heading, proximity_alert_radius, live_period=live_period) + horizontal_accuracy, heading, proximity_alert_radius, live_period=live_period, business_connection_id=business_connection_id) ) async def stop_message_live_location( @@ -4781,7 +4785,8 @@ async def stop_message_live_location( message_id: Optional[int]=None, inline_message_id: Optional[str]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None, - timeout: Optional[int]=None) -> types.Message: + timeout: Optional[int]=None, + business_connection_id: Optional[str]=None) -> types.Message: """ Use this method to stop updating a live location message before live_period expires. On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned. @@ -4804,12 +4809,15 @@ async def stop_message_live_location( :param timeout: Timeout in seconds for the request. :type timeout: :obj:`int` + :param business_connection_id: Identifier of a business connection, in which the message will be edited + :type business_connection_id: :obj:`str` + :return: On success, if the message is not an inline message, the edited Message is returned, otherwise True is returned. :rtype: :class:`telebot.types.Message` or bool """ return types.Message.de_json( await asyncio_helper.stop_message_live_location( - self.token, chat_id, message_id, inline_message_id, reply_markup, timeout)) + self.token, chat_id, message_id, inline_message_id, reply_markup, timeout, business_connection_id)) async def send_venue( self, chat_id: Union[int, str], @@ -6000,7 +6008,8 @@ async def edit_message_text( entities: Optional[List[types.MessageEntity]]=None, disable_web_page_preview: Optional[bool]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None, - link_preview_options: Optional[types.LinkPreviewOptions]=None) -> Union[types.Message, bool]: + link_preview_options: Optional[types.LinkPreviewOptions]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit text and game messages. @@ -6033,6 +6042,9 @@ async def edit_message_text( :param link_preview_options: A JSON-serialized object for options used to automatically generate Telegram link previews for messages. :type link_preview_options: :obj:`LinkPreviewOptions` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ @@ -6058,7 +6070,7 @@ async def edit_message_text( link_preview_options = types.LinkPreviewOptions(is_disabled=self.disable_web_page_preview) result = await asyncio_helper.edit_message_text(self.token, text, chat_id, message_id, inline_message_id, parse_mode, - entities, reply_markup, link_preview_options) + entities, reply_markup, link_preview_options, business_connection_id) if type(result) == bool: # if edit inline message return is bool not Message. return result return types.Message.de_json(result) @@ -6067,7 +6079,8 @@ async def edit_message_media( self, media: Any, chat_id: Optional[Union[int, str]]=None, message_id: Optional[int]=None, inline_message_id: Optional[str]=None, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit animation, audio, document, photo, or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. @@ -6090,10 +6103,13 @@ async def edit_message_media( :param reply_markup: A JSON-serialized object for an inline keyboard. :type reply_markup: :obj:`telebot.types.InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ - result = await asyncio_helper.edit_message_media(self.token, media, chat_id, message_id, inline_message_id, reply_markup) + result = await asyncio_helper.edit_message_media(self.token, media, chat_id, message_id, inline_message_id, reply_markup, business_connection_id) if type(result) == bool: # if edit inline message return is bool not Message. return result return types.Message.de_json(result) @@ -6102,7 +6118,8 @@ async def edit_message_reply_markup( self, chat_id: Optional[Union[int, str]]=None, message_id: Optional[int]=None, inline_message_id: Optional[str]=None, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> Union[types.Message, bool]: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit only the reply markup of messages. @@ -6120,10 +6137,13 @@ async def edit_message_reply_markup( :param reply_markup: A JSON-serialized object for an inline keyboard. :type reply_markup: :obj:`InlineKeyboardMarkup` or :obj:`ReplyKeyboardMarkup` or :obj:`ReplyKeyboardRemove` or :obj:`ForceReply` + :param business_connection_id: Unique identifier of the business connection + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` or :obj:`bool` """ - result = await asyncio_helper.edit_message_reply_markup(self.token, chat_id, message_id, inline_message_id, reply_markup) + result = await asyncio_helper.edit_message_reply_markup(self.token, chat_id, message_id, inline_message_id, reply_markup, business_connection_id) if type(result) == bool: return result return types.Message.de_json(result) @@ -6845,7 +6865,8 @@ async def edit_message_caption( parse_mode: Optional[str]=None, caption_entities: Optional[List[types.MessageEntity]]=None, reply_markup: Optional[types.InlineKeyboardMarkup]=None, - show_caption_above_media: Optional[bool]=None) -> Union[types.Message, bool]: + show_caption_above_media: Optional[bool]=None, + business_connection_id: Optional[str]=None) -> Union[types.Message, bool]: """ Use this method to edit captions of messages. @@ -6875,13 +6896,16 @@ async def edit_message_caption( :param show_caption_above_media: Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. :type show_caption_above_media: :obj:`bool` + :param business_connection_id: Identifier of the business connection to send the message through + :type business_connection_id: :obj:`str` + :return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned. :rtype: :obj:`types.Message` | :obj:`bool` """ parse_mode = self.parse_mode if (parse_mode is None) else parse_mode result = await asyncio_helper.edit_message_caption(self.token, caption, chat_id, message_id, inline_message_id, - parse_mode, caption_entities, reply_markup, show_caption_above_media=show_caption_above_media) + parse_mode, caption_entities, reply_markup, show_caption_above_media=show_caption_above_media, business_connection_id=business_connection_id) if type(result) == bool: return result return types.Message.de_json(result) diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 077ed3e61..0d09a052a 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -580,7 +580,7 @@ async def send_location( async def edit_message_live_location( token, latitude, longitude, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, - timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None): + timeout=None, horizontal_accuracy=None, heading=None, proximity_alert_radius=None, live_period=None, business_connection_id=None): method_url = r'editMessageLiveLocation' payload = {'latitude': latitude, 'longitude': longitude} if chat_id: @@ -601,12 +601,14 @@ async def edit_message_live_location( payload['reply_markup'] = await _convert_markup(reply_markup) if timeout: payload['timeout'] = timeout + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload) async def stop_message_live_location( token, chat_id=None, message_id=None, - inline_message_id=None, reply_markup=None, timeout=None): + inline_message_id=None, reply_markup=None, timeout=None, business_connection_id=None): method_url = r'stopMessageLiveLocation' payload = {} if chat_id: @@ -619,6 +621,8 @@ async def stop_message_live_location( payload['reply_markup'] = await _convert_markup(reply_markup) if timeout: payload['timeout'] = timeout + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload) @@ -1357,7 +1361,7 @@ async def unpin_all_chat_messages(token, chat_id): # Updating messages async def edit_message_text(token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, - entities = None, reply_markup=None, link_preview_options=None): + entities = None, reply_markup=None, link_preview_options=None, business_connection_id=None): method_url = r'editMessageText' payload = {'text': text} if chat_id: @@ -1374,11 +1378,13 @@ async def edit_message_text(token, text, chat_id=None, message_id=None, inline_m payload['reply_markup'] = await _convert_markup(reply_markup) if link_preview_options is not None: payload['link_preview_options'] = link_preview_options.to_json() + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload, method='post') async def edit_message_caption(token, caption, chat_id=None, message_id=None, inline_message_id=None, - parse_mode=None, caption_entities=None,reply_markup=None, show_caption_above_media=None): + parse_mode=None, caption_entities=None,reply_markup=None, show_caption_above_media=None, business_connection_id=None): method_url = r'editMessageCaption' payload = {'caption': caption} if chat_id: @@ -1395,10 +1401,12 @@ async def edit_message_caption(token, caption, chat_id=None, message_id=None, in payload['reply_markup'] = await _convert_markup(reply_markup) if show_caption_above_media is not None: payload['show_caption_above_media'] = show_caption_above_media + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload, method='post') -async def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None): +async def edit_message_media(token, media, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None): method_url = r'editMessageMedia' media_json, file = await convert_input_media(media) payload = {'media': media_json} @@ -1410,10 +1418,12 @@ async def edit_message_media(token, media, chat_id=None, message_id=None, inline payload['inline_message_id'] = inline_message_id if reply_markup: payload['reply_markup'] = await _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload, files=file, method='post' if file else 'get') -async def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None): +async def edit_message_reply_markup(token, chat_id=None, message_id=None, inline_message_id=None, reply_markup=None, business_connection_id=None): method_url = r'editMessageReplyMarkup' payload = {} if chat_id: @@ -1424,6 +1434,8 @@ async def edit_message_reply_markup(token, chat_id=None, message_id=None, inline payload['inline_message_id'] = inline_message_id if reply_markup: payload['reply_markup'] = await _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload, method='post') From c7130d5572128fa35a7f94c9bf8406466ae2f348 Mon Sep 17 00:00:00 2001 From: _run Date: Tue, 18 Jun 2024 17:12:38 +0500 Subject: [PATCH 5/6] Added the parameter business_connection_id to the method stopPoll, allowing the bot to stop polls it sent on behalf of a business account. --- telebot/__init__.py | 8 ++++++-- telebot/apihelper.py | 4 +++- telebot/async_telebot.py | 8 ++++++-- telebot/asyncio_helper.py | 4 +++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/telebot/__init__.py b/telebot/__init__.py index 369ce77a3..07cda06ae 100644 --- a/telebot/__init__.py +++ b/telebot/__init__.py @@ -5418,7 +5418,8 @@ def send_poll( def stop_poll( self, chat_id: Union[int, str], message_id: int, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> types.Poll: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> types.Poll: """ Use this method to stop a poll which was sent by the bot. On success, the stopped Poll is returned. @@ -5433,11 +5434,14 @@ def stop_poll( :param reply_markup: A JSON-serialized object for a new message markup. :type reply_markup: :obj:`InlineKeyboardMarkup` + :param business_connection_id: Identifier of the business connection to use for the poll + :type business_connection_id: :obj:`str` + :return: On success, the stopped Poll is returned. :rtype: :obj:`types.Poll` """ return types.Poll.de_json( - apihelper.stop_poll(self.token, chat_id, message_id, reply_markup=reply_markup) + apihelper.stop_poll(self.token, chat_id, message_id, reply_markup=reply_markup, business_connection_id=business_connection_id) ) diff --git a/telebot/apihelper.py b/telebot/apihelper.py index 3d5d89bf4..d6a372cba 100644 --- a/telebot/apihelper.py +++ b/telebot/apihelper.py @@ -1997,11 +1997,13 @@ def get_forum_topic_icon_stickers(token): method_url = r'getForumTopicIconStickers' return _make_request(token, method_url) -def stop_poll(token, chat_id, message_id, reply_markup=None): +def stop_poll(token, chat_id, message_id, reply_markup=None, business_connection_id=None): method_url = r'stopPoll' payload = {'chat_id': str(chat_id), 'message_id': message_id} if reply_markup: payload['reply_markup'] = _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return _make_request(token, method_url, params=payload) def edit_general_forum_topic(token, chat_id, name): diff --git a/telebot/async_telebot.py b/telebot/async_telebot.py index a6517a7c7..af677e5ef 100644 --- a/telebot/async_telebot.py +++ b/telebot/async_telebot.py @@ -6746,7 +6746,8 @@ async def send_poll( async def stop_poll( self, chat_id: Union[int, str], message_id: int, - reply_markup: Optional[types.InlineKeyboardMarkup]=None) -> types.Poll: + reply_markup: Optional[types.InlineKeyboardMarkup]=None, + business_connection_id: Optional[str]=None) -> types.Poll: """ Use this method to stop a poll which was sent by the bot. On success, the stopped Poll is returned. @@ -6761,10 +6762,13 @@ async def stop_poll( :param reply_markup: A JSON-serialized object for a new message markup. :type reply_markup: :obj:`InlineKeyboardMarkup` + :param business_connection_id: Identifier of the business connection to send the message through + :type business_connection_id: :obj:`str` + :return: On success, the stopped Poll is returned. :rtype: :obj:`types.Poll` """ - return types.Poll.de_json(await asyncio_helper.stop_poll(self.token, chat_id, message_id, reply_markup)) + return types.Poll.de_json(await asyncio_helper.stop_poll(self.token, chat_id, message_id, reply_markup, business_connection_id)) async def answer_shipping_query( self, shipping_query_id: str, ok: bool, diff --git a/telebot/asyncio_helper.py b/telebot/asyncio_helper.py index 0d09a052a..ef755630f 100644 --- a/telebot/asyncio_helper.py +++ b/telebot/asyncio_helper.py @@ -2084,11 +2084,13 @@ def wrapper(key, val): return wrapper -async def stop_poll(token, chat_id, message_id, reply_markup=None): +async def stop_poll(token, chat_id, message_id, reply_markup=None, business_connection_id=None): method_url = r'stopPoll' payload = {'chat_id': str(chat_id), 'message_id': message_id} if reply_markup: payload['reply_markup'] = await _convert_markup(reply_markup) + if business_connection_id: + payload['business_connection_id'] = business_connection_id return await _process_request(token, method_url, params=payload) # exceptions From e256a716965ca13a77d6805a842e7d07417bc48d Mon Sep 17 00:00:00 2001 From: _run Date: Thu, 20 Jun 2024 20:05:31 +0500 Subject: [PATCH 6/6] Added de_json classes for types --- telebot/types.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/telebot/types.py b/telebot/types.py index fe92a6ff0..5d69af0ff 100644 --- a/telebot/types.py +++ b/telebot/types.py @@ -10123,6 +10123,12 @@ class RevenueWithdrawalStatePending(RevenueWithdrawalState): def __init__(self, type, **kwargs): self.type: str = type + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + class RevenueWithdrawalStateSucceeded(RevenueWithdrawalState): """ @@ -10148,6 +10154,13 @@ def __init__(self, type, date, url, **kwargs): self.date: int = date self.url: str = url + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + class RevenueWithdrawalStateFailed(RevenueWithdrawalState): """ @@ -10165,6 +10178,12 @@ class RevenueWithdrawalStateFailed(RevenueWithdrawalState): def __init__(self, type, **kwargs): self.type: str = type + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + class TransactionPartner(JsonDeserializable): """ @@ -10214,6 +10233,15 @@ def __init__(self, type, withdrawal_state=None, **kwargs): self.type: str = type self.withdrawal_state: Optional[RevenueWithdrawalState] = withdrawal_state + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + if 'withdrawal_state' in obj: + obj['withdrawal_state'] = RevenueWithdrawalState.de_json(obj['withdrawal_state']) + return cls(**obj) + + class TransactionPartnerUser(TransactionPartner): """ @@ -10234,6 +10262,14 @@ class TransactionPartnerUser(TransactionPartner): def __init__(self, type, user, **kwargs): self.type: str = type self.user: User = user + + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + obj['user'] = User.de_json(obj['user']) + return cls(**obj) + class TransactionPartnerOther(TransactionPartner): """ @@ -10251,6 +10287,13 @@ class TransactionPartnerOther(TransactionPartner): def __init__(self, type, **kwargs): self.type: str = type + @classmethod + def de_json(cls, json_string): + if json_string is None: return None + obj = cls.check_json(json_string) + return cls(**obj) + + class StarTransaction(JsonDeserializable): """