diff --git a/include/tgbotxx/Api.hpp b/include/tgbotxx/Api.hpp index 6de74c831..f6b7107b4 100644 --- a/include/tgbotxx/Api.hpp +++ b/include/tgbotxx/Api.hpp @@ -1452,6 +1452,31 @@ namespace tgbotxx { /// @ref https://core.telegram.org/bots/api#getwebhookinfo Ptr getWebhookInfo() const; + public: /// Updating messages + /// The following methods allow you to change an existing message in the message history instead of sending a new one with a result of an action. + /// This is most useful for messages with inline keyboards using callback queries, but can also help reduce clutter in conversations with regular chat bots. + /// Please note, that it is currently only possible to edit messages without reply_markup or with inline keyboards. + + /// @brief Use this method to edit text and game messages. + /// @param text New text of the message, 1-4096 characters after entities parsing + /// @param chatId Optional. Required if inlineMessageId is not specified. Unique identifier for the target chat or username of the target channel (in the format @channelusername) + /// @param messageId Optional. Required if inlineMessageId is not specified. Identifier of the message to edit + /// @param inlineMessageId Optional. Required if chatId and messageId are not specified. Identifier of the inline message + /// @param parseMode Optional. Mode for parsing entities in the message text. See https://core.telegram.org/bots/api#formatting-options for more details. + /// @param entities Optional. List of special entities that appear in message text, which can be specified instead of parseMode + /// @param disableWebPagePreview Optional. Disables link previews for links in this message + /// @param replyMarkup Optional. A JSON-serialized object for an inline keyboard. + /// @return On success, if the edited message is not an inline message, the edited Message is returned, otherwise nullptr is returned. + /// @ref https://core.telegram.org/bots/api#editmessagetext + Ptr editMessageText(const std::string& text, + const std::variant& chatId = 0, + std::int32_t messageId = 0, + std::int32_t inlineMessageId = 0, + const std::string& parseMode = "", + const std::vector>& entities = std::vector>(), + bool disableWebPagePreview = false, + const Ptr& replyMarkup = nullptr) const; + public: /// Inline mode methods. Methods and objects used in the inline mode are described in the Inline mode section. https://core.telegram.org/bots/api#inline-mode /// @brief Use this method to send answers to an inline query. diff --git a/src/Api.cpp b/src/Api.cpp index 9b63a200d..0a80b4c6a 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -1729,6 +1729,60 @@ Ptr Api::getWebhookInfo() const { return makePtr(webhookInfoObj); } +///////////////////////////////////////////////////////////////////////////////////////////////// + +Ptr Api::editMessageText(const std::string& text, + const std::variant& chatId, + std::int32_t messageId, + std::int32_t inlineMessageId, + const std::string& parseMode, + const std::vector>& entities, + bool disableWebPagePreview, + const Ptr& replyMarkup) const { + + + cpr::Multipart data{}; + data.parts.reserve(8); + data.parts.emplace_back("text", text); + switch (chatId.index()) { + case 0: // std::int64_t + if (std::int64_t chatIdInt = std::get(chatId); chatIdInt != 0) { + data.parts.emplace_back("chat_id", std::to_string(chatIdInt)); + } + break; + case 1: // std::string + if (std::string chatIdStr = std::get(chatId); not chatIdStr.empty()) { + data.parts.emplace_back("chat_id", chatIdStr); + } + break; + default: + break; + } + if (messageId) + data.parts.emplace_back("message_id", messageId); + if (inlineMessageId) + data.parts.emplace_back("inline_message_id", inlineMessageId); + if (not parseMode.empty()) + data.parts.emplace_back("parse_mode", parseMode); + if (not entities.empty()) { + nl::json entitiesArray = nl::json::array(); + for (const Ptr& entity: entities) + entitiesArray.push_back(entity->toJson()); + data.parts.emplace_back("entities", entitiesArray.dump()); + } + if (disableWebPagePreview) + data.parts.emplace_back("disable_web_page_preview", disableWebPagePreview); + if (replyMarkup) + data.parts.emplace_back("reply_markup", replyMarkup->toJson().dump()); + + nl::json sentMessageObj = sendRequest("editMessageText", data); + if (sentMessageObj.contains("message_id")) { + Ptr message(new Message(sentMessageObj)); + return message; + } else { + return nullptr; + } +} ///////////////////////////////////////////////////////////////////////////////////////////////// bool Api::answerInlineQuery(const std::string& inlineQueryId, diff --git a/tests/manual_tests.cpp b/tests/manual_tests.cpp index fe031322c..ed5c708e2 100644 --- a/tests/manual_tests.cpp +++ b/tests/manual_tests.cpp @@ -85,7 +85,10 @@ class MyBot : public Bot { Ptr showAdministratorRights(new BotCommand()); showAdministratorRights->command = "/show_administrator_rights"; showAdministratorRights->description = "Display bot's default administrator rights in JSON"; - getApi()->setMyCommands({greet, stop, photo, buttons, audio, document, animation, voice, mediaGroup, location, userProfilePhotos, ban, poll, quiz, webhookInfo, botName, menuButtonWebApp, menuButtonDefault, showAdministratorRights}); // The above commands will be shown in the bot chat menu (bottom left) + Ptr editMessageText(new BotCommand()); + editMessageText->command = "/edit_message_text"; + editMessageText->description = "You will receive a message that its text will be edited every second for 10 seconds."; + getApi()->setMyCommands({greet, stop, photo, buttons, audio, document, animation, voice, mediaGroup, location, userProfilePhotos, ban, poll, quiz, webhookInfo, botName, menuButtonWebApp, menuButtonDefault, showAdministratorRights, editMessageText}); // The above commands will be shown in the bot chat menu (bottom left) std::cout << __func__ << ": " << api()->getMyName()->name << " bot started!" << std::endl; } @@ -263,6 +266,16 @@ class MyBot : public Bot { } else if (message->text == "/show_administrator_rights") { Ptr chatAdministratorRights = api()->getMyDefaultAdministratorRights(); api()->sendMessage(message->chat->id, chatAdministratorRights->toJson().dump(2)); + } else if (message->text == "/edit_message_text") { + Ptr originalMessage = api()->sendMessage(message->chat->id, "Progress started..."); + for(int i = 0; i <= 100; i += 10) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::ostringstream oss{}; + oss << "Progress: " << i << '/' << 100; + api()->editMessageText(oss.str(), originalMessage->chat->id, originalMessage->messageId); + } + api()->editMessageText("Done.", originalMessage->chat->id, originalMessage->messageId); + } }