From 7b72d7a35fce82049fa63444b0ce5f2a3fc22129 Mon Sep 17 00:00:00 2001 From: llnulldisk <48621230+llnulldisk@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:43:12 +0200 Subject: [PATCH 01/11] Update to Bot API 6.6 --- README.md | 10 +- include/tgbot/Api.h | 200 +++++++--- include/tgbot/TgTypeParser.h | 12 + include/tgbot/types/Animation.h | 2 +- include/tgbot/types/Audio.h | 2 +- include/tgbot/types/BotDescription.h | 25 ++ include/tgbot/types/BotShortDescription.h | 25 ++ include/tgbot/types/Document.h | 2 +- .../tgbot/types/InlineQueryResultArticle.h | 6 +- .../tgbot/types/InlineQueryResultContact.h | 6 +- .../tgbot/types/InlineQueryResultDocument.h | 6 +- include/tgbot/types/InlineQueryResultGif.h | 4 +- .../tgbot/types/InlineQueryResultLocation.h | 6 +- .../tgbot/types/InlineQueryResultMpeg4Gif.h | 4 +- include/tgbot/types/InlineQueryResultPhoto.h | 2 +- include/tgbot/types/InlineQueryResultVenue.h | 6 +- include/tgbot/types/InlineQueryResultVideo.h | 2 +- include/tgbot/types/InputMediaAnimation.h | 2 +- include/tgbot/types/InputMediaAudio.h | 2 +- include/tgbot/types/InputMediaDocument.h | 2 +- include/tgbot/types/InputMediaVideo.h | 2 +- include/tgbot/types/InputSticker.h | 45 +++ include/tgbot/types/Sticker.h | 7 +- include/tgbot/types/StickerSet.h | 2 +- include/tgbot/types/Video.h | 2 +- include/tgbot/types/VideoNote.h | 2 +- src/Api.cpp | 374 ++++++++++++------ src/TgTypeParser.cpp | 198 +++++++--- 28 files changed, 697 insertions(+), 261 deletions(-) create mode 100644 include/tgbot/types/BotDescription.h create mode 100644 include/tgbot/types/BotShortDescription.h create mode 100644 include/tgbot/types/InputSticker.h diff --git a/README.md b/README.md index 9d128e877..382bd3d1a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ Documentation is located [here](http://reo7sp.github.io/tgbot-cpp). ## State -- [x] Telegram Bot API 6.5 +- [x] Telegram Bot API 6.6 +- [] [Deep Linking](https://core.telegram.org/bots/features#deep-linking) ## Sample @@ -64,7 +65,12 @@ Dependencies: You can install dependencies on Debian-based distibutives with these commands: ```sh -sudo apt-get install g++ make binutils cmake libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev +sudo apt install g++ make binutils cmake libboost-system-dev libssl-dev zlib1g-dev libcurl4-openssl-dev +``` + +Optionally, install the dependencies for testing and documenting +```sh +sudo apt install libboost-test-dev doxygen ``` You can compile and install the library with these commands: diff --git a/include/tgbot/Api.h b/include/tgbot/Api.h index b7a541a16..a30a9fef8 100644 --- a/include/tgbot/Api.h +++ b/include/tgbot/Api.h @@ -289,7 +289,7 @@ friend class Bot; * @param duration Optional. Duration of the audio in seconds * @param performer Optional. Performer * @param title Optional. Track name - * @param thumb Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files + * @param thumbnail Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files * @param replyToMessageId Optional. If the message is a reply, ID of the original message * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. * @param parseMode Optional. Mode for parsing entities in the audio caption. See https://core.telegram.org/bots/api#formatting-options for more details. @@ -307,7 +307,7 @@ friend class Bot; std::int32_t duration = 0, const std::string& performer = "", const std::string& title = "", - boost::variant thumb = "", + boost::variant thumbnail = "", std::int32_t replyToMessageId = 0, GenericReply::Ptr replyMarkup = nullptr, const std::string& parseMode = "", @@ -324,7 +324,7 @@ friend class Bot; * * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) * @param document File to send. Pass a fileId as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files - * @param thumb Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files + * @param thumbnail Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files * @param caption Optional. Document caption (may also be used when resending documents by fileId), 0-1024 characters after entities parsing * @param replyToMessageId Optional. If the message is a reply, ID of the original message * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -340,7 +340,7 @@ friend class Bot; */ Message::Ptr sendDocument(boost::variant chatId, boost::variant document, - boost::variant thumb = "", + boost::variant thumbnail = "", const std::string& caption = "", std::int32_t replyToMessageId = 0, GenericReply::Ptr replyMarkup = nullptr, @@ -363,7 +363,7 @@ friend class Bot; * @param duration Optional. Duration of sent video in seconds * @param width Optional. Video width * @param height Optional. Video height - * @param thumb Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files + * @param thumbnail Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files * @param caption Optional. Video caption (may also be used when resending videos by fileId), 0-1024 characters after entities parsing * @param replyToMessageId Optional. If the message is a reply, ID of the original message * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -383,7 +383,7 @@ friend class Bot; std::int32_t duration = 0, std::int32_t width = 0, std::int32_t height = 0, - boost::variant thumb = "", + boost::variant thumbnail = "", const std::string& caption = "", std::int32_t replyToMessageId = 0, GenericReply::Ptr replyMarkup = nullptr, @@ -405,7 +405,7 @@ friend class Bot; * @param duration Optional. Duration of sent animation in seconds * @param width Optional. Animation width * @param height Optional. Animation height - * @param thumb Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files + * @param thumbnail Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files * @param caption Optional. Animation caption (may also be used when resending animation by fileId), 0-1024 characters after entities parsing * @param replyToMessageId Optional. If the message is a reply, ID of the original message * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -424,7 +424,7 @@ friend class Bot; std::int32_t duration = 0, std::int32_t width = 0, std::int32_t height = 0, - boost::variant thumb = "", + boost::variant thumbnail = "", const std::string& caption = "", std::int32_t replyToMessageId = 0, GenericReply::Ptr replyMarkup = nullptr, @@ -481,7 +481,7 @@ friend class Bot; * @param disableNotification Optional. Sends the message silently. Users will receive a notification with no sound. * @param duration Optional. Duration of sent video in seconds * @param length Optional. Video width and height, i.e. diameter of the video message - * @param thumb Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files + * @param thumbnail Optional. Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . https://core.telegram.org/bots/api#sending-files * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. * @param allowSendingWithoutReply Optional. Pass True if the message should be sent even if the specified replied-to message is not found * @param protectContent Optional. Protects the contents of the sent message from forwarding and saving @@ -495,7 +495,7 @@ friend class Bot; bool disableNotification = false, std::int32_t duration = 0, std::int32_t length = 0, - boost::variant thumb = "", + boost::variant thumbnail = "", GenericReply::Ptr replyMarkup = nullptr, bool allowSendingWithoutReply = false, bool protectContent = false, @@ -1236,7 +1236,7 @@ friend class Bot; bool editForumTopic(boost::variant chatId, std::int32_t messageThreadId, const std::string& name = "", - boost::variant iconCustomEmojiId = 0) const; + boost::variant iconCustomEmojiId = 0) const; /** * @brief Use this method to close an open topic in a forum supergroup chat. @@ -1411,6 +1411,46 @@ friend class Bot; std::vector getMyCommands(BotCommandScope::Ptr scope = nullptr, const std::string& languageCode = "") const; + /** + * @brief Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. + * + * @param description Optional. New bot description; 0-512 characters. Pass an empty string to remove the dedicated description for the given language. + * @param languageCode Optional. A two-letter ISO 639-1 language code. If empty, the description will be applied to all users for whose language there is no dedicated description. + * + * @return Returns True on success. + */ + bool setMyDescription(const std::string& description = "", + const std::string& languageCode = "") const; + + /** + * @brief Use this method to get the current bot description for the given user language. + * + * @param languageCode Optional. A two-letter ISO 639-1 language code or an empty string + * + * @return Returns BotDescription on success. + */ + BotDescription::Ptr getMyDescription(const std::string& languageCode = "") const; + + /** + * @brief Use this method to change the bot's short description, which is shown on the bot's profile page and is sent together with the link when users share the bot. + * + * @param shortDescription Optional. New short description for the bot; 0-120 characters. Pass an empty string to remove the dedicated short description for the given language. + * @param languageCode Optional. A two-letter ISO 639-1 language code. If empty, the short description will be applied to all users for whose language there is no dedicated short description. + * + * @return Returns True on success. + */ + bool setMyShortDescription(const std::string& shortDescription = "", + const std::string& languageCode = "") const; + + /** + * @brief Use this method to get the current bot short description for the given user language. + * + * @param languageCode Optional. A two-letter ISO 639-1 language code or an empty string + * + * @return Returns BotShortDescription on success. + */ + BotShortDescription::Ptr getMyShortDescription(const std::string& languageCode = "") const; + /** * @brief Use this method to change the bot's menu button in a private chat, or the default menu button. * @@ -1434,7 +1474,7 @@ friend class Bot; /** * @brief Use this method to change the default administrator rights requested by the bot when it's added as an administrator to groups or channels. * - * These rights will be suggested to users, but they are are free to modify the list before adding the bot. + * These rights will be suggested to users, but they are free to modify the list before adding the bot. * * @param rights Optional. A JSON-serialized object describing new default administrator rights. If not specified, the default administrator rights will be cleared. * @param forChannels Optional. Pass True to change the default administrator rights of the bot in channels. Otherwise, the default administrator rights of the bot for groups and supergroups will be changed. @@ -1569,13 +1609,14 @@ friend class Bot; * @brief Use this method to send static .WEBP, animated .TGS, or video .WEBM stickers. * * @param chatId Unique identifier for the target chat or username of the target channel (in the format @channelusername) - * @param sticker Sticker to send. Pass a fileId as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files + * @param sticker Sticker to send. Pass a fileId as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP sticker from the Internet, or upload a new .WEBP or .TGS sticker using multipart/form-data. https://core.telegram.org/bots/api#sending-files. Video stickers can only be sent by a fileId. Animated stickers can't be sent via an HTTP URL. * @param replyToMessageId Optional. If the message is a reply, ID of the original message * @param replyMarkup Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. * @param disableNotification Optional. Sends the message silently. Users will receive a notification with no sound. * @param allowSendingWithoutReply Optional. Pass True if the message should be sent even if the specified replied-to message is not found * @param protectContent Optional. Protects the contents of the sent message from forwarding and saving * @param messageThreadId Optional. Unique identifier for the target message thread (topic) of the forum; for forum supergroups only + * @param emoji Optional. Emoji associated with the sticker; only for just uploaded stickers * * @return On success, the sent Message is returned. */ @@ -1586,7 +1627,8 @@ friend class Bot; bool disableNotification = false, bool allowSendingWithoutReply = false, bool protectContent = false, - std::int32_t messageThreadId = 0) const; + std::int32_t messageThreadId = 0, + const std::string& emoji = "") const; /** * @brief Use this method to get a sticker set. @@ -1607,69 +1649,58 @@ friend class Bot; std::vector getCustomEmojiStickers(const std::vector& customEmojiIds) const; /** - * @brief Use this method to upload a .PNG file with a sticker for later use in Api::createNewStickerSet and Api::addStickerToSet methods (can be used multiple times). + * @brief Use this method to upload a file with a sticker for later use in the Api::createNewStickerSet and Api::addStickerToSet methods (the file can be used multiple times). * * @param userId User identifier of sticker file owner - * @param pngSticker PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. https://core.telegram.org/bots/api#sending-files + * @param sticker A file with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. See https://core.telegram.org/stickers for technical requirements. https://core.telegram.org/bots/api#sending-files + * @param stickerFormat Format of the sticker, must be one of “static”, “animated”, “video” * * @return Returns the uploaded File on success. */ File::Ptr uploadStickerFile(std::int64_t userId, - InputFile::Ptr pngSticker) const; + InputFile::Ptr sticker, + const std::string& stickerFormat) const; /** * @brief Use this method to create a new sticker set owned by a user. * * The bot will be able to edit the sticker set thus created. - * You must use exactly one of the fields pngSticker, tgsSticker, or webmSticker. * * @param userId User identifier of created sticker set owner * @param name Short name of sticker set, to be used in t.me/addstickers/ URLs (e.g., animals). Can contain only English letters, digits and underscores. Must begin with a letter, can't contain consecutive underscores and must end in "_by_". is case insensitive. 1-64 characters. * @param title Sticker set title, 1-64 characters - * @param emojis One or more emoji corresponding to the sticker - * @param maskPosition Optional. A JSON-serialized object for position where the mask should be placed on faces - * @param pngSticker Optional. PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files - * @param tgsSticker Optional. TGS animation with the sticker, uploaded using multipart/form-data. See https://core.telegram.org/stickers#animated-sticker-requirements for technical requirements - * @param webmSticker Optional. WEBM video with the sticker, uploaded using multipart/form-data. See https://core.telegram.org/stickers#video-sticker-requirements for technical requirements - * @param stickerType Optional. Type of stickers in the set, pass “regular” or “mask”. Custom emoji sticker sets can't be created via the Bot API at the moment. By default, a regular sticker set is created. + * @param stickers A JSON-serialized list of 1-50 initial stickers to be added to the sticker set + * @param stickerFormat Format of stickers in the set, must be one of “static”, “animated”, “video” + * @param stickerType Optional. Type of stickers in the set, pass “regular”, “mask”, or “custom_emoji”. By default, a regular sticker set is created. + * @param needsRepainting Optional. Pass True if stickers in the sticker set must be repainted to the color of text when used in messages, the accent color if used as emoji status, white on chat photos, or another appropriate color based on context; for custom emoji sticker sets only * * @return Returns True on success. */ bool createNewStickerSet(std::int64_t userId, const std::string& name, const std::string& title, - const std::string& emojis, - MaskPosition::Ptr maskPosition = nullptr, - boost::variant pngSticker = "", - InputFile::Ptr tgsSticker = nullptr, - InputFile::Ptr webmSticker = nullptr, - const std::string& stickerType = "") const; + const std::vector& stickers, + const std::string& stickerFormat, + const std::string& stickerType = "", + bool needsRepainting = false) const; /** * @brief Use this method to add a new sticker to a set created by the bot. * - * You must use exactly one of the fields pngSticker, tgsSticker, or webmSticker. - * Animated stickers can be added to animated sticker sets and only to them. - * Animated sticker sets can have up to 50 stickers. + * The format of the added sticker must match the format of the other stickers in the set. + * Emoji sticker sets can have up to 200 stickers. + * Animated and video sticker sets can have up to 50 stickers. * Static sticker sets can have up to 120 stickers. * * @param userId User identifier of sticker set owner * @param name Sticker set name - * @param emojis One or more emoji corresponding to the sticker - * @param maskPosition Optional. A JSON-serialized object for position where the mask should be placed on faces - * @param pngSticker Optional. PNG image with the sticker, must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px. Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files - * @param tgsSticker Optional. TGS animation with the sticker, uploaded using multipart/form-data. See https://core.telegram.org/stickers#animated-sticker-requirements for technical requirements - * @param webmSticker Optional. WEBM video with the sticker, uploaded using multipart/form-data. See https://core.telegram.org/stickers#video-sticker-requirements for technical requirements + * @param sticker A JSON-serialized object with information about the added sticker. If exactly the same sticker had already been added to the set, then the set isn't changed. * * @return Returns True on success. */ bool addStickerToSet(std::int64_t userId, const std::string& name, - const std::string& emojis, - MaskPosition::Ptr maskPosition = nullptr, - boost::variant pngSticker = "", - InputFile::Ptr tgsSticker = nullptr, - InputFile::Ptr webmSticker = nullptr) const; + InputSticker::Ptr sticker) const; /** * @brief Use this method to move a sticker in a set created by the bot to a specific position. @@ -1692,20 +1723,89 @@ friend class Bot; bool deleteStickerFromSet(const std::string& sticker) const; /** - * @brief Use this method to set the thumbnail of a sticker set. + * @brief Use this method to change the list of emoji assigned to a regular or custom emoji sticker. + * + * The sticker must belong to a sticker set created by the bot. + * + * @param sticker File identifier of the sticker + * @param emojiList A JSON-serialized list of 1-20 emoji associated with the sticker + * + * @return Returns True on success. + */ + bool setStickerEmojiList(const std::string& sticker, + const std::vector& emojiList) const; + + /** + * @brief Use this method to change search keywords assigned to a regular or custom emoji sticker. + * + * The sticker must belong to a sticker set created by the bot. + * + * @param sticker File identifier of the sticker + * @param keywords Optional. A JSON-serialized list of 0-20 search keywords for the sticker with total length of up to 64 characters * - * Animated thumbnails can be set for animated sticker sets only. - * Video thumbnails can be set only for video sticker sets only. + * @return Returns True on success. + */ + bool setStickerKeywords(const std::string& sticker, + const std::vector& keywords = std::vector()) const; + + /** + * @brief Use this method to change the mask position of a mask sticker. + * + * The sticker must belong to a sticker set that was created by the bot. + * + * @param sticker File identifier of the sticker + * @param maskPosition A JSON-serialized object with the position where the mask should be placed on faces. Omit the parameter to remove the mask position. + * + * @return Returns True on success. + */ + bool setStickerMaskPosition(const std::string& sticker, + MaskPosition::Ptr maskPosition = nullptr) const; + + /** + * @brief Use this method to set the title of a created sticker set. + * + * @param name Sticker set name + * @param title Sticker set title, 1-64 characters + * + * @return Returns True on success. + */ + bool setStickerSetTitle(const std::string& name, + const std::string& title) const; + + /** + * @brief Use this method to set the thumbnail of a regular or mask sticker set. + * + * The format of the thumbnail file must match the format of the stickers in the set. * * @param name Sticker set name * @param userId User identifier of the sticker set owner - * @param thumb Optional. A PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS animation with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#animated-sticker-requirements for animated sticker technical requirements, or a WEBM video with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#video-sticker-requirements for video sticker technical requirements. Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files. Animated sticker set thumbnails can't be uploaded via HTTP URL. + * @param thumbnail Optional. A .WEBP or .PNG image with the thumbnail, must be up to 128 kilobytes in size and have a width and height of exactly 100px, or a .TGS animation with a thumbnail up to 32 kilobytes in size (see https://core.telegram.org/stickers#animated-sticker-requirements for animated sticker technical requirements), or a WEBM video with the thumbnail up to 32 kilobytes in size; see https://core.telegram.org/stickers#video-sticker-requirements for video sticker technical requirements. Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. https://core.telegram.org/bots/api#sending-files. Animated and video sticker set thumbnails can't be uploaded via HTTP URL. If omitted, then the thumbnail is dropped and the first sticker is used as the thumbnail. * * @return Returns True on success. */ - bool setStickerSetThumb(const std::string& name, - std::int64_t userId, - boost::variant thumb = "") const; + bool setStickerSetThumbnail(const std::string& name, + std::int64_t userId, + boost::variant thumbnail = "") const; + + /** + * @brief Use this method to set the thumbnail of a custom emoji sticker set. + * + * @param name Sticker set name + * @param customEmojiId Optional. Custom emoji identifier of a sticker from the sticker set; pass an empty string to drop the thumbnail and use the first sticker as the thumbnail. + * + * @return Returns True on success. + */ + bool setCustomEmojiStickerSetThumbnail(const std::string& name, + const std::string& customEmojiId = "") const; + + /** + * @brief Use this method to delete a sticker set that was created by the bot. + * + * @param name Sticker set name + * + * @return Returns True on success. + */ + bool deleteStickerSet(const std::string& name) const; /** * @brief Use this method to send answers to an inline query. diff --git a/include/tgbot/TgTypeParser.h b/include/tgbot/TgTypeParser.h index 191db5ad3..9f135fd6f 100644 --- a/include/tgbot/TgTypeParser.h +++ b/include/tgbot/TgTypeParser.h @@ -77,6 +77,8 @@ #include "tgbot/types/BotCommandScopeChat.h" #include "tgbot/types/BotCommandScopeChatAdministrators.h" #include "tgbot/types/BotCommandScopeChatMember.h" +#include "tgbot/types/BotDescription.h" +#include "tgbot/types/BotShortDescription.h" #include "tgbot/types/MenuButton.h" #include "tgbot/types/MenuButtonCommands.h" #include "tgbot/types/MenuButtonWebApp.h" @@ -91,6 +93,7 @@ #include "tgbot/types/Sticker.h" #include "tgbot/types/StickerSet.h" #include "tgbot/types/MaskPosition.h" +#include "tgbot/types/InputSticker.h" #include "tgbot/types/InlineQuery.h" #include "tgbot/types/InlineQueryResult.h" #include "tgbot/types/InlineQueryResultArticle.h" @@ -391,6 +394,12 @@ class TGBOT_API TgTypeParser { BotCommandScopeChatMember::Ptr parseJsonAndGetBotCommandScopeChatMember(const boost::property_tree::ptree& data) const; std::string parseBotCommandScopeChatMember(const BotCommandScopeChatMember::Ptr& object) const; + BotDescription::Ptr parseJsonAndGetBotDescription(const boost::property_tree::ptree& data) const; + std::string parseBotDescription(const BotDescription::Ptr& object) const; + + BotShortDescription::Ptr parseJsonAndGetBotShortDescription(const boost::property_tree::ptree& data) const; + std::string parseBotShortDescription(const BotShortDescription::Ptr& object) const; + MenuButton::Ptr parseJsonAndGetMenuButton(const boost::property_tree::ptree& data) const; std::string parseMenuButton(const MenuButton::Ptr& object) const; @@ -433,6 +442,9 @@ class TGBOT_API TgTypeParser { MaskPosition::Ptr parseJsonAndGetMaskPosition(const boost::property_tree::ptree& data) const; std::string parseMaskPosition(const MaskPosition::Ptr& object) const; + InputSticker::Ptr parseJsonAndGetInputSticker(const boost::property_tree::ptree& data) const; + std::string parseInputSticker(const InputSticker::Ptr& object) const; + InlineQuery::Ptr parseJsonAndGetInlineQuery(const boost::property_tree::ptree& data) const; std::string parseInlineQuery(const InlineQuery::Ptr& object) const; diff --git a/include/tgbot/types/Animation.h b/include/tgbot/types/Animation.h index 8d9688fb8..104b3e46f 100644 --- a/include/tgbot/types/Animation.h +++ b/include/tgbot/types/Animation.h @@ -47,7 +47,7 @@ class Animation { /** * @brief Optional. Animation thumbnail as defined by sender */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; /** * @brief Optional. Original animation filename as defined by sender diff --git a/include/tgbot/types/Audio.h b/include/tgbot/types/Audio.h index 5095e5c2b..1554735b5 100644 --- a/include/tgbot/types/Audio.h +++ b/include/tgbot/types/Audio.h @@ -66,7 +66,7 @@ class Audio { /** * @brief Optional. Thumbnail of the album cover to which the music file belongs */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; }; } diff --git a/include/tgbot/types/BotDescription.h b/include/tgbot/types/BotDescription.h new file mode 100644 index 000000000..1c769a4b4 --- /dev/null +++ b/include/tgbot/types/BotDescription.h @@ -0,0 +1,25 @@ +#ifndef TGBOT_BOTDESCRIPTION_H +#define TGBOT_BOTDESCRIPTION_H + +#include +#include + +namespace TgBot { + +/** + * @brief This object represents the bot's description. + * + * @ingroup types + */ +class BotDescription { +public: + typedef std::shared_ptr Ptr; + + /** + * @brief The bot's description + */ + std::string description; +}; +} + +#endif //TGBOT_BOTDESCRIPTION_H diff --git a/include/tgbot/types/BotShortDescription.h b/include/tgbot/types/BotShortDescription.h new file mode 100644 index 000000000..d3e33b30e --- /dev/null +++ b/include/tgbot/types/BotShortDescription.h @@ -0,0 +1,25 @@ +#ifndef TGBOT_BOTSHORTDESCRIPTION_H +#define TGBOT_BOTSHORTDESCRIPTION_H + +#include +#include + +namespace TgBot { + +/** + * @brief This object represents the bot's short description. + * + * @ingroup types + */ +class BotShortDescription { +public: + typedef std::shared_ptr Ptr; + + /** + * @brief The bot's short description + */ + std::string shortDescription; +}; +} + +#endif //TGBOT_BOTSHORTDESCRIPTION_H diff --git a/include/tgbot/types/Document.h b/include/tgbot/types/Document.h index 059307631..c42fe9aac 100644 --- a/include/tgbot/types/Document.h +++ b/include/tgbot/types/Document.h @@ -33,7 +33,7 @@ class Document { /** * @brief Optional. Document thumbnail as defined by sender */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; /** * @brief Optional. Original filename as defined by sender diff --git a/include/tgbot/types/InlineQueryResultArticle.h b/include/tgbot/types/InlineQueryResultArticle.h index 509a8d275..5f61f17f5 100644 --- a/include/tgbot/types/InlineQueryResultArticle.h +++ b/include/tgbot/types/InlineQueryResultArticle.h @@ -53,17 +53,17 @@ class InlineQueryResultArticle : public InlineQueryResult { /** * @brief Optional. Url of the thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Thumbnail width */ - std::int32_t thumbWidth; + std::int32_t thumbnailWidth; /** * @brief Optional. Thumbnail height */ - std::int32_t thumbHeight; + std::int32_t thumbnailHeight; }; } diff --git a/include/tgbot/types/InlineQueryResultContact.h b/include/tgbot/types/InlineQueryResultContact.h index 32894c906..b9cceaa6e 100644 --- a/include/tgbot/types/InlineQueryResultContact.h +++ b/include/tgbot/types/InlineQueryResultContact.h @@ -55,17 +55,17 @@ class InlineQueryResultContact : public InlineQueryResult { /** * @brief Optional. Url of the thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Thumbnail width */ - std::int32_t thumbWidth; + std::int32_t thumbnailWidth; /** * @brief Optinal. Thumbnail height */ - std::int32_t thumbHeight; + std::int32_t thumbnailHeight; }; } diff --git a/include/tgbot/types/InlineQueryResultDocument.h b/include/tgbot/types/InlineQueryResultDocument.h index 9e6758cb3..b86d50e30 100644 --- a/include/tgbot/types/InlineQueryResultDocument.h +++ b/include/tgbot/types/InlineQueryResultDocument.h @@ -74,17 +74,17 @@ class InlineQueryResultDocument : public InlineQueryResult { /** * @brief Optional. URL of the thumbnail (jpeg only) for the file */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Thumbnail width */ - std::int32_t thumbWidth; + std::int32_t thumbnailWidth; /** * @brief Optinal. Thumbnail height */ - std::int32_t thumbHeight; + std::int32_t thumbnailHeight; }; } diff --git a/include/tgbot/types/InlineQueryResultGif.h b/include/tgbot/types/InlineQueryResultGif.h index 05abe3676..a5115c97d 100644 --- a/include/tgbot/types/InlineQueryResultGif.h +++ b/include/tgbot/types/InlineQueryResultGif.h @@ -53,13 +53,13 @@ class InlineQueryResultGif : public InlineQueryResult { /** * @brief URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4”. * Defaults to “image/jpeg” */ - std::string thumbMimeType; + std::string thumbnailMimeType; /** * @brief Optional. Title for the result diff --git a/include/tgbot/types/InlineQueryResultLocation.h b/include/tgbot/types/InlineQueryResultLocation.h index a72350abe..01b7581b4 100644 --- a/include/tgbot/types/InlineQueryResultLocation.h +++ b/include/tgbot/types/InlineQueryResultLocation.h @@ -72,17 +72,17 @@ class InlineQueryResultLocation : public InlineQueryResult { /** * @brief Optional. Url of the thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Thumbnail width */ - std::int32_t thumbWidth; + std::int32_t thumbnailWidth; /** * @brief Optinal. Thumbnail height */ - std::int32_t thumbHeight; + std::int32_t thumbnailHeight; }; } diff --git a/include/tgbot/types/InlineQueryResultMpeg4Gif.h b/include/tgbot/types/InlineQueryResultMpeg4Gif.h index 7543c0053..cf6aed424 100644 --- a/include/tgbot/types/InlineQueryResultMpeg4Gif.h +++ b/include/tgbot/types/InlineQueryResultMpeg4Gif.h @@ -53,13 +53,13 @@ class InlineQueryResultMpeg4Gif : public InlineQueryResult { /** * @brief URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. MIME type of the thumbnail, must be one of “image/jpeg”, “image/gif”, or “video/mp4”. * Defaults to “image/jpeg” */ - std::string thumbMimeType; + std::string thumbnailMimeType; /** * @brief Optional. Title for the result diff --git a/include/tgbot/types/InlineQueryResultPhoto.h b/include/tgbot/types/InlineQueryResultPhoto.h index b6ecd764d..45e855e57 100644 --- a/include/tgbot/types/InlineQueryResultPhoto.h +++ b/include/tgbot/types/InlineQueryResultPhoto.h @@ -39,7 +39,7 @@ class InlineQueryResultPhoto : public InlineQueryResult { /** * @brief URL of the thumbnail for the photo */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Width of the photo diff --git a/include/tgbot/types/InlineQueryResultVenue.h b/include/tgbot/types/InlineQueryResultVenue.h index 7a9359172..ff721db56 100644 --- a/include/tgbot/types/InlineQueryResultVenue.h +++ b/include/tgbot/types/InlineQueryResultVenue.h @@ -77,17 +77,17 @@ class InlineQueryResultVenue : public InlineQueryResult { /** * @brief Optional. Url of the thumbnail for the result */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Optional. Thumbnail width */ - std::int32_t thumbWidth; + std::int32_t thumbnailWidth; /** * @brief Optinal. Thumbnail height */ - std::int32_t thumbHeight; + std::int32_t thumbnailHeight; }; } diff --git a/include/tgbot/types/InlineQueryResultVideo.h b/include/tgbot/types/InlineQueryResultVideo.h index ead630343..72350587b 100644 --- a/include/tgbot/types/InlineQueryResultVideo.h +++ b/include/tgbot/types/InlineQueryResultVideo.h @@ -44,7 +44,7 @@ class InlineQueryResultVideo : public InlineQueryResult { /** * @brief URL of the thumbnail (jpeg only) for the video */ - std::string thumbUrl; + std::string thumbnailUrl; /** * @brief Title for the result diff --git a/include/tgbot/types/InputMediaAnimation.h b/include/tgbot/types/InputMediaAnimation.h index 1cc262178..b79f05948 100644 --- a/include/tgbot/types/InputMediaAnimation.h +++ b/include/tgbot/types/InputMediaAnimation.h @@ -33,7 +33,7 @@ class InputMediaAnimation : public InputMedia { * Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . * https://core.telegram.org/bots/api#sending-files */ - std::string thumb; + std::string thumbnail; /** * @brief Optional. Animation width diff --git a/include/tgbot/types/InputMediaAudio.h b/include/tgbot/types/InputMediaAudio.h index b46936e64..abfc0232b 100644 --- a/include/tgbot/types/InputMediaAudio.h +++ b/include/tgbot/types/InputMediaAudio.h @@ -32,7 +32,7 @@ class InputMediaAudio : public InputMedia { * Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . * https://core.telegram.org/bots/api#sending-files */ - std::string thumb; + std::string thumbnail; /** * @brief Optional. Duration of the audio in seconds diff --git a/include/tgbot/types/InputMediaDocument.h b/include/tgbot/types/InputMediaDocument.h index 9a6ab107c..12a02e917 100644 --- a/include/tgbot/types/InputMediaDocument.h +++ b/include/tgbot/types/InputMediaDocument.h @@ -32,7 +32,7 @@ class InputMediaDocument : public InputMedia { * Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . * https://core.telegram.org/bots/api#sending-files */ - std::string thumb; + std::string thumbnail; /** * @brief Optional. Disables automatic server-side content type detection for files uploaded using multipart/form-data. diff --git a/include/tgbot/types/InputMediaVideo.h b/include/tgbot/types/InputMediaVideo.h index 2645c9114..734e7bbde 100644 --- a/include/tgbot/types/InputMediaVideo.h +++ b/include/tgbot/types/InputMediaVideo.h @@ -33,7 +33,7 @@ class InputMediaVideo : public InputMedia { * Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . * https://core.telegram.org/bots/api#sending-files */ - std::string thumb; + std::string thumbnail; /** * @brief Optional. Video width diff --git a/include/tgbot/types/InputSticker.h b/include/tgbot/types/InputSticker.h new file mode 100644 index 000000000..f71107e76 --- /dev/null +++ b/include/tgbot/types/InputSticker.h @@ -0,0 +1,45 @@ +#ifndef TGBOT_INPUTSTICKER_H +#define TGBOT_INPUTSTICKER_H + +#include "tgbot/types/MaskPosition.h" + +#include +#include +#include + +namespace TgBot { + +/** + * @brief This object describes a sticker to be added to a sticker set. + * + * @ingroup types + */ +class InputSticker { +public: + typedef std::shared_ptr Ptr; + + /** + * @brief The added sticker. + * Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. + * Animated and video stickers can't be uploaded via HTTP URL. https://core.telegram.org/bots/api#sending-files + */ + std::string sticker; + + /** + * @brief List of 1-20 emoji associated with the sticker + */ + std::vector emojiList; + + /** + * @brief Optional. Position where the mask should be placed on faces. For “mask” stickers only. + */ + MaskPosition::Ptr maskPosition; + + /** + * @brief Optional. List of 0-20 search keywords for the sticker with total length of up to 64 characters. For “regular” and “custom_emoji” stickers only. + */ + std::vector keywords; +}; +} + +#endif //TGBOT_INPUTSTICKER_H diff --git a/include/tgbot/types/Sticker.h b/include/tgbot/types/Sticker.h index 7ec01404d..ab7f167d6 100644 --- a/include/tgbot/types/Sticker.h +++ b/include/tgbot/types/Sticker.h @@ -68,7 +68,7 @@ class Sticker { /** * @brief Optional. Sticker thumbnail in the .WEBP or .JPG format */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; /** * @brief Optional. Emoji associated with the sticker @@ -95,6 +95,11 @@ class Sticker { */ std::string customEmojiId; + /** + * @brief Optional. True, if the sticker must be repainted to a text color in messages, the color of the Telegram Premium badge in emoji status, white color on chat photos, or another appropriate color in other places + */ + bool needsRepainting = true; + /** * @brief Optional. File size in bytes */ diff --git a/include/tgbot/types/StickerSet.h b/include/tgbot/types/StickerSet.h index 006b1d1d4..c55b57786 100644 --- a/include/tgbot/types/StickerSet.h +++ b/include/tgbot/types/StickerSet.h @@ -59,7 +59,7 @@ class StickerSet { /** * @brief Optional. Sticker set thumbnail in the .WEBP, .TGS, or .WEBM format */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; }; } diff --git a/include/tgbot/types/Video.h b/include/tgbot/types/Video.h index 95590adb5..c23bf447e 100644 --- a/include/tgbot/types/Video.h +++ b/include/tgbot/types/Video.h @@ -48,7 +48,7 @@ class Video { /** * @brief Optional. Video thumbnail */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; /** * @brief Optional. Original filename as defined by sender diff --git a/include/tgbot/types/VideoNote.h b/include/tgbot/types/VideoNote.h index 755e3d051..462b117b0 100644 --- a/include/tgbot/types/VideoNote.h +++ b/include/tgbot/types/VideoNote.h @@ -43,7 +43,7 @@ class VideoNote { /** * @brief Optional. Video thumbnail */ - PhotoSize::Ptr thumb; + PhotoSize::Ptr thumbnail; /** * @brief Optional. File size diff --git a/src/Api.cpp b/src/Api.cpp index c8ce39964..bb0ac454c 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -293,7 +293,7 @@ Message::Ptr Api::sendAudio(boost::variant chatId, std::int32_t duration, const std::string& performer, const std::string& title, - boost::variant thumb, + boost::variant thumbnail, std::int32_t replyToMessageId, GenericReply::Ptr replyMarkup, const std::string& parseMode, @@ -333,13 +333,13 @@ Message::Ptr Api::sendAudio(boost::variant chatId, if (!title.empty()) { args.emplace_back("title", title); } - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); } else { // std::string - auto thumbStr = boost::get(thumb); - if (!thumbStr.empty()) { - args.emplace_back("thumb", thumbStr); + auto thumbnailStr = boost::get(thumbnail); + if (!thumbnailStr.empty()) { + args.emplace_back("thumbnail", thumbnailStr); } } if (disableNotification) { @@ -363,7 +363,7 @@ Message::Ptr Api::sendAudio(boost::variant chatId, Message::Ptr Api::sendDocument(boost::variant chatId, boost::variant document, - boost::variant thumb, + boost::variant thumbnail, const std::string& caption, std::int32_t replyToMessageId, GenericReply::Ptr replyMarkup, @@ -387,13 +387,13 @@ Message::Ptr Api::sendDocument(boost::variant chatId, } else { // std::string args.emplace_back("document", boost::get(document)); } - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); } else { // std::string - auto thumbStr = boost::get(thumb); - if (!thumbStr.empty()) { - args.emplace_back("thumb", thumbStr); + auto thumbnailStr = boost::get(thumbnail); + if (!thumbnailStr.empty()) { + args.emplace_back("thumbnail", thumbnailStr); } } if (!caption.empty()) { @@ -433,7 +433,7 @@ Message::Ptr Api::sendVideo(boost::variant chatId, std::int32_t duration, std::int32_t width, std::int32_t height, - boost::variant thumb, + boost::variant thumbnail, const std::string& caption , std::int32_t replyToMessageId, GenericReply::Ptr replyMarkup, @@ -466,13 +466,13 @@ Message::Ptr Api::sendVideo(boost::variant chatId, if (height != 0) { args.emplace_back("height", height); } - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); } else { // std::string - auto thumbStr = boost::get(thumb); - if (!thumbStr.empty()) { - args.emplace_back("thumb", thumbStr); + auto thumbnailStr = boost::get(thumbnail); + if (!thumbnailStr.empty()) { + args.emplace_back("thumbnail", thumbnailStr); } } if (!caption.empty()) { @@ -514,7 +514,7 @@ Message::Ptr Api::sendAnimation(boost::variant chatId std::int32_t duration, std::int32_t width, std::int32_t height, - boost::variant thumb, + boost::variant thumbnail, const std::string& caption, std::int32_t replyToMessageId, GenericReply::Ptr replyMarkup, @@ -547,13 +547,13 @@ Message::Ptr Api::sendAnimation(boost::variant chatId if (height != 0) { args.emplace_back("height", height); } - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); } else { // std::string - auto thumbStr = boost::get(thumb); - if (!thumbStr.empty()) { - args.emplace_back("thumb", thumbStr); + auto thumbnailStr = boost::get(thumbnail); + if (!thumbnailStr.empty()) { + args.emplace_back("thumbnail", thumbnailStr); } } if (!caption.empty()) { @@ -649,7 +649,7 @@ Message::Ptr Api::sendVideoNote(boost::variant chatId bool disableNotification, std::int32_t duration, std::int32_t length, - boost::variant thumb, + boost::variant thumbnail, GenericReply::Ptr replyMarkup, bool allowSendingWithoutReply, bool protectContent, @@ -673,13 +673,13 @@ Message::Ptr Api::sendVideoNote(boost::variant chatId if (length) { args.emplace_back("length", length); } - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); } else { // std::string - auto thumbStr = boost::get(thumb); - if (!thumbStr.empty()) { - args.emplace_back("thumb", thumbStr); + auto thumbnailStr = boost::get(thumbnail); + if (!thumbnailStr.empty()) { + args.emplace_back("thumbnail", thumbnailStr); } } if (disableNotification) { @@ -797,8 +797,14 @@ Message::Ptr Api::editMessageLiveLocation(float latitude, std::vector args; args.reserve(9); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } if (messageId) { args.emplace_back("message_id", messageId); @@ -831,8 +837,14 @@ Message::Ptr Api::stopMessageLiveLocation(boost::variant args; args.reserve(4); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } if (messageId) { args.emplace_back("message_id", messageId); @@ -1539,7 +1551,7 @@ ForumTopic::Ptr Api::createForumTopic(boost::variant bool Api::editForumTopic(boost::variant chatId, std::int32_t messageThreadId, const std::string& name, - boost::variant iconCustomEmojiId) const { + boost::variant iconCustomEmojiId) const { std::vector args; args.reserve(4); @@ -1548,8 +1560,14 @@ bool Api::editForumTopic(boost::variant chatId, if (!name.empty()) { args.emplace_back("name", name); } - if (iconCustomEmojiId.which() == 1) { // std::string - args.emplace_back("icon_custom_emoji_id", boost::get(iconCustomEmojiId)); + if (iconCustomEmojiId.which() == 0) { // std::int32_t + if (boost::get(iconCustomEmojiId) != 0) { + args.emplace_back("icon_custom_emoji_id", iconCustomEmojiId); + } + } else { // std::string + if (boost::get(iconCustomEmojiId) != "") { + args.emplace_back("icon_custom_emoji_id", iconCustomEmojiId); + } } return sendRequest("editForumTopic", args).get("", false); @@ -1689,7 +1707,7 @@ bool Api::setMyCommands(const std::vector& commands, } bool Api::deleteMyCommands(BotCommandScope::Ptr scope, - const std::string& languageCode) const { + const std::string& languageCode) const { std::vector args; args.reserve(2); @@ -1707,7 +1725,7 @@ std::vector Api::getMyCommands(BotCommandScope::Ptr scope, const std::string& languageCode) const { std::vector args; args.reserve(2); -; + if (scope != nullptr) { args.emplace_back("scope", _tgTypeParser.parseBotCommandScope(scope)); } @@ -1718,6 +1736,58 @@ std::vector Api::getMyCommands(BotCommandScope::Ptr scope, return _tgTypeParser.parseJsonAndGetArray(&TgTypeParser::parseJsonAndGetBotCommand, sendRequest("getMyCommands", args)); } +bool Api::setMyDescription(const std::string& description, + const std::string& languageCode) const { + std::vector args; + args.reserve(2); + + if (!description.empty()) { + args.emplace_back("description", description); + } + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return sendRequest("setMyDescription", args).get("", false); +} + +BotDescription::Ptr Api::getMyDescription(const std::string& languageCode) const { + std::vector args; + args.reserve(1); + + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return _tgTypeParser.parseJsonAndGetBotDescription(sendRequest("getMyDescription", args)); +} + +bool Api::setMyShortDescription(const std::string& shortDescription, + const std::string& languageCode) const { + std::vector args; + args.reserve(2); + + if (!shortDescription.empty()) { + args.emplace_back("short_description", shortDescription); + } + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return sendRequest("setMyShortDescription", args).get("", false); +} + +BotShortDescription::Ptr Api::getMyShortDescription(const std::string& languageCode) const { + std::vector args; + args.reserve(1); + + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return _tgTypeParser.parseJsonAndGetBotShortDescription(sendRequest("getMyShortDescription", args)); +} + bool Api::setChatMenuButton(std::int64_t chatId, MenuButton::Ptr menuButton) const { std::vector args; @@ -1781,8 +1851,14 @@ Message::Ptr Api::editMessageText(const std::string& text, std::vector args; args.reserve(8); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } if (messageId) { args.emplace_back("message_id", messageId); @@ -1822,8 +1898,14 @@ Message::Ptr Api::editMessageCaption(boost::variant c std::vector args; args.reserve(7); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } if (messageId) { args.emplace_back("message_id", messageId); @@ -1861,10 +1943,16 @@ Message::Ptr Api::editMessageMedia(InputMedia::Ptr media, std::vector args; args.reserve(5); - args.emplace_back("media", _tgTypeParser.parseInputMedia(media)); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } + args.emplace_back("media", _tgTypeParser.parseInputMedia(media)); if (messageId) { args.emplace_back("message_id", messageId); } @@ -1891,8 +1979,14 @@ Message::Ptr Api::editMessageReplyMarkup(boost::variant args; args.reserve(4); - if ((boost::get(chatId) != 0) || (boost::get(chatId) != "")) { - args.emplace_back("chat_id", chatId); + if (chatId.which() == 0) { // std::int64_t + if (boost::get(chatId) != 0) { + args.emplace_back("chat_id", chatId); + } + } else { // std::string + if (boost::get(chatId) != "") { + args.emplace_back("chat_id", chatId); + } } if (messageId) { args.emplace_back("message_id", messageId); @@ -1945,9 +2039,10 @@ Message::Ptr Api::sendSticker(boost::variant chatId, bool disableNotification, bool allowSendingWithoutReply, bool protectContent, - std::int32_t messageThreadId) const { + std::int32_t messageThreadId, + const std::string& emoji) const { std::vector args; - args.reserve(8); + args.reserve(9); args.emplace_back("chat_id", chatId); if (messageThreadId != 0) { @@ -1959,6 +2054,9 @@ Message::Ptr Api::sendSticker(boost::variant chatId, } else { // std::string args.emplace_back("sticker", boost::get(sticker)); } + if (!emoji.empty()) { + args.emplace_back("emoji", emoji); + } if (disableNotification) { args.emplace_back("disable_notification", disableNotification); } @@ -1991,7 +2089,8 @@ std::vector Api::getCustomEmojiStickers(const std::vector args; args.reserve(1); - args.emplace_back("custom_emoji_ids", _tgTypeParser.parseArray([] (const std::string& customEmojiId) -> std::string { + args.emplace_back("custom_emoji_ids", _tgTypeParser.parseArray( + [] (const std::string& customEmojiId) -> std::string { return "\"" + StringTools::escapeJsonString(customEmojiId) + "\""; }, customEmojiIds)); @@ -1999,12 +2098,14 @@ std::vector Api::getCustomEmojiStickers(const std::vector args; - args.reserve(2); + args.reserve(3); args.emplace_back("user_id", userId); - args.emplace_back("png_sticker", pngSticker->data, true, pngSticker->mimeType, pngSticker->fileName); + args.emplace_back("sticker", sticker->data, true, sticker->mimeType, sticker->fileName); + args.emplace_back("sticker_format", stickerFormat); return _tgTypeParser.parseJsonAndGetFile(sendRequest("uploadStickerFile", args)); } @@ -2012,70 +2113,37 @@ File::Ptr Api::uploadStickerFile(std::int64_t userId, bool Api::createNewStickerSet(std::int64_t userId, const std::string& name, const std::string& title, - const std::string& emojis, - MaskPosition::Ptr maskPosition, - boost::variant pngSticker, - InputFile::Ptr tgsSticker, - InputFile::Ptr webmSticker, - const std::string& stickerType) const { + const std::vector& stickers, + const std::string& stickerFormat, + const std::string& stickerType, + bool needsRepainting) const { std::vector args; - args.reserve(10); + args.reserve(7); args.emplace_back("user_id", userId); args.emplace_back("name", name); args.emplace_back("title", title); - if (pngSticker.which() == 0) { // InputFile::Ptr - auto file = boost::get(pngSticker); - args.emplace_back("png_sticker", file->data, true, file->mimeType, file->fileName); - } else { // std::string - args.emplace_back("png_sticker", boost::get(pngSticker)); - } - if (tgsSticker != nullptr) { - args.emplace_back("tgs_sticker", tgsSticker->data, true, tgsSticker->mimeType, tgsSticker->fileName); - } - if (webmSticker != nullptr) { - args.emplace_back("webm_sticker", webmSticker->data, true, webmSticker->mimeType, webmSticker->fileName); - } + args.emplace_back("stickers", _tgTypeParser.parseArray(&TgTypeParser::parseInputSticker, stickers)); + args.emplace_back("sticker_format", stickerFormat); if (!stickerType.empty()) { args.emplace_back("sticker_type", stickerType); } - args.emplace_back("emojis", emojis); - if (maskPosition != nullptr) { - args.emplace_back("mask_position", _tgTypeParser.parseMaskPosition(maskPosition)); + if (needsRepainting) { + args.emplace_back("needs_repainting", needsRepainting); } return sendRequest("createNewStickerSet", args).get("", false); } bool Api::addStickerToSet(std::int64_t userId, - const std::string& name, - const std::string& emojis, - MaskPosition::Ptr maskPosition, - boost::variant pngSticker, - InputFile::Ptr tgsSticker, - InputFile::Ptr webmSticker) const { + const std::string& name, + InputSticker::Ptr sticker) const { std::vector args; - args.reserve(7); + args.reserve(3); args.emplace_back("user_id", userId); args.emplace_back("name", name); - - if (pngSticker.which() == 0) { // InputFile::Ptr - auto file = boost::get(pngSticker); - args.emplace_back("png_sticker", file->data, true, file->mimeType, file->fileName); - } else { // std::string - args.emplace_back("png_sticker", boost::get(pngSticker)); - } - if (tgsSticker != nullptr) { - args.emplace_back("tgs_sticker", tgsSticker->data, true, tgsSticker->mimeType, tgsSticker->fileName); - } - if (webmSticker != nullptr) { - args.emplace_back("webm_sticker", webmSticker->data, true, webmSticker->mimeType, webmSticker->fileName); - } - args.emplace_back("emojis", emojis); - if (maskPosition != nullptr) { - args.emplace_back("mask_position", _tgTypeParser.parseMaskPosition(maskPosition)); - } + args.emplace_back("sticker", _tgTypeParser.parseInputSticker(sticker)); return sendRequest("addStickerToSet", args).get("", false); } @@ -2100,22 +2168,102 @@ bool Api::deleteStickerFromSet(const std::string& sticker) const { return sendRequest("deleteStickerFromSet", args).get("", false); } -bool Api::setStickerSetThumb(const std::string& name, - std::int64_t userId, - boost::variant thumb) const { +bool Api::setStickerEmojiList(const std::string& sticker, + const std::vector& emojiList) const { + std::vector args; + args.reserve(2); + + args.emplace_back("sticker", sticker); + args.emplace_back("emoji_list", _tgTypeParser.parseArray( + [](const std::string& emoji)->std::string { + return "\"" + StringTools::escapeJsonString(emoji) + "\""; + }, emojiList)); + + return sendRequest("setStickerEmojiList", args).get("", false); +} + +bool Api::setStickerKeywords(const std::string& sticker, + const std::vector& keywords) const { + std::vector args; + args.reserve(2); + + args.emplace_back("sticker", sticker); + if (!keywords.empty()) { + args.emplace_back("keywords", _tgTypeParser.parseArray( + [](const std::string& keyword)->std::string { + return "\"" + StringTools::escapeJsonString(keyword) + "\""; + }, keywords)); + } + + return sendRequest("setStickerKeywords", args).get("", false); +} + +bool Api::setStickerMaskPosition(const std::string& sticker, + MaskPosition::Ptr maskPosition) const { + std::vector args; + args.reserve(2); + + args.emplace_back("sticker", sticker); + if (maskPosition != nullptr) { + args.emplace_back("mask_position", _tgTypeParser.parseMaskPosition(maskPosition)); + } + + return sendRequest("setStickerMaskPosition", args).get("", false); +} + +bool Api::setStickerSetTitle(const std::string& name, + const std::string& title) const { + std::vector args; + args.reserve(2); + + args.emplace_back("name", name); + args.emplace_back("title", title); + + return sendRequest("setStickerSetTitle", args).get("", false); +} + +bool Api::setStickerSetThumbnail(const std::string& name, + std::int64_t userId, + boost::variant thumbnail) const { std::vector args; args.reserve(3); args.emplace_back("name", name); args.emplace_back("user_id", userId); - if (thumb.which() == 0) { // InputFile::Ptr - auto file = boost::get(thumb); - args.emplace_back("thumb", file->data, true, file->mimeType, file->fileName); + if (thumbnail.which() == 0) { // InputFile::Ptr + if (boost::get(thumbnail) != nullptr) { + auto file = boost::get(thumbnail); + args.emplace_back("thumbnail", file->data, true, file->mimeType, file->fileName); + } } else { // std::string - args.emplace_back("thumb", boost::get(thumb)); + if (boost::get(thumbnail) != "") { + args.emplace_back("thumbnail", boost::get(thumbnail)); + } + } + + return sendRequest("setStickerSetThumbnail", args).get("", false); +} + +bool Api::setCustomEmojiStickerSetThumbnail(const std::string& name, + const std::string& customEmojiId) const { + std::vector args; + args.reserve(2); + + args.emplace_back("name", name); + if (!customEmojiId.empty()) { + args.emplace_back("custom_emoji_id", customEmojiId); } - return sendRequest("setStickerSetThumb", args).get("", false); + return sendRequest("setCustomEmojiStickerSetThumbnail", args).get("", false); +} + +bool Api::deleteStickerSet(const std::string& name) const { + std::vector args; + args.reserve(1); + + args.emplace_back("name", name); + + return sendRequest("deleteStickerSet", args).get("", false); } bool Api::answerInlineQuery(const std::string& inlineQueryId, diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index 9e04851b3..efd1c0822 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -531,7 +531,7 @@ Animation::Ptr TgTypeParser::parseJsonAndGetAnimation(const boost::property_tree result->width = data.get("width", 0); result->height = data.get("height", 0); result->duration = data.get("duration", 0); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); result->fileName = data.get("file_name", ""); result->mimeType = data.get("mime_type", ""); result->fileSize = data.get("file_size", 0); @@ -549,7 +549,7 @@ std::string TgTypeParser::parseAnimation(const Animation::Ptr& object) const { appendToJson(result, "width", object->width); appendToJson(result, "height", object->height); appendToJson(result, "duration", object->duration); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); appendToJson(result, "file_name", object->fileName); appendToJson(result, "mime_type", object->mimeType); appendToJson(result, "file_size", object->fileSize); @@ -568,7 +568,7 @@ Audio::Ptr TgTypeParser::parseJsonAndGetAudio(const boost::property_tree::ptree& result->fileName = data.get("file_name", ""); result->mimeType = data.get("mime_type", ""); result->fileSize = data.get("file_size", 0); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); return result; } @@ -586,7 +586,7 @@ std::string TgTypeParser::parseAudio(const Audio::Ptr& object) const { appendToJson(result, "file_name", object->fileName); appendToJson(result, "mime_type", object->mimeType); appendToJson(result, "file_size", object->fileSize); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); removeLastComma(result); result += '}'; return result; @@ -596,7 +596,7 @@ Document::Ptr TgTypeParser::parseJsonAndGetDocument(const boost::property_tree:: auto result(std::make_shared()); result->fileId = data.get("file_id", ""); result->fileUniqueId = data.get("file_unique_id", ""); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); result->fileName = data.get("file_name", ""); result->mimeType = data.get("mime_type", ""); result->fileSize = data.get("file_size", 0); @@ -611,7 +611,7 @@ std::string TgTypeParser::parseDocument(const Document::Ptr& object) const { result += '{'; appendToJson(result, "file_id", object->fileId); appendToJson(result, "file_unique_id", object->fileUniqueId); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); appendToJson(result, "file_name", object->fileName); appendToJson(result, "mime_type", object->mimeType); appendToJson(result, "file_size", object->fileSize); @@ -627,7 +627,7 @@ Video::Ptr TgTypeParser::parseJsonAndGetVideo(const boost::property_tree::ptree& result->width = data.get("width", 0); result->height = data.get("height", 0); result->duration = data.get("duration", 0); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); result->fileName = data.get("file_name", ""); result->mimeType = data.get("mime_type", ""); result->fileSize = data.get("file_size", 0); @@ -645,7 +645,7 @@ std::string TgTypeParser::parseVideo(const Video::Ptr& object) const { appendToJson(result, "width", object->width); appendToJson(result, "height", object->height); appendToJson(result, "duration", object->duration); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); appendToJson(result, "file_name", object->fileName); appendToJson(result, "mime_type", object->mimeType); appendToJson(result, "file_size", object->fileSize); @@ -660,7 +660,7 @@ VideoNote::Ptr TgTypeParser::parseJsonAndGetVideoNote(const boost::property_tree result->fileUniqueId = data.get("file_unique_id", ""); result->length = data.get("length", 0); result->duration = data.get("duration", 0); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); result->fileSize = data.get("file_size", 0); return result; } @@ -675,7 +675,7 @@ std::string TgTypeParser::parseVideoNote(const VideoNote::Ptr& object) const { appendToJson(result, "file_unique_id", object->fileUniqueId); appendToJson(result, "length", object->length); appendToJson(result, "duration", object->duration); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); appendToJson(result, "file_size", object->fileSize); removeLastComma(result); result += '}'; @@ -2220,6 +2220,36 @@ std::string TgTypeParser::parseBotCommandScopeChatMember(const BotCommandScopeCh return result; } +BotDescription::Ptr TgTypeParser::parseJsonAndGetBotDescription(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->description = data.get("description", ""); + return result; +} + +std::string TgTypeParser::parseBotDescription(const BotDescription::Ptr& object) const { + std::string result; + result += '{'; + appendToJson(result, "description", object->description); + removeLastComma(result); + result += '}'; + return result; +} + +BotShortDescription::Ptr TgTypeParser::parseJsonAndGetBotShortDescription(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->shortDescription = data.get("short_description", ""); + return result; +} + +std::string TgTypeParser::parseBotShortDescription(const BotShortDescription::Ptr& object) const { + std::string result; + result += '{'; + appendToJson(result, "short_description", object->shortDescription); + removeLastComma(result); + result += '}'; + return result; +} + MenuButton::Ptr TgTypeParser::parseJsonAndGetMenuButton(const boost::property_tree::ptree& data) const { std::string type = data.get("type", ""); MenuButton::Ptr result; @@ -2413,7 +2443,7 @@ std::string TgTypeParser::parseInputMediaPhoto(const InputMediaPhoto::Ptr& objec InputMediaVideo::Ptr TgTypeParser::parseJsonAndGetInputMediaVideo(const boost::property_tree::ptree& data) const { // NOTE: This function will be called by parseJsonAndGetInputMedia(). auto result(std::make_shared()); - result->thumb = data.get("thumb", ""); + result->thumbnail = data.get("thumbnail", ""); result->width = data.get("width", 0); result->height = data.get("height", 0); result->duration = data.get("duration", 0); @@ -2429,7 +2459,7 @@ std::string TgTypeParser::parseInputMediaVideo(const InputMediaVideo::Ptr& objec // This function will be called by parseInputMedia(), so I don't add // curly brackets to the result std::string. std::string result; - appendToJson(result, "thumb", object->thumb); + appendToJson(result, "thumbnail", object->thumbnail); appendToJson(result, "width", object->width); appendToJson(result, "height", object->height); appendToJson(result, "duration", object->duration); @@ -2442,7 +2472,7 @@ std::string TgTypeParser::parseInputMediaVideo(const InputMediaVideo::Ptr& objec InputMediaAnimation::Ptr TgTypeParser::parseJsonAndGetInputMediaAnimation(const boost::property_tree::ptree& data) const { // NOTE: This function will be called by parseJsonAndGetInputMedia(). auto result(std::make_shared()); - result->thumb = data.get("thumb", ""); + result->thumbnail = data.get("thumbnail", ""); result->width = data.get("width", 0); result->height = data.get("height", 0); result->duration = data.get("duration", 0); @@ -2457,7 +2487,7 @@ std::string TgTypeParser::parseInputMediaAnimation(const InputMediaAnimation::Pt // This function will be called by parseInputMedia(), so I don't add // curly brackets to the result std::string. std::string result; - appendToJson(result, "thumb", object->thumb); + appendToJson(result, "thumbnail", object->thumbnail); appendToJson(result, "width", object->width); appendToJson(result, "height", object->height); appendToJson(result, "duration", object->duration); @@ -2469,7 +2499,7 @@ std::string TgTypeParser::parseInputMediaAnimation(const InputMediaAnimation::Pt InputMediaAudio::Ptr TgTypeParser::parseJsonAndGetInputMediaAudio(const boost::property_tree::ptree& data) const { // NOTE: This function will be called by parseJsonAndGetInputMedia(). auto result(std::make_shared()); - result->thumb = data.get("thumb", ""); + result->thumbnail = data.get("thumbnail", ""); result->duration = data.get("duration", 0); result->performer = data.get("performer", ""); result->title = data.get("title", ""); @@ -2483,7 +2513,7 @@ std::string TgTypeParser::parseInputMediaAudio(const InputMediaAudio::Ptr& objec // This function will be called by parseInputMedia(), so I don't add // curly brackets to the result std::string. std::string result; - appendToJson(result, "thumb", object->thumb); + appendToJson(result, "thumbnail", object->thumbnail); appendToJson(result, "duration", object->duration); appendToJson(result, "performer", object->performer); appendToJson(result, "title", object->title); @@ -2494,7 +2524,7 @@ std::string TgTypeParser::parseInputMediaAudio(const InputMediaAudio::Ptr& objec InputMediaDocument::Ptr TgTypeParser::parseJsonAndGetInputMediaDocument(const boost::property_tree::ptree& data) const { // NOTE: This function will be called by parseJsonAndGetInputMedia(). auto result(std::make_shared()); - result->thumb = data.get("thumb", ""); + result->thumbnail = data.get("thumbnail", ""); result->disableContentTypeDetection = data.get("disable_content_type_detection", false); return result; } @@ -2506,7 +2536,7 @@ std::string TgTypeParser::parseInputMediaDocument(const InputMediaDocument::Ptr& // This function will be called by parseInputMedia(), so I don't add // curly brackets to the result std::string. std::string result; - appendToJson(result, "thumb", object->thumb); + appendToJson(result, "thumbnail", object->thumbnail); appendToJson(result, "disable_content_type_detection", object->disableContentTypeDetection); // The last comma will be erased by parseInputMedia(). return result; @@ -2528,12 +2558,13 @@ Sticker::Ptr TgTypeParser::parseJsonAndGetSticker(const boost::property_tree::pt result->height = data.get("height", 0); result->isAnimated = data.get("is_animated", false); result->isVideo = data.get("is_video", false); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); result->emoji = data.get("emoji", ""); result->setName = data.get("set_name", ""); result->premiumAnimation = tryParseJson(&TgTypeParser::parseJsonAndGetFile, data, "premium_animation"); result->maskPosition = tryParseJson(&TgTypeParser::parseJsonAndGetMaskPosition, data, "mask_position"); result->customEmojiId = data.get("custom_emoji_id", ""); + result->needsRepainting = data.get("needs_repainting", true); result->fileSize = data.get("file_size", 0); return result; } @@ -2557,12 +2588,13 @@ std::string TgTypeParser::parseSticker(const Sticker::Ptr& object) const { appendToJson(result, "height", object->height); appendToJson(result, "is_animated", object->isAnimated); appendToJson(result, "is_video", object->isVideo); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); appendToJson(result, "emoji", object->emoji); appendToJson(result, "set_name", object->setName); appendToJson(result, "premium_animation", parseFile(object->premiumAnimation)); appendToJson(result, "mask_position", parseMaskPosition(object->maskPosition)); appendToJson(result, "custom_emoji_id", object->customEmojiId); + appendToJson(result, "needs_repainting", object->needsRepainting); appendToJson(result, "file_size", object->fileSize); removeLastComma(result); result += '}'; @@ -2584,7 +2616,7 @@ StickerSet::Ptr TgTypeParser::parseJsonAndGetStickerSet(const boost::property_tr result->isAnimated = data.get("is_animated", false); result->isVideo = data.get("is_video", false); result->stickers = parseJsonAndGetArray(&TgTypeParser::parseJsonAndGetSticker, data, "stickers"); - result->thumb = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumb"); + result->thumbnail = tryParseJson(&TgTypeParser::parseJsonAndGetPhotoSize, data, "thumbnail"); return result; } @@ -2606,7 +2638,7 @@ std::string TgTypeParser::parseStickerSet(const StickerSet::Ptr& object) const { appendToJson(result, "is_animated", object->isAnimated); appendToJson(result, "is_video", object->isVideo); appendToJson(result, "stickers", parseArray(&TgTypeParser::parseSticker, object->stickers)); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "thumbnail", parsePhotoSize(object->thumbnail)); removeLastComma(result); result += '}'; return result; @@ -2636,6 +2668,44 @@ std::string TgTypeParser::parseMaskPosition(const MaskPosition::Ptr& object) con return result; } +InputSticker::Ptr TgTypeParser::parseJsonAndGetInputSticker(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->sticker = data.get("sticker", ""); + result->emojiList = parseJsonAndGetArray( + [] (const boost::property_tree::ptree& innerData)->std::string { + return innerData.get(""); + } + , data, "emoji_list"); + result->maskPosition = tryParseJson(&TgTypeParser::parseJsonAndGetMaskPosition, data, "mask_position"); + result->keywords = parseJsonAndGetArray( + [] (const boost::property_tree::ptree& innerData)->std::string { + return innerData.get(""); + } + , data, "keywords"); + return result; +} + +std::string TgTypeParser::parseInputSticker(const InputSticker::Ptr& object) const { + if (!object) { + return ""; + } + std::string result; + result += '{'; + appendToJson(result, "sticker", object->sticker); + appendToJson(result, "emoji_list", parseArray( + [] (const std::string& s)->std::string { + return s; + }, object->emojiList)); + appendToJson(result, "mask_position", parseMaskPosition(object->maskPosition)); + appendToJson(result, "keywords", parseArray( + [] (const std::string& s)->std::string { + return s; + }, object->keywords)); + removeLastComma(result); + result += '}'; + return result; +} + InlineQuery::Ptr TgTypeParser::parseJsonAndGetInlineQuery(const boost::property_tree::ptree& data) const { auto result(std::make_shared()); result->id = data.get("id", ""); @@ -2784,9 +2854,9 @@ InlineQueryResultArticle::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultArti result->url = data.get("url", ""); result->hideUrl = data.get("hide_url", false); result->description = data.get("description", ""); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbWidth = data.get("thumb_width", 0); - result->thumbHeight = data.get("thumb_height", 0); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailWidth = data.get("thumbnail_width", 0); + result->thumbnailHeight = data.get("thumbnail_height", 0); return result; } @@ -2802,9 +2872,9 @@ std::string TgTypeParser::parseInlineQueryResultArticle(const InlineQueryResultA appendToJson(result, "url", object->url); appendToJson(result, "hide_url", object->hideUrl); appendToJson(result, "description", object->description); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_width", object->thumbWidth); - appendToJson(result, "thumb_height", object->thumbHeight); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_width", object->thumbnailWidth); + appendToJson(result, "thumbnail_height", object->thumbnailHeight); // The last comma will be erased by parseInlineQueryResult(). return result; } @@ -2813,7 +2883,7 @@ InlineQueryResultPhoto::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultPhoto( // NOTE: This function will be called by parseJsonAndGetInlineQueryResult(). auto result(std::make_shared()); result->photoUrl = data.get("photo_url", ""); - result->thumbUrl = data.get("thumb_url", ""); + result->thumbnailUrl = data.get("thumbnail_url", ""); result->photoWidth = data.get("photo_width", 0); result->photoHeight = data.get("photo_height", 0); result->title = data.get("title", ""); @@ -2833,7 +2903,7 @@ std::string TgTypeParser::parseInlineQueryResultPhoto(const InlineQueryResultPho // curly brackets to the result std::string. std::string result; appendToJson(result, "photo_url", object->photoUrl); - appendToJson(result, "thumb_url", object->thumbUrl); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); appendToJson(result, "photo_width", object->photoWidth); appendToJson(result, "photo_height", object->photoHeight); appendToJson(result, "title", object->title); @@ -2853,8 +2923,8 @@ InlineQueryResultGif::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultGif(cons result->gifWidth = data.get("gif_width", 0); result->gifHeight = data.get("gif_height", 0); result->gifDuration = data.get("gif_duration", 0); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbMimeType = data.get("thumb_mime_type", ""); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailMimeType = data.get("thumbnail_mime_type", ""); result->title = data.get("title", ""); result->caption = data.get("caption", ""); result->parseMode = data.get("parse_mode", ""); @@ -2874,8 +2944,8 @@ std::string TgTypeParser::parseInlineQueryResultGif(const InlineQueryResultGif:: appendToJson(result, "gif_width", object->gifWidth); appendToJson(result, "gif_height", object->gifHeight); appendToJson(result, "gif_duration", object->gifDuration); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_mime_type", object->thumbMimeType); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_mime_type", object->thumbnailMimeType); appendToJson(result, "title", object->title); appendToJson(result, "caption", object->caption); appendToJson(result, "parse_mode", object->parseMode); @@ -2892,8 +2962,8 @@ InlineQueryResultMpeg4Gif::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultMpe result->mpeg4Width = data.get("mpeg4_width", 0); result->mpeg4Height = data.get("mpeg4_height", 0); result->mpeg4Duration = data.get("mpeg4_duration", 0); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbMimeType = data.get("thumb_mime_type", ""); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailMimeType = data.get("thumbnail_mime_type", ""); result->title = data.get("title", ""); result->caption = data.get("caption", ""); result->parseMode = data.get("parse_mode", ""); @@ -2913,8 +2983,8 @@ std::string TgTypeParser::parseInlineQueryResultMpeg4Gif(const InlineQueryResult appendToJson(result, "mpeg4_width", object->mpeg4Width); appendToJson(result, "mpeg4_height", object->mpeg4Height); appendToJson(result, "mpeg4_duration", object->mpeg4Duration); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_mime_type", object->thumbMimeType); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_mime_type", object->thumbnailMimeType); appendToJson(result, "title", object->title); appendToJson(result, "caption", object->caption); appendToJson(result, "parse_mode", object->parseMode); @@ -2929,7 +2999,7 @@ InlineQueryResultVideo::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultVideo( auto result(std::make_shared()); result->videoUrl = data.get("video_url", ""); result->mimeType = data.get("mime_type", ""); - result->thumbUrl = data.get("thumb_url", ""); + result->thumbnailUrl = data.get("thumbnail_url", ""); result->title = data.get("title", ""); result->caption = data.get("caption", ""); result->parseMode = data.get("parse_mode", ""); @@ -2951,7 +3021,7 @@ std::string TgTypeParser::parseInlineQueryResultVideo(const InlineQueryResultVid std::string result; appendToJson(result, "video_url", object->videoUrl); appendToJson(result, "mime_type", object->mimeType); - appendToJson(result, "thumb_url", object->thumbUrl); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); appendToJson(result, "title", object->title); appendToJson(result, "caption", object->caption); appendToJson(result, "parse_mode", object->parseMode); @@ -3040,9 +3110,9 @@ InlineQueryResultDocument::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultDoc result->mimeType = data.get("mime_type", ""); result->description = data.get("description", ""); result->inputMessageContent = tryParseJson(&TgTypeParser::parseJsonAndGetInputMessageContent, data, "input_message_content"); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbWidth = data.get("thumb_width", 0); - result->thumbHeight = data.get("thumb_height", 0); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailWidth = data.get("thumbnail_width", 0); + result->thumbnailHeight = data.get("thumbnail_height", 0); return result; } @@ -3061,9 +3131,9 @@ std::string TgTypeParser::parseInlineQueryResultDocument(const InlineQueryResult appendToJson(result, "mime_type", object->mimeType); appendToJson(result, "description", object->description); appendToJson(result, "input_message_content", parseInputMessageContent(object->inputMessageContent)); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_width", object->thumbWidth); - appendToJson(result, "thumb_height", object->thumbHeight); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_width", object->thumbnailWidth); + appendToJson(result, "thumbnail_height", object->thumbnailHeight); // The last comma will be erased by parseInlineQueryResult(). return result; } @@ -3079,9 +3149,9 @@ InlineQueryResultLocation::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultLoc result->heading = data.get("heading", 0); result->proximityAlertRadius = data.get("proximity_alert_radius", 0); result->inputMessageContent = tryParseJson(&TgTypeParser::parseJsonAndGetInputMessageContent, data, "input_message_content"); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbWidth = data.get("thumb_width", 0); - result->thumbHeight = data.get("thumb_height", 0); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailWidth = data.get("thumbnail_width", 0); + result->thumbnailHeight = data.get("thumbnail_height", 0); return result; } @@ -3100,9 +3170,9 @@ std::string TgTypeParser::parseInlineQueryResultLocation(const InlineQueryResult appendToJson(result, "heading", object->heading); appendToJson(result, "proximity_alert_radius", object->proximityAlertRadius); appendToJson(result, "input_message_content", parseInputMessageContent(object->inputMessageContent)); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_width", object->thumbWidth); - appendToJson(result, "thumb_height", object->thumbHeight); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_width", object->thumbnailWidth); + appendToJson(result, "thumbnail_height", object->thumbnailHeight); // The last comma will be erased by parseInlineQueryResult(). return result; } @@ -3119,9 +3189,9 @@ InlineQueryResultVenue::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultVenue( result->googlePlaceId = data.get("google_place_id", ""); result->googlePlaceType = data.get("google_place_type", ""); result->inputMessageContent = tryParseJson(&TgTypeParser::parseJsonAndGetInputMessageContent, data, "input_message_content"); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbWidth = data.get("thumb_width", 0); - result->thumbHeight = data.get("thumb_height", 0); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailWidth = data.get("thumbnail_width", 0); + result->thumbnailHeight = data.get("thumbnail_height", 0); return result; } @@ -3141,9 +3211,9 @@ std::string TgTypeParser::parseInlineQueryResultVenue(const InlineQueryResultVen appendToJson(result, "google_place_id", object->googlePlaceId); appendToJson(result, "google_place_type", object->googlePlaceType); appendToJson(result, "input_message_content", parseInputMessageContent(object->inputMessageContent)); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_width", object->thumbWidth); - appendToJson(result, "thumb_height", object->thumbHeight); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_width", object->thumbnailWidth); + appendToJson(result, "thumbnail_height", object->thumbnailHeight); // The last comma will be erased by parseInlineQueryResult(). return result; } @@ -3156,9 +3226,9 @@ InlineQueryResultContact::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultCont result->lastName = data.get("last_name", ""); result->vcard = data.get("vcard", ""); result->inputMessageContent = tryParseJson(&TgTypeParser::parseJsonAndGetInputMessageContent, data, "input_message_content"); - result->thumbUrl = data.get("thumb_url", ""); - result->thumbWidth = data.get("thumb_width", 0); - result->thumbHeight = data.get("thumb_height", 0); + result->thumbnailUrl = data.get("thumbnail_url", ""); + result->thumbnailWidth = data.get("thumbnail_width", 0); + result->thumbnailHeight = data.get("thumbnail_height", 0); return result; } @@ -3174,9 +3244,9 @@ std::string TgTypeParser::parseInlineQueryResultContact(const InlineQueryResultC appendToJson(result, "last_name", object->lastName); appendToJson(result, "vcard", object->vcard); appendToJson(result, "input_message_content", parseInputMessageContent(object->inputMessageContent)); - appendToJson(result, "thumb_url", object->thumbUrl); - appendToJson(result, "thumb_width", object->thumbWidth); - appendToJson(result, "thumb_height", object->thumbHeight); + appendToJson(result, "thumbnail_url", object->thumbnailUrl); + appendToJson(result, "thumbnail_width", object->thumbnailWidth); + appendToJson(result, "thumbnail_height", object->thumbnailHeight); // The last comma will be erased by parseInlineQueryResult(). return result; } From 38258eb91f752222e1e64f0499a408643a107149 Mon Sep 17 00:00:00 2001 From: Nulldisk <48621230+llnulldisk@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:45:43 +0200 Subject: [PATCH 02/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 382bd3d1a..46df6714a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Documentation is located [here](http://reo7sp.github.io/tgbot-cpp). ## State - [x] Telegram Bot API 6.6 -- [] [Deep Linking](https://core.telegram.org/bots/features#deep-linking) +- [ ] [Deep Linking](https://core.telegram.org/bots/features#deep-linking) ## Sample From fbeb025e21fad2fa1fb6cd5ae186eabf9a349091 Mon Sep 17 00:00:00 2001 From: llnulldisk <48621230+llnulldisk@users.noreply.github.com> Date: Mon, 15 Apr 2024 01:24:12 +0200 Subject: [PATCH 03/11] Update to Bot API 6.7 --- README.md | 6 +- include/tgbot/Api.h | 28 +++++-- include/tgbot/TgTypeParser.h | 12 +++ include/tgbot/types/BotName.h | 25 +++++++ include/tgbot/types/ChatMemberUpdated.h | 8 +- include/tgbot/types/InlineKeyboardButton.h | 6 ++ .../tgbot/types/InlineQueryResultsButton.h | 44 +++++++++++ include/tgbot/types/InputSticker.h | 2 +- .../tgbot/types/KeyboardButtonRequestChat.h | 2 + .../tgbot/types/KeyboardButtonRequestUser.h | 2 + .../tgbot/types/SwitchInlineQueryChosenChat.h | 46 ++++++++++++ include/tgbot/types/WriteAccessAllowed.h | 10 ++- src/Api.cpp | 42 ++++++++--- src/TgTypeParser.cpp | 74 ++++++++++++++++++- 14 files changed, 282 insertions(+), 25 deletions(-) create mode 100644 include/tgbot/types/BotName.h create mode 100644 include/tgbot/types/InlineQueryResultsButton.h create mode 100644 include/tgbot/types/SwitchInlineQueryChosenChat.h diff --git a/README.md b/README.md index 46df6714a..5b4bb7217 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Documentation is located [here](http://reo7sp.github.io/tgbot-cpp). ## State -- [x] Telegram Bot API 6.6 +- [x] Telegram Bot API 6.7 - [ ] [Deep Linking](https://core.telegram.org/bots/features#deep-linking) @@ -105,8 +105,8 @@ Taken from [Vcpkg - Quick Start: Windows](https://github.com/Microsoft/vcpkg/#qu Prerequisites: - Windows 7 or newer -- Git -- Visual Studio 2015 Update 3 or greater with the English language pack +- [Git][https://git-scm.com/downloads] +- [Visual Studio][https://visualstudio.microsoft.com] 2015 Update 3 or greater with the English language pack First, download and bootstrap vcpkg itself; it can be installed anywhere, but generally we recommend using vcpkg as a submodule for CMake projects, and installing it globally for Visual Studio projects. We recommend somewhere like `C:\src\vcpkg` or `C:\dev\vcpkg`, since otherwise you may run into path issues for some port build systems. diff --git a/include/tgbot/Api.h b/include/tgbot/Api.h index a30a9fef8..5efe50fe0 100644 --- a/include/tgbot/Api.h +++ b/include/tgbot/Api.h @@ -1411,6 +1411,26 @@ friend class Bot; std::vector getMyCommands(BotCommandScope::Ptr scope = nullptr, const std::string& languageCode = "") const; + /** + * @brief Use this method to change the bot's name. + * + * @param name Optional. New bot name; 0-64 characters. Pass an empty string to remove the dedicated name for the given language. + * @param languageCode Optional. A two-letter ISO 639-1 language code. If empty, the name will be shown to all users for whose language there is no dedicated name. + * + * @return Returns True on success. + */ + bool setMyName(const std::string& name = "", + const std::string& languageCode = "") const; + + /** + * @brief Use this method to get the current bot name for the given user language. + * + * @param languageCode Optional. A two-letter ISO 639-1 language code or an empty string + * + * @return Returns BotName on success. + */ + BotName::Ptr getMyName(const std::string& languageCode = "") const; + /** * @brief Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty. * @@ -1815,10 +1835,9 @@ friend class Bot; * @param inlineQueryId Unique identifier for the answered query * @param results A JSON-serialized array of results for the inline query * @param cacheTime Optional. The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300. - * @param isPersonal Optional. Pass True if results may be cached on the server side only for the user that sent the query. By default, results may be returned to any user who sends the same query + * @param isPersonal Optional. Pass True if results may be cached on the server side only for the user that sent the query. By default, results may be returned to any user who sends the same query. * @param nextOffset Optional. Pass the offset that a client should send in the next query with the same text to receive more results. Pass an empty string if there are no more results or if you don't support pagination. Offset length can't exceed 64 bytes. - * @param switchPmText Optional. If passed, clients will display a button with specified text that switches the user to a private chat with the bot and sends the bot a start message with the parameter switchPmParameter - * @param switchPmParameter Optional. Deep-linking parameter for the /start message sent to the bot when user presses the switch button. 1-64 characters, only A-Z, a-z, 0-9, _ and - are allowed. Example: An inline bot that sends YouTube videos can ask the user to connect the bot to their YouTube account to adapt search results accordingly. To do this, it displays a 'Connect your YouTube account' button above the results, or even before showing any. The user presses the button, switches to a private chat with the bot and, in doing so, passes a start parameter that instructs the bot to return an OAuth link. Once done, the bot can offer an InlineKeyboardMarkup button so that the user can easily return to the chat where they wanted to use the bot's inline capabilities. + * @param button Optional. A JSON-serialized object describing a button to be shown above inline query results * * @return On success, True is returned. */ @@ -1827,8 +1846,7 @@ friend class Bot; std::int32_t cacheTime = 300, bool isPersonal = false, const std::string& nextOffset = "", - const std::string& switchPmText = "", - const std::string& switchPmParameter = "") const; + InlineQueryResultsButton::Ptr button = nullptr) const; /** * @brief Use this method to set the result of an interaction with a Web App and send a corresponding message on behalf of the user to the chat from which the query originated. diff --git a/include/tgbot/TgTypeParser.h b/include/tgbot/TgTypeParser.h index 9f135fd6f..99a38a932 100644 --- a/include/tgbot/TgTypeParser.h +++ b/include/tgbot/TgTypeParser.h @@ -51,6 +51,7 @@ #include "tgbot/types/InlineKeyboardMarkup.h" #include "tgbot/types/InlineKeyboardButton.h" #include "tgbot/types/LoginUrl.h" +#include "tgbot/types/SwitchInlineQueryChosenChat.h" #include "tgbot/types/CallbackQuery.h" #include "tgbot/types/ForceReply.h" #include "tgbot/types/ChatPhoto.h" @@ -77,6 +78,7 @@ #include "tgbot/types/BotCommandScopeChat.h" #include "tgbot/types/BotCommandScopeChatAdministrators.h" #include "tgbot/types/BotCommandScopeChatMember.h" +#include "tgbot/types/BotName.h" #include "tgbot/types/BotDescription.h" #include "tgbot/types/BotShortDescription.h" #include "tgbot/types/MenuButton.h" @@ -95,6 +97,7 @@ #include "tgbot/types/MaskPosition.h" #include "tgbot/types/InputSticker.h" #include "tgbot/types/InlineQuery.h" +#include "tgbot/types/InlineQueryResultsButton.h" #include "tgbot/types/InlineQueryResult.h" #include "tgbot/types/InlineQueryResultArticle.h" #include "tgbot/types/InlineQueryResultPhoto.h" @@ -316,6 +319,9 @@ class TGBOT_API TgTypeParser { LoginUrl::Ptr parseJsonAndGetLoginUrl(const boost::property_tree::ptree& data) const; std::string parseLoginUrl(const LoginUrl::Ptr& object) const; + SwitchInlineQueryChosenChat::Ptr parseJsonAndGetSwitchInlineQueryChosenChat(const boost::property_tree::ptree& data) const; + std::string parseSwitchInlineQueryChosenChat(const SwitchInlineQueryChosenChat::Ptr& object) const; + CallbackQuery::Ptr parseJsonAndGetCallbackQuery(const boost::property_tree::ptree& data) const; std::string parseCallbackQuery(const CallbackQuery::Ptr& object) const; @@ -394,6 +400,9 @@ class TGBOT_API TgTypeParser { BotCommandScopeChatMember::Ptr parseJsonAndGetBotCommandScopeChatMember(const boost::property_tree::ptree& data) const; std::string parseBotCommandScopeChatMember(const BotCommandScopeChatMember::Ptr& object) const; + BotName::Ptr parseJsonAndGetBotName(const boost::property_tree::ptree& data) const; + std::string parseBotName(const BotName::Ptr& object) const; + BotDescription::Ptr parseJsonAndGetBotDescription(const boost::property_tree::ptree& data) const; std::string parseBotDescription(const BotDescription::Ptr& object) const; @@ -448,6 +457,9 @@ class TGBOT_API TgTypeParser { InlineQuery::Ptr parseJsonAndGetInlineQuery(const boost::property_tree::ptree& data) const; std::string parseInlineQuery(const InlineQuery::Ptr& object) const; + InlineQueryResultsButton::Ptr parseJsonAndGetInlineQueryResultsButton(const boost::property_tree::ptree& data) const; + std::string parseInlineQueryResultsButton(const InlineQueryResultsButton::Ptr& object) const; + InlineQueryResult::Ptr parseJsonAndGetInlineQueryResult(const boost::property_tree::ptree& data) const; std::string parseInlineQueryResult(const InlineQueryResult::Ptr& object) const; diff --git a/include/tgbot/types/BotName.h b/include/tgbot/types/BotName.h new file mode 100644 index 000000000..d89ee5c4d --- /dev/null +++ b/include/tgbot/types/BotName.h @@ -0,0 +1,25 @@ +#ifndef TGBOT_BOTNAME_H +#define TGBOT_BOTNAME_H + +#include +#include + +namespace TgBot { + +/** + * @brief This object represents the bot's name. + * + * @ingroup types + */ +class BotName { +public: + typedef std::shared_ptr Ptr; + + /** + * @brief The bot's name + */ + std::string name; +}; +} + +#endif //TGBOT_BOTNAME_H diff --git a/include/tgbot/types/ChatMemberUpdated.h b/include/tgbot/types/ChatMemberUpdated.h index 9d8ce2b98..1d572e631 100644 --- a/include/tgbot/types/ChatMemberUpdated.h +++ b/include/tgbot/types/ChatMemberUpdated.h @@ -6,6 +6,7 @@ #include "tgbot/types/ChatMember.h" #include "tgbot/types/ChatInviteLink.h" +#include #include namespace TgBot { @@ -33,7 +34,7 @@ class ChatMemberUpdated { /** * @brief Date the change was done in Unix time */ - std::uint32_t date; + std::uint64_t date; /** * @brief Previous information about the chat member @@ -49,6 +50,11 @@ class ChatMemberUpdated { * @brief Optional. Chat invite link, which was used by the user to join the chat; for joining by invite link events only. */ ChatInviteLink::Ptr inviteLink; + + /** + * @brief Optional. True, if the user joined the chat via a chat folder invite link + */ + bool viaChatFolderInviteLink; }; } diff --git a/include/tgbot/types/InlineKeyboardButton.h b/include/tgbot/types/InlineKeyboardButton.h index f2166691c..1f2e16f66 100644 --- a/include/tgbot/types/InlineKeyboardButton.h +++ b/include/tgbot/types/InlineKeyboardButton.h @@ -3,6 +3,7 @@ #include "tgbot/types/WebAppInfo.h" #include "tgbot/types/LoginUrl.h" +#include "tgbot/types/SwitchInlineQueryChosenChat.h" #include "tgbot/types/CallbackGame.h" #include @@ -66,6 +67,11 @@ class InlineKeyboardButton { */ std::string switchInlineQueryCurrentChat; + /** + * @brief Optional. If set, pressing the button will prompt the user to select one of their chats of the specified type, open that chat and insert the bot's username and the specified inline query in the input field + */ + SwitchInlineQueryChosenChat::Ptr switchInlineQueryChosenChat; + /** * @brief Optional. Description of the game that will be launched when the user presses the button. * diff --git a/include/tgbot/types/InlineQueryResultsButton.h b/include/tgbot/types/InlineQueryResultsButton.h new file mode 100644 index 000000000..2343ff5e7 --- /dev/null +++ b/include/tgbot/types/InlineQueryResultsButton.h @@ -0,0 +1,44 @@ +#ifndef TGBOT_INLINEQUERYRESULTSBUTTON_H +#define TGBOT_INLINEQUERYRESULTSBUTTON_H + +#include "tgbot/types/WebAppInfo.h" + +#include +#include + +namespace TgBot { + +/** + * @brief This object represents a button to be shown above inline query results. + * + * You must use exactly one of the optional fields. + * + * @ingroup types + */ +class InlineQueryResultsButton { +public: + typedef std::shared_ptr Ptr; + + /** + * @brief Label text on the button + */ + std::string text; + + /** + * @brief Optional. Description of the Web App (https://core.telegram.org/bots/webapps) that will be launched when the user presses the button. The Web App will be able to switch back to the inline mode using the method switchInlineQuery (https://core.telegram.org/bots/webapps#initializing-web-apps) inside the Web App. + */ + WebAppInfo::Ptr webApp; + + /** + * @brief Optional. Deep-linking (https://core.telegram.org/bots/features#deep-linking) parameter for the /start message sent to the bot when a user presses the button. 1-64 characters, only A-Z, a-z, 0-9, _ and - are allowed. + * + * Example: An inline bot that sends YouTube videos can ask the user to connect the bot to their YouTube account to adapt search results accordingly. + * To do this, it displays a 'Connect your YouTube account' button above the results, or even before showing any. + * The user presses the button, switches to a private chat with the bot and, in doing so, passes a start parameter that instructs the bot to return an OAuth link. + * Once done, the bot can offer a switchInline button so that the user can easily return to the chat where they wanted to use the bot's inline capabilities. + */ + std::string startParameter; +}; +} + +#endif //TGBOT_INLINEQUERYRESULTSBUTTON_H diff --git a/include/tgbot/types/InputSticker.h b/include/tgbot/types/InputSticker.h index f71107e76..06dafd271 100644 --- a/include/tgbot/types/InputSticker.h +++ b/include/tgbot/types/InputSticker.h @@ -20,7 +20,7 @@ class InputSticker { /** * @brief The added sticker. - * Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. + * Pass a fileId as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, upload a new one using multipart/form-data, or pass “attach://” to upload a new one using multipart/form-data under name. * Animated and video stickers can't be uploaded via HTTP URL. https://core.telegram.org/bots/api#sending-files */ std::string sticker; diff --git a/include/tgbot/types/KeyboardButtonRequestChat.h b/include/tgbot/types/KeyboardButtonRequestChat.h index 9e446d83b..92e858df5 100644 --- a/include/tgbot/types/KeyboardButtonRequestChat.h +++ b/include/tgbot/types/KeyboardButtonRequestChat.h @@ -10,7 +10,9 @@ namespace TgBot { /** * @brief This object defines the criteria used to request a suitable chat. + * * The identifier of the selected chat will be shared with the bot when the corresponding button is pressed. + * https://core.telegram.org/bots/features#chat-and-user-selection * * @ingroup types */ diff --git a/include/tgbot/types/KeyboardButtonRequestUser.h b/include/tgbot/types/KeyboardButtonRequestUser.h index 3463e4911..3ec6f1638 100644 --- a/include/tgbot/types/KeyboardButtonRequestUser.h +++ b/include/tgbot/types/KeyboardButtonRequestUser.h @@ -8,7 +8,9 @@ namespace TgBot { /** * @brief This object defines the criteria used to request a suitable user. + * * The identifier of the selected user will be shared with the bot when the corresponding button is pressed. + * https://core.telegram.org/bots/features#chat-and-user-selection * * @ingroup types */ diff --git a/include/tgbot/types/SwitchInlineQueryChosenChat.h b/include/tgbot/types/SwitchInlineQueryChosenChat.h new file mode 100644 index 000000000..b0ecf2cba --- /dev/null +++ b/include/tgbot/types/SwitchInlineQueryChosenChat.h @@ -0,0 +1,46 @@ +#ifndef TGBOT_SWITCHINLINEQUERYCHOSENCHAT_H +#define TGBOT_SWITCHINLINEQUERYCHOSENCHAT_H + +#include +#include + +namespace TgBot { + +/** + * @brief This object represents an inline button that switches the current user to inline mode in a chosen chat, with an optional default inline query. + * + * @ingroup types + */ +class SwitchInlineQueryChosenChat { + +public: + typedef std::shared_ptr Ptr; + + /** + * @brief Optional. The default inline query to be inserted in the input field. If left empty, only the bot's username will be inserted + */ + std::string query; + + /** + * @brief Optional. True, if private chats with users can be chosen + */ + bool allowUserChats; + + /** + * @brief Optional. True, if private chats with bots can be chosen + */ + bool allowBotChats; + + /** + * @brief Optional. True, if group and supergroup chats can be chosen + */ + bool allowGroupChats; + + /** + * @brief Optional. True, if channel chats can be chosen + */ + bool allowChannelChats; +}; +} + +#endif //TGBOT_SWITCHINLINEQUERYCHOSENCHAT_H diff --git a/include/tgbot/types/WriteAccessAllowed.h b/include/tgbot/types/WriteAccessAllowed.h index d01aa3134..e3138dfc0 100644 --- a/include/tgbot/types/WriteAccessAllowed.h +++ b/include/tgbot/types/WriteAccessAllowed.h @@ -2,19 +2,23 @@ #define TGBOT_WRITEACCESSALLOWED_H #include +#include namespace TgBot { /** - * @brief This object represents a service message about a user allowing a bot added to the attachment menu to write messages. - * - * Currently holds no information. + * @brief This object represents a service message about a user allowing a bot to write messages after adding the bot to the attachment menu or launching a Web App from a link. * * @ingroup types */ class WriteAccessAllowed { public: typedef std::shared_ptr Ptr; + + /** + * @brief Optional. Name of the Web App which was launched from a link + */ + std::string webAppName; }; } diff --git a/src/Api.cpp b/src/Api.cpp index bb0ac454c..8a91aee0e 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -1736,6 +1736,32 @@ std::vector Api::getMyCommands(BotCommandScope::Ptr scope, return _tgTypeParser.parseJsonAndGetArray(&TgTypeParser::parseJsonAndGetBotCommand, sendRequest("getMyCommands", args)); } +bool Api::setMyName(const std::string& name, + const std::string& languageCode) const { + std::vector args; + args.reserve(2); + + if (!name.empty()) { + args.emplace_back("name", name); + } + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return sendRequest("setMyName", args).get("", false); +} + +BotName::Ptr Api::getMyName(const std::string& languageCode) const { + std::vector args; + args.reserve(1); + + if (!languageCode.empty()) { + args.emplace_back("language_code", languageCode); + } + + return _tgTypeParser.parseJsonAndGetBotName(sendRequest("getMyName", args)); +} + bool Api::setMyDescription(const std::string& description, const std::string& languageCode) const { std::vector args; @@ -2271,27 +2297,23 @@ bool Api::answerInlineQuery(const std::string& inlineQueryId, std::int32_t cacheTime, bool isPersonal, const std::string& nextOffset, - const std::string& switchPmText, - const std::string& switchPmParameter) const { + InlineQueryResultsButton::Ptr button) const { std::vector args; - args.reserve(7); + args.reserve(6); args.emplace_back("inline_query_id", inlineQueryId); args.emplace_back("results", _tgTypeParser.parseArray(&TgTypeParser::parseInlineQueryResult, results)); - if (cacheTime) { + if (cacheTime != 300) { args.emplace_back("cache_time", cacheTime); } - if (isPersonal) { + if (isPersonal != false) { args.emplace_back("is_personal", isPersonal); } if (!nextOffset.empty()) { args.emplace_back("next_offset", nextOffset); } - if (!switchPmText.empty()) { - args.emplace_back("switch_pm_text", switchPmText); - } - if (!switchPmParameter.empty()) { - args.emplace_back("switch_pm_parameter", switchPmParameter); + if (button != nullptr) { + args.emplace_back("button", _tgTypeParser.parseInlineQueryResultsButton(button)); } return sendRequest("answerInlineQuery", args).get("", false); diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index efd1c0822..76a4addf2 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -1109,6 +1109,7 @@ std::string TgTypeParser::parseChatShared(const ChatShared::Ptr& object) const { WriteAccessAllowed::Ptr TgTypeParser::parseJsonAndGetWriteAccessAllowed(const boost::property_tree::ptree& data) const { auto result(std::make_shared()); + result->webAppName = data.get("web_app_name", ""); return result; } @@ -1118,7 +1119,8 @@ std::string TgTypeParser::parseWriteAccessAllowed(const WriteAccessAllowed::Ptr& } std::string result; result += '{'; - //removeLastComma(result); + appendToJson(result, "web_app_name", object->webAppName); + removeLastComma(result); result += '}'; return result; } @@ -1456,10 +1458,12 @@ InlineKeyboardButton::Ptr TgTypeParser::parseJsonAndGetInlineKeyboardButton(cons result->loginUrl = tryParseJson(&TgTypeParser::parseJsonAndGetLoginUrl, data, "login_url"); result->switchInlineQuery = data.get("switch_inline_query", ""); result->switchInlineQueryCurrentChat = data.get("switch_inline_query_current_chat", ""); + result->switchInlineQueryChosenChat = tryParseJson(&TgTypeParser::parseJsonAndGetSwitchInlineQueryChosenChat, data, "switch_inline_query_chosen_chat"); result->callbackGame = tryParseJson(&TgTypeParser::parseJsonAndGetCallbackGame, data, "callback_game"); result->pay = data.get("pay", false); return result; } + std::string TgTypeParser::parseInlineKeyboardButton(const InlineKeyboardButton::Ptr& object) const { if (!object) { return ""; @@ -1473,6 +1477,7 @@ std::string TgTypeParser::parseInlineKeyboardButton(const InlineKeyboardButton:: appendToJson(result, "login_url", parseLoginUrl(object->loginUrl)); appendToJson(result, "switch_inline_query", object->switchInlineQuery); appendToJson(result, "switch_inline_query_current_chat", object->switchInlineQueryCurrentChat); + appendToJson(result, "switch_inline_query_chosen_chat", parseSwitchInlineQueryChosenChat(object->switchInlineQueryChosenChat)); appendToJson(result, "callback_game", parseCallbackGame(object->callbackGame)); appendToJson(result, "pay", object->pay); removeLastComma(result); @@ -1504,6 +1509,32 @@ std::string TgTypeParser::parseLoginUrl(const LoginUrl::Ptr& object) const { return result; } +SwitchInlineQueryChosenChat::Ptr TgTypeParser::parseJsonAndGetSwitchInlineQueryChosenChat(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->query = data.get("query", ""); + result->allowUserChats = data.get("allow_user_chats", false); + result->allowBotChats = data.get("allow_bot_chats", false); + result->allowGroupChats = data.get("allow_group_chats", false); + result->allowChannelChats = data.get("allow_channel_chats", false); + return result; +} + +std::string TgTypeParser::parseSwitchInlineQueryChosenChat(const SwitchInlineQueryChosenChat::Ptr& object) const { + if (!object) { + return ""; + } + std::string result; + result += '{'; + appendToJson(result, "query", object->query); + appendToJson(result, "allow_user_chats", object->allowUserChats); + appendToJson(result, "allow_bot_chats", object->allowBotChats); + appendToJson(result, "allow_group_chats", object->allowGroupChats); + appendToJson(result, "allow_channel_chats", object->allowChannelChats); + removeLastComma(result); + result += '}'; + return result; +} + CallbackQuery::Ptr TgTypeParser::parseJsonAndGetCallbackQuery(const boost::property_tree::ptree& data) const { auto result(std::make_shared()); result->id = data.get("id"); @@ -1880,10 +1911,11 @@ ChatMemberUpdated::Ptr TgTypeParser::parseJsonAndGetChatMemberUpdated(const boos auto result(std::make_shared()); result->chat = tryParseJson(&TgTypeParser::parseJsonAndGetChat, data, "chat"); result->from = tryParseJson(&TgTypeParser::parseJsonAndGetUser, data, "from"); - result->date = data.get("date", 0); + result->date = data.get("date", 0); result->oldChatMember = tryParseJson(&TgTypeParser::parseJsonAndGetChatMember, data, "old_chat_member"); result->newChatMember = tryParseJson(&TgTypeParser::parseJsonAndGetChatMember, data, "new_chat_member"); result->inviteLink = tryParseJson(&TgTypeParser::parseJsonAndGetChatInviteLink, data, "invite_link"); + result->viaChatFolderInviteLink = data.get("via_chat_folder_invite_link", false); return result; } @@ -1899,6 +1931,7 @@ std::string TgTypeParser::parseChatMemberUpdated(const ChatMemberUpdated::Ptr& o appendToJson(result, "old_chat_member", parseChatMember(object->oldChatMember)); appendToJson(result, "new_chat_member", parseChatMember(object->newChatMember)); appendToJson(result, "invite_link", parseChatInviteLink(object->inviteLink)); + appendToJson(result, "via_chat_folder_invite_link", object->viaChatFolderInviteLink); removeLastComma(result); result += '}'; return result; @@ -2220,6 +2253,21 @@ std::string TgTypeParser::parseBotCommandScopeChatMember(const BotCommandScopeCh return result; } +BotName::Ptr TgTypeParser::parseJsonAndGetBotName(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->name = data.get("name", ""); + return result; +} + +std::string TgTypeParser::parseBotName(const BotName::Ptr& object) const { + std::string result; + result += '{'; + appendToJson(result, "name", object->name); + removeLastComma(result); + result += '}'; + return result; +} + BotDescription::Ptr TgTypeParser::parseJsonAndGetBotDescription(const boost::property_tree::ptree& data) const { auto result(std::make_shared()); result->description = data.get("description", ""); @@ -2734,6 +2782,28 @@ std::string TgTypeParser::parseInlineQuery(const InlineQuery::Ptr& object) const return result; } +InlineQueryResultsButton::Ptr TgTypeParser::parseJsonAndGetInlineQueryResultsButton(const boost::property_tree::ptree& data) const { + auto result(std::make_shared()); + result->text = data.get("text", ""); + result->webApp = tryParseJson(&TgTypeParser::parseJsonAndGetWebAppInfo, data, "web_app"); + result->startParameter = data.get("start_parameter", ""); + return result; +} + +std::string TgTypeParser::parseInlineQueryResultsButton(const InlineQueryResultsButton::Ptr& object) const { + if (!object) { + return ""; + } + std::string result; + result += '{'; + appendToJson(result, "text", object->text); + appendToJson(result, "web_app", parseWebAppInfo(object->webApp)); + appendToJson(result, "start_parameter", object->startParameter); + removeLastComma(result); + result += '}'; + return result; +} + InlineQueryResult::Ptr TgTypeParser::parseJsonAndGetInlineQueryResult(const boost::property_tree::ptree& data) const { std::string type = data.get("type", ""); InlineQueryResult::Ptr result; From 5aaaa79ee2441dd36a3af4e1c869717bf9b2c927 Mon Sep 17 00:00:00 2001 From: llnulldisk <48621230+llnulldisk@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:46:10 +0200 Subject: [PATCH 04/11] Update to Bot API 6.8 --- README.md | 2 +- include/tgbot/Api.h | 11 ++++ include/tgbot/TgTypeParser.h | 4 ++ include/tgbot/types/Chat.h | 7 +++ include/tgbot/types/InlineKeyboardButton.h | 10 ++-- include/tgbot/types/Message.h | 14 +++-- include/tgbot/types/PollAnswer.h | 20 ++++--- include/tgbot/types/Story.h | 22 ++++++++ src/Api.cpp | 9 ++++ src/TgTypeParser.cpp | 61 +++++++++++++++------- 10 files changed, 127 insertions(+), 33 deletions(-) create mode 100644 include/tgbot/types/Story.h diff --git a/README.md b/README.md index 5b4bb7217..c21a4c3c4 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Documentation is located [here](http://reo7sp.github.io/tgbot-cpp). ## State -- [x] Telegram Bot API 6.7 +- [x] Telegram Bot API 6.8 - [ ] [Deep Linking](https://core.telegram.org/bots/features#deep-linking) diff --git a/include/tgbot/Api.h b/include/tgbot/Api.h index 5efe50fe0..c3df15c16 100644 --- a/include/tgbot/Api.h +++ b/include/tgbot/Api.h @@ -1349,6 +1349,17 @@ friend class Bot; */ bool unhideGeneralForumTopic(boost::variant chatId) const; + /** + * @brief Use this method to clear the list of pinned messages in a General forum topic. + * + * The bot must be an administrator in the chat for this to work and must have the canPinMessages administrator right in the supergroup. + * + * @param chatId Unique identifier for the target chat or username of the target supergroup (in the format @supergroupusername) + * + * @return Returns True on success. + */ + bool unpinAllGeneralForumTopicMessages(boost::variant chatId) const; + /** * @brief Use this method to send answers to callback queries sent from inline keyboards. * diff --git a/include/tgbot/TgTypeParser.h b/include/tgbot/TgTypeParser.h index 99a38a932..ad610df7d 100644 --- a/include/tgbot/TgTypeParser.h +++ b/include/tgbot/TgTypeParser.h @@ -13,6 +13,7 @@ #include "tgbot/types/Animation.h" #include "tgbot/types/Audio.h" #include "tgbot/types/Document.h" +#include "tgbot/types/Story.h" #include "tgbot/types/Video.h" #include "tgbot/types/VideoNote.h" #include "tgbot/types/Voice.h" @@ -205,6 +206,9 @@ class TGBOT_API TgTypeParser { Document::Ptr parseJsonAndGetDocument(const boost::property_tree::ptree& data) const; std::string parseDocument(const Document::Ptr& object) const; + Story::Ptr parseJsonAndGetStory(const boost::property_tree::ptree& data) const; + std::string parseStory(const Story::Ptr& object) const; + Video::Ptr parseJsonAndGetVideo(const boost::property_tree::ptree& data) const; std::string parseVideo(const Video::Ptr& object) const; diff --git a/include/tgbot/types/Chat.h b/include/tgbot/types/Chat.h index 24013004c..e8380460d 100644 --- a/include/tgbot/types/Chat.h +++ b/include/tgbot/types/Chat.h @@ -90,6 +90,13 @@ class Chat { */ std::string emojiStatusCustomEmojiId; + /** + * @brief Optional. Expiration date of the emoji status of the other party in a private chat, if any. + * + * Returned only in Api::getChat. + */ + std::int64_t emojiStatusExpirationDate; + /** * @brief Optional. Bio of the other party in a private chat. * diff --git a/include/tgbot/types/InlineKeyboardButton.h b/include/tgbot/types/InlineKeyboardButton.h index 1f2e16f66..3b59ce81b 100644 --- a/include/tgbot/types/InlineKeyboardButton.h +++ b/include/tgbot/types/InlineKeyboardButton.h @@ -13,6 +13,7 @@ namespace TgBot { /** * @brief This object represents one button of an inline keyboard. + * * You must use exactly one of the optional fields. * * @ingroup types @@ -28,6 +29,7 @@ class InlineKeyboardButton { /** * @brief Optional. HTTP or tg:// URL to be opened when the button is pressed. + * * Links tg://user?id= can be used to mention a user by their ID without using a username, if this is allowed by their privacy settings. */ std::string url; @@ -39,6 +41,7 @@ class InlineKeyboardButton { /** * @brief Optional. Description of the Web App that will be launched when the user presses the button. + * * The Web App will be able to send an arbitrary message on behalf of the user using the method Api::answerWebAppQuery. * Available only in private chats between a user and the bot. */ @@ -46,23 +49,22 @@ class InlineKeyboardButton { /** * @brief Optional. An HTTPS URL used to automatically authorize the user. + * * Can be used as a replacement for the Telegram Login Widget. */ LoginUrl::Ptr loginUrl; /** * @brief Optional. If set, pressing the button will prompt the user to select one of their chats, open that chat and insert the bot's username and the specified inline query in the input field. + * * May be empty, in which case just the bot's username will be inserted. - * - * Note: This offers an easy way for users to start using your bot in inline mode when they are currently in a private chat with it. - * Especially useful when combined with switch_pm… actions - in this case the user will be automatically returned to the chat they switched from, skipping the chat selection screen. */ std::string switchInlineQuery; /** * @brief Optional. If set, pressing the button will insert the bot's username and the specified inline query in the current chat's input field. - * May be empty, in which case only the bot's username will be inserted. * + * May be empty, in which case only the bot's username will be inserted. * This offers a quick way for the user to open your bot in inline mode in the same chat - good for selecting something from multiple options. */ std::string switchInlineQueryCurrentChat; diff --git a/include/tgbot/types/Message.h b/include/tgbot/types/Message.h index 8ed830040..a38dd01a0 100644 --- a/include/tgbot/types/Message.h +++ b/include/tgbot/types/Message.h @@ -10,6 +10,7 @@ #include "tgbot/types/Document.h" #include "tgbot/types/PhotoSize.h" #include "tgbot/types/Sticker.h" +#include "tgbot/types/Story.h" #include "tgbot/types/Video.h" #include "tgbot/types/VideoNote.h" #include "tgbot/types/Voice.h" @@ -41,9 +42,9 @@ #include "tgbot/types/InlineKeyboardMarkup.h" #include +#include #include #include -#include namespace TgBot { @@ -84,7 +85,7 @@ class Message { /** * @brief Date the message was sent in Unix time */ - std::int32_t date; + std::int64_t date; /** * @brief Conversation the message belongs to @@ -119,7 +120,7 @@ class Message { /** * @brief Optional. For forwarded messages, date the original message was sent in Unix time */ - std::int32_t forwardDate; + std::int64_t forwardDate; /** * @brief Optional. True, if the message is sent to a forum topic @@ -146,7 +147,7 @@ class Message { /** * @brief Optional. Date the message was last edited in Unix time */ - std::int32_t editDate; + std::int64_t editDate; /** * @brief Optional. True, if the message can't be forwarded @@ -200,6 +201,11 @@ class Message { */ Sticker::Ptr sticker; + /** + * @brief Optional. Message is a forwarded story + */ + Story::Ptr story; + /** * @brief Optional. Message is a video, information about the video */ diff --git a/include/tgbot/types/PollAnswer.h b/include/tgbot/types/PollAnswer.h index 4476d637f..af9637786 100644 --- a/include/tgbot/types/PollAnswer.h +++ b/include/tgbot/types/PollAnswer.h @@ -1,8 +1,10 @@ -#ifndef TGBOT_CPP_POLLANSWER_H -#define TGBOT_CPP_POLLANSWER_H +#ifndef TGBOT_POLLANSWER_H +#define TGBOT_POLLANSWER_H +#include "tgbot/types/Chat.h" #include "tgbot/types/User.h" +#include #include #include #include @@ -25,16 +27,22 @@ class PollAnswer { std::string pollId; /** - * @brief The user, who changed the answer to the poll + * @brief Optional. The chat that changed the answer to the poll, if the voter is anonymous + */ + Chat::Ptr voterChat; + + /** + * @brief Optional. The user that changed the answer to the poll, if the voter isn't anonymous */ User::Ptr user; /** - * @brief 0-based identifiers of answer options, chosen by the user. - * May be empty if the user retracted their vote. + * @brief 0-based identifiers of chosen answer options. + * + * May be empty if the vote was retracted. */ std::vector optionIds; }; } -#endif //TGBOT_CPP_POLLANSWER_H +#endif //TGBOT_POLLANSWER_H diff --git a/include/tgbot/types/Story.h b/include/tgbot/types/Story.h new file mode 100644 index 000000000..98fd70179 --- /dev/null +++ b/include/tgbot/types/Story.h @@ -0,0 +1,22 @@ +#ifndef TGBOT_STORY_H +#define TGBOT_STORY_H + +#include + +namespace TgBot { + +/** + * @brief This object represents a message about a forwarded story in the chat. + * + * Currently holds no information. + * + * @ingroup types + */ +class Story { + +public: + typedef std::shared_ptr Ptr; +}; +} + +#endif //TGBOT_STORY_H diff --git a/src/Api.cpp b/src/Api.cpp index 8a91aee0e..b3ce4eaf3 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -1664,6 +1664,15 @@ bool Api::unhideGeneralForumTopic(boost::variant chat return sendRequest("unhideGeneralForumTopic", args).get("", false); } +bool Api::unpinAllGeneralForumTopicMessages(boost::variant chatId) const { + std::vector args; + args.reserve(1); + + args.emplace_back("chat_id", chatId); + + return sendRequest("unpinAllGeneralForumTopicMessages", args).get("", false); +} + bool Api::answerCallbackQuery(const std::string& callbackQueryId, const std::string& text, bool showAlert, diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index 76a4addf2..86a25c170 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -152,6 +152,7 @@ Chat::Ptr TgTypeParser::parseJsonAndGetChat(const boost::property_tree::ptree& d return innerData.get(""); }, data, "active_usernames"); result->emojiStatusCustomEmojiId = data.get("emoji_status_custom_emoji_id", ""); + result->emojiStatusExpirationDate = data.get("emoji_status_expiration_date", 0); result->bio = data.get("bio", ""); result->hasPrivateForwards = data.get("has_private_forwards", false); result->hasRestrictedVoiceAndVideoMessages = data.get("has_restricted_voice_and_video_messages", false); @@ -200,6 +201,7 @@ std::string TgTypeParser::parseChat(const Chat::Ptr& object) const { return s; }, object->activeUsernames)); appendToJson(result, "emoji_status_custom_emoji_id", object->emojiStatusCustomEmojiId); + appendToJson(result, "emoji_status_expiration_date", object->emojiStatusExpirationDate); appendToJson(result, "bio", object->bio); appendToJson(result, "has_private_forwards", object->hasPrivateForwards); appendToJson(result, "has_restricted_voice_and_video_messages", object->hasRestrictedVoiceAndVideoMessages); @@ -229,19 +231,19 @@ Message::Ptr TgTypeParser::parseJsonAndGetMessage(const boost::property_tree::pt result->messageThreadId = data.get("message_thread_id", 0); result->from = tryParseJson(&TgTypeParser::parseJsonAndGetUser, data, "from"); result->senderChat = tryParseJson(&TgTypeParser::parseJsonAndGetChat, data, "sender_chat"); - result->date = data.get("date", 0); + result->date = data.get("date", 0); result->chat = parseJsonAndGetChat(data.find("chat")->second); result->forwardFrom = tryParseJson(&TgTypeParser::parseJsonAndGetUser, data, "forward_from"); result->forwardFromChat = tryParseJson(&TgTypeParser::parseJsonAndGetChat, data, "forward_from_chat"); result->forwardFromMessageId = data.get("forward_from_message_id", 0); result->forwardSignature = data.get("forward_signature", ""); result->forwardSenderName = data.get("forward_sender_name", ""); - result->forwardDate = data.get("forward_date", 0); + result->forwardDate = data.get("forward_date", 0); result->isTopicMessage = data.get("is_topic_message", false); result->isAutomaticForward = data.get("is_automatic_forward", false); result->replyToMessage = tryParseJson(&TgTypeParser::parseJsonAndGetMessage, data, "reply_to_message"); result->viaBot = tryParseJson(&TgTypeParser::parseJsonAndGetUser, data, "via_bot"); - result->editDate = data.get("edit_date", 0); + result->editDate = data.get("edit_date", 0); result->hasProtectedContent = data.get("has_protected_content", false); result->mediaGroupId = data.get("media_group_id", ""); result->authorSignature = data.get("author_signature", ""); @@ -252,6 +254,7 @@ Message::Ptr TgTypeParser::parseJsonAndGetMessage(const boost::property_tree::pt result->document = tryParseJson(&TgTypeParser::parseJsonAndGetDocument, data, "document"); result->photo = parseJsonAndGetArray(&TgTypeParser::parseJsonAndGetPhotoSize, data, "photo"); result->sticker = tryParseJson(&TgTypeParser::parseJsonAndGetSticker, data, "sticker"); + result->story = tryParseJson(&TgTypeParser::parseJsonAndGetStory, data, "story"); result->video = tryParseJson