From 58c2f0165c894fa1a2e902fbd14ac3723729c8f1 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 8 Mar 2024 14:50:28 +0300 Subject: [PATCH 01/42] Update TDLib to 1.8.26. --- td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td b/td index d93a99e..b3b63bb 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit d93a99e3351db82573d765ce4f5e84714c277518 +Subproject commit b3b63bbdc14dc377d2de6b78e5844fec1564f95d From a19b05e4ff50aac0239fa1ad4a9b973560d3e36d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 11 Mar 2024 22:28:39 +0300 Subject: [PATCH 02/42] Fix warnings. --- telegram-bot-api/Client.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 07833f3..6979a86 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1078,8 +1078,8 @@ class Client::JsonMessages final : public td::Jsonable { class Client::JsonLinkPreviewOptions final : public td::Jsonable { public: - JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options, const Client *client) - : link_preview_options_(link_preview_options), client_(client) { + explicit JsonLinkPreviewOptions(const td_api::linkPreviewOptions *link_preview_options) + : link_preview_options_(link_preview_options) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -1102,7 +1102,6 @@ class Client::JsonLinkPreviewOptions final : public td::Jsonable { private: const td_api::linkPreviewOptions *link_preview_options_; - const Client *client_; }; class Client::JsonAnimation final : public td::Jsonable { @@ -2277,7 +2276,7 @@ class Client::JsonExternalReplyInfo final : public td::Jsonable { case td_api::messageText::ID: { auto content = static_cast(reply_->content_.get()); if (content->link_preview_options_ != nullptr) { - object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -2514,7 +2513,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("entities", JsonVectorEntities(content->text_->entities_, client_)); } if (content->link_preview_options_ != nullptr) { - object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get(), client_)); + object("link_preview_options", JsonLinkPreviewOptions(content->link_preview_options_.get())); } break; } @@ -6203,8 +6202,8 @@ void Client::on_update(object_ptr result) { auto group_info = add_group_info(group_id); group_info->photo = std::move(full_info->photo_); group_info->description = std::move(full_info->description_); - group_info->invite_link = std::move( - full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); + group_info->invite_link = + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string(); break; } case td_api::updateSupergroup::ID: { @@ -6220,8 +6219,8 @@ void Client::on_update(object_ptr result) { auto supergroup_info = add_supergroup_info(supergroup_id); supergroup_info->photo = std::move(full_info->photo_); supergroup_info->description = std::move(full_info->description_); - supergroup_info->invite_link = std::move( - full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string()); + supergroup_info->invite_link = + full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) : td::string(); supergroup_info->sticker_set_id = full_info->sticker_set_id_; supergroup_info->custom_emoji_sticker_set_id = full_info->custom_emoji_sticker_set_id_; supergroup_info->can_set_sticker_set = full_info->can_set_sticker_set_; From de02ab0a009d76f83767ac7831ea235640b3b73b Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 14:47:41 +0300 Subject: [PATCH 03/42] Update TDLib to 1.8.27. --- td | 2 +- telegram-bot-api/Client.cpp | 97 ++++++++++++++++++++++--------------- telegram-bot-api/Client.h | 6 +-- 3 files changed, 61 insertions(+), 44 deletions(-) diff --git a/td b/td index b3b63bb..efc6bd5 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit b3b63bbdc14dc377d2de6b78e5844fec1564f95d +Subproject commit efc6bd553b61dea0ae8c0436695e8d2539bf03f9 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 6979a86..423eaf9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1983,7 +1983,7 @@ class Client::JsonUserShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_id", users_shared_->user_ids_[0]); + object("user_id", users_shared_->users_[0]->user_id_); object("request_id", users_shared_->button_id_); } @@ -1997,7 +1997,7 @@ class Client::JsonUsersShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("user_ids", td::json_array(users_shared_->user_ids_, [](int64 user_id) { return user_id; })); + object("user_ids", td::json_array(users_shared_->users_, [](auto &user) { return user->user_id_; })); object("request_id", users_shared_->button_id_); } @@ -2011,7 +2011,7 @@ class Client::JsonChatShared final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat_id", chat_shared_->chat_id_); + object("chat_id", chat_shared_->chat_->chat_id_); object("request_id", chat_shared_->button_id_); } @@ -2827,7 +2827,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageUsersShared::ID: { auto content = static_cast(message_->content.get()); - if (content->user_ids_.size() == 1) { + if (content->users_.size() == 1) { object("user_shared", JsonUserShared(content)); } object("users_shared", JsonUsersShared(content)); @@ -3654,10 +3654,6 @@ class Client::JsonStickerSet final : public td::Jsonable { client_->json_store_thumbnail(object, sticker_set_->thumbnail_.get()); } - auto format = sticker_set_->sticker_format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - auto type = Client::get_sticker_type(sticker_set_->sticker_type_); object("sticker_type", type); object("contains_masks", td::JsonBool(type == "mask")); @@ -6591,8 +6587,9 @@ td::Result> Client::get_keyboard_butt TRY_RESULT(user_is_premium, request_user_object.get_optional_bool_field("user_is_premium")); TRY_RESULT(max_quantity, request_user_object.get_optional_int_field("max_quantity", 1)); return make_object( - text, make_object( - id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity)); + text, make_object(id, restrict_user_is_bot, user_is_bot, + restrict_user_is_premium, user_is_premium, + max_quantity, false, false, false)); } if (object.has_field("request_chat")) { @@ -6621,7 +6618,7 @@ td::Result> Client::get_keyboard_butt text, make_object( id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, chat_has_username, chat_is_created, std::move(user_administrator_rights), - std::move(bot_administrator_rights), bot_is_member)); + std::move(bot_administrator_rights), bot_is_member, false, false, false)); } return make_object(text, nullptr); @@ -7918,11 +7915,15 @@ td::Result> Client::get_sticker_format if (sticker_format == "video") { return make_object(); } + if (sticker_format == "auto") { + return nullptr; + } return td::Status::Error(400, "Invalid sticker format specified"); } td::Result> Client::get_input_sticker(const Query *query, - td::JsonValue &&value) const { + td::JsonValue &&value, + td::Slice default_sticker_format) const { if (value.type() != td::JsonValue::Type::Object) { return td::Status::Error(400, "InputSticker must be an Object"); } @@ -7934,6 +7935,16 @@ td::Result> Client::get_input_sticker(c if (input_file == nullptr) { return td::Status::Error(400, "sticker not found"); } + td::string sticker_format_str; + if (default_sticker_format.empty()) { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_required_string_field("format")); + } else { + TRY_RESULT_ASSIGN(sticker_format_str, object.get_optional_string_field("format")); + if (sticker_format_str.empty()) { + sticker_format_str = default_sticker_format.str(); + } + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); TRY_RESULT(emoji_list, object.extract_required_field("emoji_list", td::JsonValue::Type::Array)); TRY_RESULT(emojis, get_sticker_emojis(std::move(emoji_list))); TRY_RESULT(mask_position, get_mask_position(object.extract_field("mask_position"))); @@ -7947,8 +7958,8 @@ td::Result> Client::get_input_sticker(c input_keywords.push_back(keyword.get_string().str()); } } - return make_object(std::move(input_file), emojis, std::move(mask_position), - std::move(input_keywords)); + return make_object(std::move(input_file), std::move(sticker_format), emojis, + std::move(mask_position), std::move(input_keywords)); } td::Result> Client::get_input_sticker(const Query *query) const { @@ -7961,7 +7972,7 @@ td::Result> Client::get_input_sticker(c return td::Status::Error(400, "Can't parse sticker JSON object"); } - auto r_sticker = get_input_sticker(query, r_value.move_as_ok()); + auto r_sticker = get_input_sticker(query, r_value.move_as_ok(), "auto"); if (r_sticker.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse sticker: " << r_sticker.error().message()); } @@ -7971,14 +7982,20 @@ td::Result> Client::get_input_sticker(c auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); + object_ptr sticker_format; object_ptr mask_position; if (sticker != nullptr) { + sticker_format = make_object(); TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position")); } else { sticker = get_input_file(query, "tgs_sticker", true); - if (sticker == nullptr) { + if (sticker != nullptr) { + sticker_format = make_object(); + } else { sticker = get_input_file(query, "webm_sticker", true); - if (sticker == nullptr) { + if (sticker != nullptr) { + sticker_format = make_object(); + } else { if (!query->arg("tgs_sticker").empty()) { return td::Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile"); } @@ -7990,14 +8007,13 @@ td::Result> Client::get_input_sticker(c } } - return make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector()); + return make_object(std::move(sticker), std::move(sticker_format), emojis.str(), + std::move(mask_position), td::vector()); } -td::Result>> Client::get_input_stickers( - const Query *query, object_ptr &sticker_format) const { +td::Result>> Client::get_input_stickers(const Query *query) const { if (query->has_arg("stickers")) { - TRY_RESULT_ASSIGN(sticker_format, get_sticker_format(query->arg("sticker_format"))); + auto sticker_format_str = query->arg("sticker_format"); auto stickers = query->arg("stickers"); LOG(INFO) << "Parsing JSON object: " << stickers; auto r_value = json_decode(stickers); @@ -8018,7 +8034,7 @@ td::Result>> Client::get_inp td::vector> input_stickers; for (auto &input_sticker : value.get_array()) { - auto r_input_sticker = get_input_sticker(query, std::move(input_sticker)); + auto r_input_sticker = get_input_sticker(query, std::move(input_sticker), sticker_format_str); if (r_input_sticker.is_error()) { return td::Status::Error(400, PSLICE() << "Can't parse InputSticker: " << r_input_sticker.error().message()); } @@ -8030,6 +8046,7 @@ td::Result>> Client::get_inp auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); + object_ptr sticker_format; object_ptr mask_position; if (sticker != nullptr) { sticker_format = make_object(); @@ -8055,8 +8072,8 @@ td::Result>> Client::get_inp } td::vector> stickers; - stickers.push_back(make_object(std::move(sticker), emojis.str(), std::move(mask_position), - td::vector())); + stickers.push_back(make_object(std::move(sticker), std::move(sticker_format), emojis.str(), + std::move(mask_position), td::vector())); return std::move(stickers); } @@ -9618,8 +9635,9 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, message_thread_id, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, message_thread_id, std::move(action)), - td::make_unique(std::move(query))); + send_request( + make_object(chat_id, message_thread_id, td::string(), std::move(action)), + td::make_unique(std::move(query))); }); return td::Status::OK(); } @@ -10781,23 +10799,21 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) auto name = query->arg("name"); auto title = query->arg("title"); auto needs_repainting = to_bool(query->arg("needs_repainting")); - object_ptr sticker_format; - TRY_RESULT(stickers, get_input_stickers(query.get(), sticker_format)); + TRY_RESULT(stickers, get_input_stickers(query.get())); TRY_RESULT(sticker_type, get_sticker_type(query->arg("sticker_type"))); if (to_bool(query->arg("contains_masks"))) { sticker_type = make_object(); } - check_user( - user_id, std::move(query), - [this, user_id, title, name, sticker_format = std::move(sticker_format), sticker_type = std::move(sticker_type), - needs_repainting, stickers = std::move(stickers)](PromisedQueryPtr query) mutable { - send_request(make_object( - user_id, title.str(), name.str(), std::move(sticker_format), std::move(sticker_type), - needs_repainting, std::move(stickers), PSTRING() << "bot" << my_id_), - td::make_unique(this, false, std::move(query))); - }); + check_user(user_id, std::move(query), + [this, user_id, title, name, sticker_type = std::move(sticker_type), needs_repainting, + stickers = std::move(stickers)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, title.str(), name.str(), + std::move(sticker_type), needs_repainting, + std::move(stickers), PSTRING() << "bot" << my_id_), + td::make_unique(this, false, std::move(query))); + }); return td::Status::OK(); } @@ -10831,8 +10847,9 @@ td::Status Client::process_set_sticker_set_thumbnail_query(PromisedQueryPtr &que } check_user(user_id, std::move(query), [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { - send_request(make_object(user_id, name.str(), std::move(thumbnail)), - td::make_unique(std::move(query))); + send_request( + make_object(user_id, name.str(), std::move(thumbnail), nullptr), + td::make_unique(std::move(query))); }); return td::Status::OK(); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 25f0cf8..4c49c77 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -474,10 +474,10 @@ class Client final : public WebhookActor::Callback { td::Result> get_input_sticker(const Query *query) const; - td::Result> get_input_sticker(const Query *query, td::JsonValue &&value) const; + td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, + td::Slice default_sticker_format) const; - td::Result>> get_input_stickers( - const Query *query, object_ptr &sticker_format) const; + td::Result>> get_input_stickers(const Query *query) const; static td::Result> get_sticker_input_file(const Query *query); From 393b6c00fb864aa6d4ca0c556140b8e7b6cb646e Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 15:09:47 +0300 Subject: [PATCH 04/42] Add "business_connection" updates. --- telegram-bot-api/Client.cpp | 39 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 43 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 423eaf9..7cdd107 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3576,6 +3576,26 @@ class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { const Client *client_; }; +class Client::JsonBusinessConnection final : public td::Jsonable { + public: + JsonBusinessConnection(const td_api::businessConnection *connection, const Client *client) + : connection_(connection), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("id", connection_->id_); + object("user", JsonUser(connection_->user_id_, client_)); + object("user_chat_id", connection_->user_chat_id_); + object("date", connection_->date_); + object("can_reply", td::JsonBool(connection_->can_reply_)); + object("is_enabled", td::JsonBool(connection_->is_enabled_)); + } + + private: + const td_api::businessConnection *connection_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6330,6 +6350,9 @@ void Client::on_update(object_ptr result) { case td_api::updateMessageReactions::ID: add_update_message_reaction_count(move_object_as(result)); break; + case td_api::updateBusinessConnection::ID: + add_update_business_connection(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -11967,6 +11990,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("message_reaction"); case UpdateType::MessageReactionCount: return td::Slice("message_reaction_count"); + case UpdateType::BusinessConnection: + return td::Slice("business_connection"); default: UNREACHABLE(); return td::Slice(); @@ -12317,6 +12342,20 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { + CHECK(update != nullptr); + auto connection = std::move(update->connection_); + auto left_time = connection->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection.get(), this), left_time, + webhook_queue_id); + } else { + LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->date_ << ", because current date is " + << get_unix_time(); + } +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4c49c77..0f2a1c6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -163,6 +163,7 @@ class Client final : public WebhookActor::Callback { class JsonGameHighScore; class JsonMessageReactionUpdated; class JsonMessageReactionCountUpdated; + class JsonBusinessConnection; class JsonAddress; class JsonOrderInfo; class JsonStory; @@ -1017,6 +1018,8 @@ class Client final : public WebhookActor::Callback { void add_update_message_reaction_count(object_ptr &&update); + void add_update_business_connection(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1039,6 +1042,7 @@ class Client final : public WebhookActor::Callback { ChatBoostRemoved, MessageReaction, MessageReactionCount, + BusinessConnection, Size }; From a3f62fcdf72f7b20a5ac0e7fa6c44f1ed1d9beb7 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 15:44:44 +0300 Subject: [PATCH 05/42] Add cache for business connections. --- telegram-bot-api/Client.cpp | 31 ++++++++++++++++++++++++++----- telegram-bot-api/Client.h | 13 +++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7cdd107..e95a53c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3578,7 +3578,7 @@ class Client::JsonMessageReactionCountUpdated final : public td::Jsonable { class Client::JsonBusinessConnection final : public td::Jsonable { public: - JsonBusinessConnection(const td_api::businessConnection *connection, const Client *client) + JsonBusinessConnection(const BusinessConnection *connection, const Client *client) : connection_(connection), client_(client) { } void store(td::JsonValueScope *scope) const { @@ -3592,7 +3592,7 @@ class Client::JsonBusinessConnection final : public td::Jsonable { } private: - const td_api::businessConnection *connection_; + const BusinessConnection *connection_; const Client *client_; }; @@ -11839,6 +11839,28 @@ td::string Client::get_chat_description(int64 chat_id) const { } } +const Client::BusinessConnection *Client::add_business_connection( + object_ptr &&business_connection, bool from_update) { + CHECK(business_connection != nullptr); + auto &connection = business_connections_[business_connection->id_]; + if (connection == nullptr) { + connection = td::make_unique(); + } else if (!from_update) { + return connection.get(); + } + connection->id_ = std::move(business_connection->id_); + connection->user_id_ = business_connection->user_id_; + connection->user_chat_id_ = business_connection->user_chat_id_; + connection->date_ = business_connection->date_; + connection->can_reply_ = business_connection->can_reply_; + connection->is_enabled_ = business_connection->is_enabled_; + return connection.get(); +} + +const Client::BusinessConnection *Client::get_business_connection(const td::string &connection_id) const { + return business_connections_.get_pointer(connection_id); +} + void Client::json_store_file(td::JsonObjectScope &object, const td_api::file *file, bool with_path) const { if (file->id_ == 0) { return; @@ -12344,12 +12366,11 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { CHECK(update != nullptr); - auto connection = std::move(update->connection_); + const auto *connection = add_business_connection(std::move(update->connection_), true); auto left_time = connection->date_ + 86400 - get_unix_time(); if (left_time > 0) { auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); - add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection.get(), this), left_time, - webhook_queue_id); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), left_time, webhook_queue_id); } else { LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->date_ << ", because current date is " << get_unix_time(); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0f2a1c6..cd34b49 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -888,6 +888,18 @@ class Client final : public WebhookActor::Callback { mutable bool is_content_changed = false; }; + struct BusinessConnection { + td::string id_; + int64 user_id_ = 0; + int64 user_chat_id_ = 0; + int32 date_ = 0; + bool can_reply_ = false; + bool is_enabled_ = false; + }; + const BusinessConnection *add_business_connection(object_ptr &&business_connection, + bool from_update); + const BusinessConnection *get_business_connection(const td::string &connection_id) const; + static int64 get_same_chat_reply_to_message_id(const td_api::messageReplyToMessage *reply_to, int64 message_thread_id); @@ -1112,6 +1124,7 @@ class Client final : public WebhookActor::Callback { td::WaitFreeHashMap> groups_; td::WaitFreeHashMap> supergroups_; td::WaitFreeHashMap> chats_; + td::WaitFreeHashMap> business_connections_; td::FlatHashMap> file_download_listeners_; td::FlatHashSet download_started_file_ids_; From a731cb0083a89dff537d4f7121886d03f2799dab Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 16:09:23 +0300 Subject: [PATCH 06/42] Add Client::init_message. --- telegram-bot-api/Client.cpp | 13 +++++++++---- telegram-bot-api/Client.h | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e95a53c..06ca775 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12915,7 +12915,14 @@ Client::FullMessageId Client::add_message(object_ptr &&message, message_info = td::make_unique(); } - message_info->id = message_id; + init_message(message_info.get(), std::move(message), force_update_content); + + return {chat_id, message_id}; +} + +void Client::init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content) { + int64 chat_id = message->chat_id_; + message_info->id = message->id_; message_info->chat_id = chat_id; message_info->message_thread_id = message->message_thread_id_; message_info->date = message->date_; @@ -12997,11 +13004,9 @@ Client::FullMessageId Client::add_message(object_ptr &&message, } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); } - set_message_reply_markup(message_info.get(), std::move(message->reply_markup_)); + set_message_reply_markup(message_info, std::move(message->reply_markup_)); message = nullptr; - - return {chat_id, message_id}; } void Client::update_message_content(int64 chat_id, int64 message_id, object_ptr &&content) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index cd34b49..4fe12cc 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -924,7 +924,7 @@ class Client final : public WebhookActor::Callback { static bool are_equal_inline_keyboards(const td_api::replyMarkupInlineKeyboard *lhs, const td_api::replyMarkupInlineKeyboard *rhs); - void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); + static void set_message_reply_markup(MessageInfo *message_info, object_ptr &&reply_markup); static int64 get_sticker_set_id(const object_ptr &content); @@ -975,6 +975,7 @@ class Client final : public WebhookActor::Callback { }; FullMessageId add_message(object_ptr &&message, bool force_update_content = false); + void init_message(MessageInfo *message_info, object_ptr &&message, bool force_update_content); const MessageInfo *get_message(int64 chat_id, int64 message_id, bool force_cache) const; MessageInfo *get_message_editable(int64 chat_id, int64 message_id); From f05754481f5cb2cebd546cde2fc592db1a86d7da Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 20:07:18 +0300 Subject: [PATCH 07/42] Support business_connection_id with sendChatAction. --- telegram-bot-api/Client.cpp | 74 +++++++++++++++++++++++++++++++++---- telegram-bot-api/Client.h | 8 ++++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 06ca775..2391314 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4012,7 +4012,7 @@ class Client::TdOnCheckUserCallback final : public TdQueryCallback { auto user_info = client_->get_user_info(user->id_); CHECK(user_info != nullptr); // it must have already been got through updates - return client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); + client_->check_user_read_access(user_info, std::move(query_), std::move(on_success_)); } private: @@ -4063,7 +4063,7 @@ class Client::TdOnCheckChatCallback final : public TdQueryCallback { return fail_query(400, "Bad Request: chat not found", std::move(query_)); } - return client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); + client_->check_chat_access(chat->id_, access_rights_, chat_info, std::move(query_), std::move(on_success_)); } private: @@ -4091,6 +4091,30 @@ class Client::TdOnCheckChatNoFailCallback final : public TdQueryCallback { OnSuccess on_success_; }; +template +class Client::TdOnCheckBusinessConnectionCallback final : public TdQueryCallback { + public: + TdOnCheckBusinessConnectionCallback(Client *client, PromisedQueryPtr query, OnSuccess on_success) + : client_(client), query_(std::move(query)), on_success_(std::move(on_success)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result), + "business connection not found"); + } + + CHECK(result->get_id() == td_api::businessConnection::ID); + auto connection = client_->add_business_connection(move_object_as(result), false); + on_success_(connection->id_, std::move(query_)); + } + + private: + Client *client_; + PromisedQueryPtr query_; + OnSuccess on_success_; +}; + template class Client::TdOnSearchStickerSetCallback final : public TdQueryCallback { public: @@ -4838,7 +4862,7 @@ class Client::TdOnGetSupergroupMemberCountCallback final : public TdQueryCallbac CHECK(result->get_id() == td_api::supergroupFullInfo::ID); auto supergroup_full_info = move_object_as(result); - return answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); + answer_query(td::VirtuallyJsonableInt(supergroup_full_info->member_count_), std::move(query_)); } private: @@ -4857,7 +4881,7 @@ class Client::TdOnCreateInvoiceLinkCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::httpUrl::ID); auto http_url = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(http_url->url_), std::move(query_)); } private: @@ -4876,7 +4900,7 @@ class Client::TdOnReplacePrimaryChatInviteLinkCallback final : public TdQueryCal CHECK(result->get_id() == td_api::chatInviteLink::ID); auto invite_link = move_object_as(result); - return answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); + answer_query(td::VirtuallyJsonableString(invite_link->invite_link_), std::move(query_)); } private: @@ -5525,6 +5549,30 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O chat_id, std::move(query), std::move(on_success))); } +td::Result Client::get_business_connection_chat_id(td::Slice chat_id_str) { + if (chat_id_str.empty()) { + return td::Status::Error(400, "Bad Request: chat_id is empty"); + } + + auto r_chat_id = td::to_integer_safe(chat_id_str); + if (r_chat_id.is_error()) { + return td::Status::Error(400, "Bad Request: chat_id must be a valid Integer"); + } + return r_chat_id.move_as_ok(); +} + +template +void Client::check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success) { + auto business_connection = get_business_connection(business_connection_id); + if (business_connection != nullptr) { + return on_success(business_connection_id, std::move(query)); + } + send_request( + make_object(business_connection_id), + td::make_unique>(this, std::move(query), std::move(on_success))); +} + template void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { CHECK(scope.scope_ != nullptr); @@ -9649,14 +9697,26 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { } td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { - auto chat_id = query->arg("chat_id"); + auto chat_id_str = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + auto business_connection_id = query->arg("business_connection_id").str(); object_ptr action = get_chat_action(query.get()); if (action == nullptr) { return td::Status::Error(400, "Wrong parameter action in request"); } + if (!business_connection_id.empty()) { + TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); + check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, action = std::move(action)](const td::string &business_connection_id, + PromisedQueryPtr query) mutable { + send_request(make_object(chat_id, 0, business_connection_id, std::move(action)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); + } - check_chat(chat_id, AccessRights::Write, std::move(query), + check_chat(chat_id_str, AccessRights::Write, std::move(query), [this, message_thread_id, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { send_request( make_object(chat_id, message_thread_id, td::string(), std::move(action)), diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4fe12cc..ae21af1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -293,6 +293,8 @@ class Client final : public WebhookActor::Callback { template class TdOnCheckMessageThreadCallback; template + class TdOnCheckBusinessConnectionCallback; + template class TdOnCheckRemoteFileIdCallback; template class TdOnGetChatMemberCallback; @@ -321,6 +323,12 @@ class Client final : public WebhookActor::Callback { template void check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, OnSuccess on_success); + static td::Result get_business_connection_chat_id(td::Slice chat_id_str); + + template + void check_business_connection(const td::string &business_connection_id, PromisedQueryPtr query, + OnSuccess on_success); + template void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); From 2ac6b4bcca9809635e8924ff5d160dd428b0fe6b Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 14 Mar 2024 22:51:02 +0300 Subject: [PATCH 08/42] Support sending messages to business connection. --- telegram-bot-api/Client.cpp | 74 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 7 ++++ 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 2391314..1b298bc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2416,6 +2416,9 @@ class Client::JsonTextQuote final : public td::Jsonable { void Client::JsonMessage::store(td::JsonValueScope *scope) const { CHECK(message_ != nullptr); auto object = scope->enter_object(); + if (!message_->business_connection_id.empty()) { + object("business_connection_id", message_->business_connection_id); + } object("message_id", as_client_message_id(message_->id)); if (message_->sender_user_id != 0) { object("from", JsonUser(message_->sender_user_id, client_)); @@ -3797,6 +3800,29 @@ class Client::TdOnSendMessageCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::businessMessage::ID); + auto message = client_->create_business_message(std::move(business_connection_id_), + move_object_as(result)); + answer_query(JsonMessage(message.get(), false, "sent business message", client_), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { public: TdOnSendMessageAlbumCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -6554,6 +6580,15 @@ td_api::object_ptr Client::get_input_message_reply_ return nullptr; } +td_api::object_ptr Client::get_input_message_reply_to( + InputReplyParameters &&reply_parameters) { + if (reply_parameters.reply_in_chat_id.empty() && reply_parameters.reply_to_message_id > 0) { + return make_object(0, reply_parameters.reply_to_message_id, + std::move(reply_parameters.quote)); + } + return nullptr; +} + td::Result Client::get_reply_parameters(const Query *query) { if (!query->has_arg("reply_parameters")) { InputReplyParameters result; @@ -11446,6 +11481,7 @@ void Client::do_send_message(object_ptr input_messa bool force) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); + auto business_connection_id = query->arg("business_connection_id"); auto r_reply_parameters = get_reply_parameters(query.get()); if (r_reply_parameters.is_error()) { return fail_query_with_error(std::move(query), 400, r_reply_parameters.error().message()); @@ -11461,9 +11497,30 @@ void Client::do_send_message(object_ptr input_messa resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), - disable_notification, protect_content, input_message_content = std::move(input_message_content)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_content = std::move(input_message_content)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( + const td::string &business_connection_id, PromisedQueryPtr query) mutable { + send_request( + make_object(business_connection_id, chat_id, + get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, + std::move(reply_markup), std::move(input_message_content)), + td::make_unique(this, business_connection_id, std::move(query))); + }); + } + auto on_success = [this, disable_notification, protect_content, input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, @@ -11481,7 +11538,7 @@ void Client::do_send_message(object_ptr input_messa std::move(reply_markup), std::move(input_message_content)), td::make_unique(this, chat_id, std::move(query))); }; - check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); } @@ -13069,6 +13126,15 @@ void Client::init_message(MessageInfo *message_info, object_ptr message = nullptr; } +td::unique_ptr Client::create_business_message(td::string business_connection_id, + object_ptr &&message) { + auto message_info = td::make_unique(); + CHECK(message != nullptr); + init_message(message_info.get(), std::move(message->message_), true); + message_info->business_connection_id = std::move(business_connection_id); + return message_info; +} + void Client::update_message_content(int64 chat_id, int64 message_id, object_ptr &&content) { auto message_info = get_message_editable(chat_id, message_id); if (message_info == nullptr) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ae21af1..d4c10a4 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -196,6 +196,7 @@ class Client final : public WebhookActor::Callback { class TdOnInitCallback; class TdOnGetUserProfilePhotosCallback; class TdOnSendMessageCallback; + class TdOnSendBusinessMessageCallback; class TdOnSendMessageAlbumCallback; class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; @@ -383,6 +384,8 @@ class Client final : public WebhookActor::Callback { static object_ptr get_input_message_reply_to(CheckedReplyParameters &&reply_parameters); + static object_ptr get_input_message_reply_to(InputReplyParameters &&reply_parameters); + static td::Result get_reply_parameters(const Query *query); static td::Result get_reply_parameters(td::JsonValue &&value); @@ -889,6 +892,7 @@ class Client final : public WebhookActor::Callback { int64 via_bot_user_id = 0; object_ptr content; object_ptr reply_markup; + td::string business_connection_id; bool can_be_saved = false; bool is_automatic_forward = false; @@ -987,6 +991,9 @@ class Client final : public WebhookActor::Callback { const MessageInfo *get_message(int64 chat_id, int64 message_id, bool force_cache) const; MessageInfo *get_message_editable(int64 chat_id, int64 message_id); + td::unique_ptr create_business_message(td::string business_connection_id, + object_ptr &&message); + void update_message_content(int64 chat_id, int64 message_id, object_ptr &&content); void on_update_message_edited(int64 chat_id, int64 message_id, int32 edit_date, From 82134ecc94d8ebbc963a5755fde50b900790abd8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 15 Mar 2024 15:56:40 +0300 Subject: [PATCH 09/42] Support sending media groups as business. --- telegram-bot-api/Client.cpp | 58 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 1 + 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1b298bc..7cf9d2d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3853,6 +3853,34 @@ class Client::TdOnSendMessageAlbumCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnSendBusinessMessageAlbumCallback final : public TdQueryCallback { + public: + TdOnSendBusinessMessageAlbumCallback(Client *client, td::string business_connection_id, PromisedQueryPtr query) + : client_(client), business_connection_id_(std::move(business_connection_id)), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::businessMessages::ID); + auto messages = move_object_as(result); + td::vector message_strings; + for (auto &message : messages->messages_) { + auto message_info = client_->create_business_message(business_connection_id_, std::move(message)); + message_strings.push_back( + td::json_encode(JsonMessage(message_info.get(), false, "sent business message", client_))); + } + answer_query(JsonMessages(message_strings), std::move(query_)); + } + + private: + Client *client_; + td::string business_connection_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnForwardMessagesCallback final : public TdQueryCallback { public: TdOnForwardMessagesCallback(Client *client, int64 chat_id, std::size_t message_count, PromisedQueryPtr query) @@ -9696,6 +9724,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); auto message_thread_id = get_message_id(query.get(), "message_thread_id"); TRY_RESULT(reply_parameters, get_reply_parameters(query.get())); + auto business_connection_id = query->arg("business_connection_id"); auto disable_notification = to_bool(query->arg("disable_notification")); auto protect_content = to_bool(query->arg("protect_content")); // TRY_RESULT(reply_markup, get_reply_markup(query.get(), bot_user_ids_)); @@ -9704,9 +9733,30 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_thread_id, reply_parameters = std::move(reply_parameters), - disable_notification, protect_content, input_message_contents = std::move(input_message_contents)]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id_str = chat_id.str(), message_thread_id, business_connection_id = business_connection_id.str(), + reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_contents = std::move(input_message_contents)](object_ptr reply_markup, + PromisedQueryPtr query) mutable { + if (!business_connection_id.empty()) { + auto r_chat_id = get_business_connection_chat_id(chat_id_str); + if (r_chat_id.is_error()) { + return fail_query_with_error(std::move(query), 400, r_chat_id.error().message()); + } + auto chat_id = r_chat_id.move_as_ok(); + return check_business_connection( + business_connection_id, std::move(query), + [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, + input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( + const td::string &business_connection_id, PromisedQueryPtr query) mutable { + send_request( + make_object( + business_connection_id, chat_id, get_input_message_reply_to(std::move(reply_parameters)), + disable_notification, protect_content, std::move(input_message_contents)), + td::make_unique(this, business_connection_id, + std::move(query))); + }); + } + auto on_success = [this, disable_notification, protect_content, input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_thread_id, @@ -9725,7 +9775,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { get_message_send_options(disable_notification, protect_content), std::move(input_message_contents)), td::make_unique(this, chat_id, message_count, std::move(query))); }; - check_reply_parameters(chat_id, std::move(reply_parameters), message_thread_id, std::move(query), + check_reply_parameters(chat_id_str, std::move(reply_parameters), message_thread_id, std::move(query), std::move(on_success)); }); return td::Status::OK(); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d4c10a4..1b94cc7 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -198,6 +198,7 @@ class Client final : public WebhookActor::Callback { class TdOnSendMessageCallback; class TdOnSendBusinessMessageCallback; class TdOnSendMessageAlbumCallback; + class TdOnSendBusinessMessageAlbumCallback; class TdOnForwardMessagesCallback; class TdOnDeleteFailedToSendMessageCallback; class TdOnEditMessageCallback; From f6497b76c49bd5175679d5b22e63be8e32e5c011 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 11:21:43 +0300 Subject: [PATCH 10/42] Support replies in business messages. --- telegram-bot-api/Client.cpp | 17 +++++++++++++---- telegram-bot-api/Client.h | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7cf9d2d..23e4e04 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2486,7 +2486,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto reply_to_message_id = get_same_chat_reply_to_message_id(message_); if (reply_to_message_id > 0) { // internal reply - const MessageInfo *reply_to_message = client_->get_message(message_->chat_id, reply_to_message_id, true); + const MessageInfo *reply_to_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, reply_to_message_id, true); if (reply_to_message != nullptr) { object("reply_to_message", JsonMessage(reply_to_message, false, "reply in " + source_, client_)); } else { @@ -2719,7 +2721,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto content = static_cast(message_->content.get()); auto message_id = content->message_id_; if (message_id > 0) { - const MessageInfo *pinned_message = client_->get_message(message_->chat_id, message_id, true); + const MessageInfo *pinned_message = !message_->business_connection_id.empty() + ? message_->business_reply_to_message.get() + : client_->get_message(message_->chat_id, message_id, true); if (pinned_message != nullptr) { object("pinned_message", JsonMessage(pinned_message, false, "pin in " + source_, client_)); } else if (need_reply_) { @@ -3814,7 +3818,7 @@ class Client::TdOnSendBusinessMessageCallback final : public TdQueryCallback { CHECK(result->get_id() == td_api::businessMessage::ID); auto message = client_->create_business_message(std::move(business_connection_id_), move_object_as(result)); - answer_query(JsonMessage(message.get(), false, "sent business message", client_), std::move(query_)); + answer_query(JsonMessage(message.get(), true, "sent business message", client_), std::move(query_)); } private: @@ -3870,7 +3874,7 @@ class Client::TdOnSendBusinessMessageAlbumCallback final : public TdQueryCallbac for (auto &message : messages->messages_) { auto message_info = client_->create_business_message(business_connection_id_, std::move(message)); message_strings.push_back( - td::json_encode(JsonMessage(message_info.get(), false, "sent business message", client_))); + td::json_encode(JsonMessage(message_info.get(), true, "sent business message", client_))); } answer_query(JsonMessages(message_strings), std::move(query_)); } @@ -13182,6 +13186,11 @@ td::unique_ptr Client::create_business_message(td::string b CHECK(message != nullptr); init_message(message_info.get(), std::move(message->message_), true); message_info->business_connection_id = std::move(business_connection_id); + if (message->reply_to_message_ != nullptr) { + message_info->business_reply_to_message = td::make_unique(); + init_message(message_info->business_reply_to_message.get(), std::move(message->reply_to_message_), true); + message_info->business_reply_to_message->business_connection_id = message_info->business_connection_id; + } return message_info; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 1b94cc7..ee7d7c6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -887,6 +887,7 @@ class Client final : public WebhookActor::Callback { int32 sender_boost_count = 0; object_ptr forward_origin; td::string author_signature; + td::unique_ptr business_reply_to_message; object_ptr reply_to_message; object_ptr reply_to_story; int64 media_album_id = 0; From b9d4d5767862f51293b105ffdb4edaa6742ca2c9 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 11:54:29 +0300 Subject: [PATCH 11/42] Support business messages in need_skip_update_message. --- telegram-bot-api/Client.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 23e4e04..0edfad3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -12562,9 +12562,17 @@ td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *me } bool Client::need_skip_update_message(int64 chat_id, const object_ptr &message, bool is_edited) const { - auto chat = get_chat(chat_id); - CHECK(chat != nullptr); - if (message->is_outgoing_) { + const ChatInfo *chat; + ChatInfo::Type chat_type; + if (chat_id != 0) { + chat = get_chat(chat_id); + CHECK(chat != nullptr); + chat_type = chat->type; + } else { + chat = nullptr; + chat_type = ChatInfo::Type::Private; + } + if (message->is_outgoing_ && chat_id != 0) { switch (message->content_->get_id()) { case td_api::messageChatChangeTitle::ID: case td_api::messageChatChangePhoto::ID: @@ -12600,7 +12608,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype == ChatInfo::Type::Supergroup) { + if (chat_type == ChatInfo::Type::Supergroup) { + CHECK(chat != nullptr); auto supergroup_info = get_supergroup_info(chat->supergroup_id); if (supergroup_info->status->get_id() == td_api::chatMemberStatusLeft::ID || supergroup_info->status->get_id() == td_api::chatMemberStatusBanned::ID) { @@ -12641,7 +12650,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrtype != ChatInfo::Type::Supergroup) { + if (chat_type != ChatInfo::Type::Supergroup) { LOG(ERROR) << "Receive messageSupergroupChatCreate in the non-supergroup chat " << chat_id; return true; } @@ -12698,7 +12707,7 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrid_, true); if (old_message != nullptr && !old_message->is_content_changed) { return true; From c783b1c821ba6c9d6d6c2fa0771e1aabaee0a875 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 12:36:19 +0300 Subject: [PATCH 12/42] Add "business_message" and "edited_business_message" updates. --- telegram-bot-api/Client.cpp | 121 ++++++++++++++++++++++++++++++++---- telegram-bot-api/Client.h | 23 +++++++ 2 files changed, 131 insertions(+), 13 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0edfad3..3871a4c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4513,11 +4513,13 @@ class Client::TdOnGetCallbackQueryMessageCallback final : public TdQueryCallback class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { public: - TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id) + TdOnGetStickerSetCallback(Client *client, int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id) : client_(client) , set_id_(set_id) , new_callback_query_user_id_(new_callback_query_user_id) - , new_message_chat_id_(new_message_chat_id) { + , new_message_chat_id_(new_message_chat_id) + , new_message_business_connection_id_(new_message_business_connection_id) { } void on_result(object_ptr result) final { @@ -4528,12 +4530,13 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { << new_callback_query_user_id_ << "/new message in chat " << new_message_chat_id_ << ": " << td::oneline(to_string(error)); } - return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, nullptr); + return client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, + new_message_business_connection_id_, nullptr); } CHECK(result->get_id() == td_api::stickerSet::ID); client_->on_get_sticker_set(set_id_, new_callback_query_user_id_, new_message_chat_id_, - move_object_as(result)); + new_message_business_connection_id_, move_object_as(result)); } private: @@ -4541,6 +4544,7 @@ class Client::TdOnGetStickerSetCallback final : public TdQueryCallback { int64 set_id_; int64 new_callback_query_user_id_; int64 new_message_chat_id_; + td::string new_message_business_connection_id_; }; class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCallback { @@ -5422,6 +5426,7 @@ void Client::on_get_callback_query_message(object_ptr message, } void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set) { if (new_callback_query_user_id != 0) { auto &queue = new_callback_query_queues_[new_callback_query_user_id]; @@ -5437,6 +5442,13 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, CHECK(!queue.queue_.empty()); } + if (!new_message_business_connection_id.empty()) { + auto &queue = new_business_message_queues_[new_message_business_connection_id]; + CHECK(queue.has_active_request_); + queue.has_active_request_ = false; + + CHECK(!queue.queue_.empty()); + } CHECK(set_id != 0); if (set_id != GREAT_MINDS_SET_ID) { @@ -5452,6 +5464,9 @@ void Client::on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, if (new_message_chat_id != 0) { process_new_message_queue(new_message_chat_id, 2); } + if (!new_message_business_connection_id.empty()) { + process_new_business_message_queue(new_message_business_connection_id); + } } void Client::on_get_sticker_set_name(int64 set_id, const td::string &name) { @@ -6459,6 +6474,12 @@ void Client::on_update(object_ptr result) { case td_api::updateBusinessConnection::ID: add_update_business_connection(move_object_as(result)); break; + case td_api::updateNewBusinessMessage::ID: + add_new_business_message(move_object_as(result)); + break; + case td_api::updateBusinessMessageEdited::ID: + add_business_message_edited(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -12185,6 +12206,10 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("message_reaction_count"); case UpdateType::BusinessConnection: return td::Slice("business_connection"); + case UpdateType::BusinessMessage: + return td::Slice("business_message"); + case UpdateType::EditedBusinessMessage: + return td::Slice("edited_business_message"); default: UNREACHABLE(); return td::Slice(); @@ -12400,8 +12425,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { auto message_sticker_set_id = message_info == nullptr ? 0 : get_sticker_set_id(message_info->content); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, user_id, 0)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, user_id, 0, td::string())); } auto reply_to_message_id = get_same_chat_reply_to_message_id(message_info); if (reply_to_message_id > 0) { @@ -12410,8 +12436,9 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { reply_to_message_info == nullptr ? 0 : get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, user_id, 0)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, user_id, 0, td::string())); } } } @@ -12548,6 +12575,20 @@ void Client::add_update_business_connection(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), false); + process_new_business_message_queue(update->connection_id_); +} + +void Client::add_business_message_edited(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(!update->connection_id_.empty()); + new_business_message_queues_[update->connection_id_].queue_.emplace(std::move(update->message_), true); + process_new_business_message_queue(update->connection_id_); +} + td::int64 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { @@ -12780,6 +12821,7 @@ td::int64 Client::get_same_chat_reply_to_message_id(const MessageInfo *message_i } void Client::drop_internal_reply_to_message_in_another_chat(object_ptr &message) { + CHECK(message != nullptr); if (message->reply_to_ != nullptr && message->reply_to_->get_id() == td_api::messageReplyToMessage::ID) { auto *reply_to = static_cast(message->reply_to_.get()); auto reply_in_chat_id = reply_to->chat_id_; @@ -12969,8 +13011,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto message_sticker_set_id = get_sticker_set_id(message_ref->content_); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(message_sticker_set_id), - td::make_unique(this, message_sticker_set_id, 0, chat_id)); + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, chat_id, td::string())); } if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id, true); @@ -12978,8 +13021,9 @@ void Client::process_new_message_queue(int64 chat_id, int state) { auto reply_sticker_set_id = get_sticker_set_id(reply_to_message_info->content); if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; - return send_request(make_object(reply_sticker_set_id), - td::make_unique(this, reply_sticker_set_id, 0, chat_id)); + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, chat_id, td::string())); } } } @@ -13050,6 +13094,57 @@ void Client::process_new_message_queue(int64 chat_id, int state) { new_message_queues_.erase(chat_id); } +void Client::process_new_business_message_queue(const td::string &connection_id) { + auto &queue = new_business_message_queues_[connection_id]; + if (queue.has_active_request_) { + return; + } + if (logging_out_ || closing_) { + new_business_message_queues_.erase(connection_id); + return; + } + while (!queue.queue_.empty()) { + auto &message_ref = queue.queue_.front().message_; + + drop_internal_reply_to_message_in_another_chat(message_ref->message_); + + auto message_sticker_set_id = get_sticker_set_id(message_ref->message_->content_); + if (!have_sticker_set_name(message_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(message_sticker_set_id), + td::make_unique(this, message_sticker_set_id, 0, 0, connection_id)); + } + if (message_ref->reply_to_message_ != nullptr) { + drop_internal_reply_to_message_in_another_chat(message_ref->reply_to_message_); + auto reply_sticker_set_id = get_sticker_set_id(message_ref->reply_to_message_->content_); + if (!have_sticker_set_name(reply_sticker_set_id)) { + queue.has_active_request_ = true; + return send_request( + make_object(reply_sticker_set_id), + td::make_unique(this, reply_sticker_set_id, 0, 0, connection_id)); + } + } + + auto message = std::move(message_ref); + auto is_edited = queue.queue_.front().is_edited_; + queue.queue_.pop(); + if (need_skip_update_message(0, message->message_, is_edited)) { + continue; + } + + auto message_date = message->message_->edit_date_ == 0 ? message->message_->date_ : message->message_->edit_date_; + auto now = get_unix_time(); + auto left_time = message_date + 86400 - now; + auto webhook_queue_id = message->message_->chat_id_ + (static_cast(11) << 33); + auto update_type = is_edited ? UpdateType::EditedBusinessMessage : UpdateType::BusinessMessage; + auto message_info = create_business_message(connection_id, std::move(message)); + add_update(update_type, JsonMessage(message_info.get(), true, get_update_type_name(update_type).str(), this), + left_time, webhook_queue_id); + } + new_business_message_queues_.erase(connection_id); +} + td::unique_ptr Client::delete_message(int64 chat_id, int64 message_id, bool only_from_cache) { auto message_info = std::move(messages_[{chat_id, message_id}]); if (message_info == nullptr) { @@ -13179,7 +13274,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { send_request(make_object(sticker_set_id), - td::make_unique(this, sticker_set_id, 0, 0)); + td::make_unique(this, sticker_set_id, 0, 0, td::string())); } } else if (message->content_->get_id() == td_api::messagePoll::ID) { message_info->content = std::move(message->content_); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ee7d7c6..e4ceda8 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -245,6 +245,7 @@ class Client final : public WebhookActor::Callback { void on_get_callback_query_message(object_ptr message, int64 user_id, int state); void on_get_sticker_set(int64 set_id, int64 new_callback_query_user_id, int64 new_message_chat_id, + const td::string &new_message_business_connection_id, object_ptr sticker_set); void on_get_sticker_set_name(int64 set_id, const td::string &name); @@ -968,6 +969,12 @@ class Client final : public WebhookActor::Callback { void process_new_message_queue(int64 chat_id, int state); + void add_new_business_message(object_ptr &&update); + + void add_business_message_edited(object_ptr &&update); + + void process_new_business_message_queue(const td::string &connection_id); + struct FullMessageId { int64 chat_id; int64 message_id; @@ -1073,6 +1080,8 @@ class Client final : public WebhookActor::Callback { MessageReaction, MessageReactionCount, BusinessConnection, + BusinessMessage, + EditedBusinessMessage, Size }; @@ -1180,6 +1189,20 @@ class Client final : public WebhookActor::Callback { }; td::FlatHashMap new_message_queues_; // chat_id -> queue + struct NewBusinessMessage { + object_ptr message_; + bool is_edited_ = false; + + NewBusinessMessage(object_ptr &&message, bool is_edited) + : message_(std::move(message)), is_edited_(is_edited) { + } + }; + struct NewBusinessMessageQueue { + std::queue queue_; + bool has_active_request_ = false; + }; + td::FlatHashMap new_business_message_queues_; // connection_id -> queue + struct NewCallbackQueryQueue { std::queue> queue_; bool has_active_request_ = false; From 5bc529774616f6a81c814e4727ce7e9060d18800 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 12:52:17 +0300 Subject: [PATCH 13/42] Add Client::get_legacy_input_sticker. --- telegram-bot-api/Client.cpp | 36 ++++++------------------------------ telegram-bot-api/Client.h | 2 ++ 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3871a4c..0dc2629 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -8138,8 +8138,11 @@ td::Result> Client::get_input_sticker(c return r_sticker.move_as_ok(); } - auto emojis = query->arg("emojis"); + return get_legacy_input_sticker(query); +} +td::Result> Client::get_legacy_input_sticker(const Query *query) const { + auto emojis = query->arg("emojis"); auto sticker = get_input_file(query, "png_sticker"); object_ptr sticker_format; object_ptr mask_position; @@ -8202,37 +8205,10 @@ td::Result>> Client::get_inp return std::move(input_stickers); } - auto emojis = query->arg("emojis"); - - auto sticker = get_input_file(query, "png_sticker"); - object_ptr sticker_format; - object_ptr mask_position; - if (sticker != nullptr) { - sticker_format = make_object(); - TRY_RESULT_ASSIGN(mask_position, get_mask_position(query, "mask_position")); - } else { - sticker = get_input_file(query, "tgs_sticker", true); - if (sticker != nullptr) { - sticker_format = make_object(); - } else { - sticker = get_input_file(query, "webm_sticker", true); - if (sticker != nullptr) { - sticker_format = make_object(); - } else { - if (!query->arg("tgs_sticker").empty()) { - return td::Status::Error(400, "Bad Request: animated sticker must be uploaded as an InputFile"); - } - if (!query->arg("webm_sticker").empty()) { - return td::Status::Error(400, "Bad Request: video sticker must be uploaded as an InputFile"); - } - return td::Status::Error(400, "Bad Request: there is no sticker file in the request"); - } - } - } + TRY_RESULT(input_sticker, get_legacy_input_sticker(query)); td::vector> stickers; - stickers.push_back(make_object(std::move(sticker), std::move(sticker_format), emojis.str(), - std::move(mask_position), td::vector())); + stickers.push_back(std::move(input_sticker)); return std::move(stickers); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index e4ceda8..252e79e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -486,6 +486,8 @@ class Client final : public WebhookActor::Callback { static td::Result> get_sticker_format(td::Slice sticker_format); + td::Result> get_legacy_input_sticker(const Query *query) const; + td::Result> get_input_sticker(const Query *query) const; td::Result> get_input_sticker(const Query *query, td::JsonValue &&value, From 538fc78fa68977a5a9e9a83a3e9829130e31e4ad Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 13:58:44 +0300 Subject: [PATCH 14/42] Add "deleted_business_messages" updates. --- telegram-bot-api/Client.cpp | 30 ++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0dc2629..da6ffcf 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3603,6 +3603,24 @@ class Client::JsonBusinessConnection final : public td::Jsonable { const Client *client_; }; +class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { + public: + JsonBusinessMessagesDeleted(const td_api::updateBusinessMessagesDeleted *update, const Client *client) + : update_(update), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("business_connection_id", update_->connection_id_); + object("chat", JsonChat(update_->chat_id_, client_)); + object("message_ids", + td::json_array(update_->message_ids_, [](int64 message_id) { return as_client_message_id(message_id); })); + } + + private: + const td_api::updateBusinessMessagesDeleted *update_; + const Client *client_; +}; + class Client::JsonUpdateTypes final : public td::Jsonable { public: explicit JsonUpdateTypes(td::uint32 update_types) : update_types_(update_types) { @@ -6480,6 +6498,9 @@ void Client::on_update(object_ptr result) { case td_api::updateBusinessMessageEdited::ID: add_business_message_edited(move_object_as(result)); break; + case td_api::updateBusinessMessagesDeleted::ID: + add_update_business_messages_deleted(move_object_as(result)); + break; case td_api::updateConnectionState::ID: { auto update = move_object_as(result); if (update->state_->get_id() == td_api::connectionStateReady::ID) { @@ -12186,6 +12207,8 @@ td::Slice Client::get_update_type_name(UpdateType update_type) { return td::Slice("business_message"); case UpdateType::EditedBusinessMessage: return td::Slice("edited_business_message"); + case UpdateType::BusinessMessagesDeleted: + return td::Slice("deleted_business_messages"); default: UNREACHABLE(); return td::Slice(); @@ -12551,6 +12574,13 @@ void Client::add_update_business_connection(object_ptr &&update) { + CHECK(update != nullptr); + auto webhook_queue_id = update->chat_id_ + (static_cast(11) << 33); + add_update(UpdateType::BusinessMessagesDeleted, JsonBusinessMessagesDeleted(update.get(), this), 86400, + webhook_queue_id); +} + void Client::add_new_business_message(object_ptr &&update) { CHECK(update != nullptr); CHECK(!update->connection_id_.empty()); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 252e79e..80a6a1b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -164,6 +164,7 @@ class Client final : public WebhookActor::Callback { class JsonMessageReactionUpdated; class JsonMessageReactionCountUpdated; class JsonBusinessConnection; + class JsonBusinessMessagesDeleted; class JsonAddress; class JsonOrderInfo; class JsonStory; @@ -1059,6 +1060,8 @@ class Client final : public WebhookActor::Callback { void add_update_business_connection(object_ptr &&update); + void add_update_business_messages_deleted(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -1084,6 +1087,7 @@ class Client final : public WebhookActor::Callback { BusinessConnection, BusinessMessage, EditedBusinessMessage, + BusinessMessagesDeleted, Size }; From a872d6036200219bde798e91d7b86024492e7d99 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 14:17:05 +0300 Subject: [PATCH 15/42] Add setStickerSetThumbnail.format parameter. --- telegram-bot-api/Client.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index da6ffcf..4ccc222 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -11035,11 +11035,17 @@ td::Status Client::process_set_sticker_set_thumbnail_query(PromisedQueryPtr &que if (thumbnail == nullptr) { thumbnail = get_input_file(query.get(), "thumb"); } + td::Slice sticker_format_str = query->arg("format"); + if (sticker_format_str.empty()) { + sticker_format_str = td::Slice("auto"); + } + TRY_RESULT(sticker_format, get_sticker_format(sticker_format_str)); check_user(user_id, std::move(query), - [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { - send_request( - make_object(user_id, name.str(), std::move(thumbnail), nullptr), - td::make_unique(std::move(query))); + [this, user_id, name, thumbnail = std::move(thumbnail), + sticker_format = std::move(sticker_format)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(thumbnail), + std::move(sticker_format)), + td::make_unique(std::move(query))); }); return td::Status::OK(); } From f1c14471850d1689b2cfcef8ed0c60699661bb38 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 14:26:39 +0300 Subject: [PATCH 16/42] Add chat.business_location field. --- telegram-bot-api/Client.cpp | 23 +++++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4ccc222..47b1c43 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -627,6 +627,22 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBusinessLocation final : public td::Jsonable { + public: + JsonBusinessLocation(const td_api::businessLocation *business_location) : business_location_(business_location) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (business_location_->location_ != nullptr) { + object("location", JsonLocation(business_location_->location_.get())); + } + object("address", business_location_->address_); + } + + private: + const td_api::businessLocation *business_location_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -769,6 +785,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } + if (user_info->business_location != nullptr) { + object("business_location", JsonBusinessLocation(user_info->business_location.get())); + } } photo = user_info->photo.get(); break; @@ -6340,6 +6359,10 @@ void Client::on_update(object_ptr result) { user_info->photo = full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); + user_info->business_location = + full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr + ? std::move(full_info->business_info_->location_) + : nullptr; user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 80a6a1b..619f006 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBusinessLocation; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -793,6 +794,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr business_location; bool have_access = false; bool can_join_groups = false; From 1a86bb56db3829db240361ef3fcbb78fd1cf862e Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 17:04:42 +0300 Subject: [PATCH 17/42] Add chat.business_opening_hours field. --- telegram-bot-api/Client.cpp | 38 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 3 +++ 2 files changed, 41 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 47b1c43..25396d7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -643,6 +643,37 @@ class Client::JsonBusinessLocation final : public td::Jsonable { const td_api::businessLocation *business_location_; }; +class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { + public: + JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) + : opening_hours_interval_(opening_hours_interval) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_minute", opening_hours_interval_->start_minute_); + object("closing_minute", opening_hours_interval_->end_minute_); + } + + private: + const td_api::businessOpeningHoursInterval *opening_hours_interval_; +}; + +class Client::JsonBusinessOpeningHours final : public td::Jsonable { + public: + JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("opening_hours", td::json_array(opening_hours_->opening_hours_, [](const auto &opening_hours_interval) { + return JsonBusinessOpeningHoursInterval(opening_hours_interval.get()); + })); + object("time_zone_name", opening_hours_->time_zone_id_); + } + + private: + const td_api::businessOpeningHours *opening_hours_; +}; + class Client::JsonChatPermissions final : public td::Jsonable { public: explicit JsonChatPermissions(const td_api::chatPermissions *chat_permissions) : chat_permissions_(chat_permissions) { @@ -788,6 +819,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->business_location != nullptr) { object("business_location", JsonBusinessLocation(user_info->business_location.get())); } + if (user_info->business_opening_hours != nullptr) { + object("business_opening_hours", JsonBusinessOpeningHours(user_info->business_opening_hours.get())); + } } photo = user_info->photo.get(); break; @@ -6363,6 +6397,10 @@ void Client::on_update(object_ptr result) { full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr ? std::move(full_info->business_info_->location_) : nullptr; + user_info->business_opening_hours = + full_info->business_info_ != nullptr && full_info->business_info_->opening_hours_ != nullptr + ? std::move(full_info->business_info_->opening_hours_) + : nullptr; user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 619f006..8f1e259 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -94,6 +94,8 @@ class Client final : public WebhookActor::Callback { class JsonReactionType; class JsonReactionCount; class JsonBusinessLocation; + class JsonBusinessOpeningHoursInterval; + class JsonBusinessOpeningHours; class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; @@ -795,6 +797,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; object_ptr business_location; + object_ptr business_opening_hours; bool have_access = false; bool can_join_groups = false; From 15836d84f4a8834dc55f5203d53202069f6aa24a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 17:50:16 +0300 Subject: [PATCH 18/42] Add Message.sender_business_bot. --- telegram-bot-api/Client.cpp | 6 ++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 7 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 25396d7..33ceb59 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2471,6 +2471,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); if (!message_->business_connection_id.empty()) { object("business_connection_id", message_->business_connection_id); + if (message_->sender_business_bot_user_id != 0) { + object("sender_business_bot", JsonUser(message_->sender_business_bot_user_id, client_)); + } } object("message_id", as_client_message_id(message_->id)); if (message_->sender_user_id != 0) { @@ -13361,10 +13364,13 @@ td::unique_ptr Client::create_business_message(td::string b object_ptr &&message) { auto message_info = td::make_unique(); CHECK(message != nullptr); + message_info->sender_business_bot_user_id = message->message_->sender_business_bot_user_id_; init_message(message_info.get(), std::move(message->message_), true); message_info->business_connection_id = std::move(business_connection_id); if (message->reply_to_message_ != nullptr) { message_info->business_reply_to_message = td::make_unique(); + message_info->business_reply_to_message->sender_business_bot_user_id = + message->reply_to_message_->sender_business_bot_user_id_; init_message(message_info->business_reply_to_message.get(), std::move(message->reply_to_message_), true); message_info->business_reply_to_message->business_connection_id = message_info->business_connection_id; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 8f1e259..afc8d2e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -904,6 +904,7 @@ class Client final : public WebhookActor::Callback { object_ptr content; object_ptr reply_markup; td::string business_connection_id; + int64 sender_business_bot_user_id = 0; bool can_be_saved = false; bool is_automatic_forward = false; From 5ca4a446f0cc4384de1a6fb37db718b5df4b282a Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 18:31:52 +0300 Subject: [PATCH 19/42] Add getBusinessConnection method. --- telegram-bot-api/Client.cpp | 12 ++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 13 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 33ceb59..d49223b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -257,6 +257,7 @@ bool Client::init_methods() { methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); + methods_.emplace("getbusinessconnection", &Client::process_get_business_connection_query); methods_.emplace("getchat", &Client::process_get_chat_query); methods_.emplace("setchatphoto", &Client::process_set_chat_photo_query); methods_.emplace("deletechatphoto", &Client::process_delete_chat_photo_query); @@ -10331,6 +10332,17 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query return td::Status::OK(); } +td::Status Client::process_get_business_connection_query(PromisedQueryPtr &query) { + auto business_connection_id = query->arg("business_connection_id"); + check_business_connection(business_connection_id.str(), std::move(query), + [this](const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const auto *connection = get_business_connection(business_connection_id); + CHECK(connection != nullptr); + answer_query(JsonBusinessConnection(connection, this), std::move(query)); + }); + return td::Status::OK(); +} + td::Status Client::process_get_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index afc8d2e..0e67436 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -650,6 +650,7 @@ class Client final : public WebhookActor::Callback { td::Status process_create_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); td::Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); + td::Status process_get_business_connection_query(PromisedQueryPtr &query); td::Status process_get_chat_query(PromisedQueryPtr &query); td::Status process_set_chat_photo_query(PromisedQueryPtr &query); td::Status process_delete_chat_photo_query(PromisedQueryPtr &query); From 938847a51e65b8bc48d30d076496678d81238101 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Mar 2024 21:50:53 +0300 Subject: [PATCH 20/42] Pass BusinessConnection pointer to check_business_connection callback. --- telegram-bot-api/Client.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d49223b..e873e86 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4239,7 +4239,7 @@ class Client::TdOnCheckBusinessConnectionCallback final : public TdQueryCallback CHECK(result->get_id() == td_api::businessConnection::ID); auto connection = client_->add_business_connection(move_object_as(result), false); - on_success_(connection->id_, std::move(query_)); + on_success_(connection, std::move(query_)); } private: @@ -5714,7 +5714,7 @@ void Client::check_business_connection(const td::string &business_connection_id, OnSuccess on_success) { auto business_connection = get_business_connection(business_connection_id); if (business_connection != nullptr) { - return on_success(business_connection_id, std::move(query)); + return on_success(business_connection, std::move(query)); } send_request( make_object(business_connection_id), @@ -9834,12 +9834,12 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)]( - const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { send_request( make_object( - business_connection_id, chat_id, get_input_message_reply_to(std::move(reply_parameters)), + business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), disable_notification, protect_content, std::move(input_message_contents)), - td::make_unique(this, business_connection_id, + td::make_unique(this, business_connection->id_, std::move(query))); }); } @@ -9880,9 +9880,9 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { TRY_RESULT(chat_id, get_business_connection_chat_id(chat_id_str)); check_business_connection( business_connection_id, std::move(query), - [this, chat_id, action = std::move(action)](const td::string &business_connection_id, + [this, chat_id, action = std::move(action)](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, 0, business_connection_id, std::move(action)), + send_request(make_object(chat_id, 0, business_connection->id_, std::move(action)), td::make_unique(std::move(query))); }); return td::Status::OK(); @@ -10335,10 +10335,8 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query td::Status Client::process_get_business_connection_query(PromisedQueryPtr &query) { auto business_connection_id = query->arg("business_connection_id"); check_business_connection(business_connection_id.str(), std::move(query), - [this](const td::string &business_connection_id, PromisedQueryPtr query) mutable { - const auto *connection = get_business_connection(business_connection_id); - CHECK(connection != nullptr); - answer_query(JsonBusinessConnection(connection, this), std::move(query)); + [this](const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { + answer_query(JsonBusinessConnection(business_connection, this), std::move(query)); }); return td::Status::OK(); } @@ -11665,13 +11663,13 @@ void Client::do_send_message(object_ptr input_messa business_connection_id, std::move(query), [this, chat_id, reply_parameters = std::move(reply_parameters), disable_notification, protect_content, reply_markup = std::move(reply_markup), input_message_content = std::move(input_message_content)]( - const td::string &business_connection_id, PromisedQueryPtr query) mutable { + const BusinessConnection *business_connection, PromisedQueryPtr query) mutable { send_request( - make_object(business_connection_id, chat_id, + make_object(business_connection->id_, chat_id, get_input_message_reply_to(std::move(reply_parameters)), disable_notification, protect_content, std::move(reply_markup), std::move(input_message_content)), - td::make_unique(this, business_connection_id, std::move(query))); + td::make_unique(this, business_connection->id_, std::move(query))); }); } From 3d54e3c43bc91b154ae701c7dbe770ed70c40af5 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:03:04 +0300 Subject: [PATCH 21/42] Add Chat.business_intro. --- telegram-bot-api/Client.cpp | 225 ++++++++++++++++++++---------------- telegram-bot-api/Client.h | 2 + 2 files changed, 129 insertions(+), 98 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index e873e86..f5a721a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -552,6 +552,101 @@ class Client::JsonVectorEntities final : public td::Jsonable { const Client *client_; }; +class Client::JsonMaskPosition final : public td::Jsonable { + public: + explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); + object("x_shift", mask_position_->x_shift_); + object("y_shift", mask_position_->y_shift_); + object("scale", mask_position_->scale_); + } + + private: + const td_api::maskPosition *mask_position_; +}; + +class Client::JsonSticker final : public td::Jsonable { + public: + JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("width", sticker_->width_); + object("height", sticker_->height_); + if (!sticker_->emoji_.empty()) { + object("emoji", sticker_->emoji_); + } + auto set_name = client_->get_sticker_set_name(sticker_->set_id_); + if (!set_name.empty()) { + object("set_name", set_name); + } + + auto format = sticker_->format_->get_id(); + object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); + object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); + + switch (sticker_->full_type_->get_id()) { + case td_api::stickerFullTypeRegular::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->premium_animation_ != nullptr) { + object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); + } + break; + } + case td_api::stickerFullTypeMask::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->mask_position_ != nullptr) { + object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); + } + break; + } + case td_api::stickerFullTypeCustomEmoji::ID: { + auto full_type = static_cast(sticker_->full_type_.get()); + object("type", Client::get_sticker_type(make_object())); + if (full_type->custom_emoji_id_ != 0) { + object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); + } + if (full_type->needs_repainting_) { + object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); + } + break; + } + default: + UNREACHABLE(); + break; + } + + client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); + client_->json_store_file(object, sticker_->sticker_.get()); + } + + private: + const td_api::sticker *sticker_; + const Client *client_; +}; + +class Client::JsonStickers final : public td::Jsonable { + public: + JsonStickers(const td::vector> &stickers, const Client *client) + : stickers_(stickers), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto array = scope->enter_array(); + for (auto &sticker : stickers_) { + array << JsonSticker(sticker.get(), client_); + } + } + + private: + const td::vector> &stickers_; + const Client *client_; +}; + class Client::JsonLocation final : public td::Jsonable { public: explicit JsonLocation(const td_api::location *location, double expires_in = 0.0, int32 live_period = 0, @@ -628,9 +723,32 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBusinessIntro final : public td::Jsonable { + public: + JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (!intro_->title_.empty()) { + object("title", intro_->title_); + } + if (!intro_->message_.empty()) { + object("message", intro_->message_); + } + if (intro_->sticker_ != nullptr) { + object("sticker", JsonSticker(intro_->sticker_.get(), client_)); + } + } + + private: + const td_api::businessIntro *intro_; + const Client *client_; +}; + class Client::JsonBusinessLocation final : public td::Jsonable { public: - JsonBusinessLocation(const td_api::businessLocation *business_location) : business_location_(business_location) { + explicit JsonBusinessLocation(const td_api::businessLocation *business_location) + : business_location_(business_location) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -646,7 +764,7 @@ class Client::JsonBusinessLocation final : public td::Jsonable { class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { public: - JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) + explicit JsonBusinessOpeningHoursInterval(const td_api::businessOpeningHoursInterval *opening_hours_interval) : opening_hours_interval_(opening_hours_interval) { } void store(td::JsonValueScope *scope) const { @@ -661,7 +779,7 @@ class Client::JsonBusinessOpeningHoursInterval final : public td::Jsonable { class Client::JsonBusinessOpeningHours final : public td::Jsonable { public: - JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { + explicit JsonBusinessOpeningHours(const td_api::businessOpeningHours *opening_hours) : opening_hours_(opening_hours) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -817,6 +935,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } + if (user_info->business_intro != nullptr) { + object("business_intro", JsonBusinessIntro(user_info->business_intro.get(), client_)); + } if (user_info->business_location != nullptr) { object("business_location", JsonBusinessLocation(user_info->business_location.get())); } @@ -1303,101 +1424,6 @@ class Client::JsonChatPhoto final : public td::Jsonable { const Client *client_; }; -class Client::JsonMaskPosition final : public td::Jsonable { - public: - explicit JsonMaskPosition(const td_api::maskPosition *mask_position) : mask_position_(mask_position) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("point", Client::MASK_POINTS[Client::mask_point_to_index(mask_position_->point_)]); - object("x_shift", mask_position_->x_shift_); - object("y_shift", mask_position_->y_shift_); - object("scale", mask_position_->scale_); - } - - private: - const td_api::maskPosition *mask_position_; -}; - -class Client::JsonSticker final : public td::Jsonable { - public: - JsonSticker(const td_api::sticker *sticker, const Client *client) : sticker_(sticker), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto object = scope->enter_object(); - object("width", sticker_->width_); - object("height", sticker_->height_); - if (!sticker_->emoji_.empty()) { - object("emoji", sticker_->emoji_); - } - auto set_name = client_->get_sticker_set_name(sticker_->set_id_); - if (!set_name.empty()) { - object("set_name", set_name); - } - - auto format = sticker_->format_->get_id(); - object("is_animated", td::JsonBool(format == td_api::stickerFormatTgs::ID)); - object("is_video", td::JsonBool(format == td_api::stickerFormatWebm::ID)); - - switch (sticker_->full_type_->get_id()) { - case td_api::stickerFullTypeRegular::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->premium_animation_ != nullptr) { - object("premium_animation", JsonFile(full_type->premium_animation_.get(), client_, false)); - } - break; - } - case td_api::stickerFullTypeMask::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->mask_position_ != nullptr) { - object("mask_position", JsonMaskPosition(full_type->mask_position_.get())); - } - break; - } - case td_api::stickerFullTypeCustomEmoji::ID: { - auto full_type = static_cast(sticker_->full_type_.get()); - object("type", Client::get_sticker_type(make_object())); - if (full_type->custom_emoji_id_ != 0) { - object("custom_emoji_id", td::to_string(full_type->custom_emoji_id_)); - } - if (full_type->needs_repainting_) { - object("needs_repainting", td::JsonBool(full_type->needs_repainting_)); - } - break; - } - default: - UNREACHABLE(); - break; - } - - client_->json_store_thumbnail(object, sticker_->thumbnail_.get()); - client_->json_store_file(object, sticker_->sticker_.get()); - } - - private: - const td_api::sticker *sticker_; - const Client *client_; -}; - -class Client::JsonStickers final : public td::Jsonable { - public: - JsonStickers(const td::vector> &stickers, const Client *client) - : stickers_(stickers), client_(client) { - } - void store(td::JsonValueScope *scope) const { - auto array = scope->enter_array(); - for (auto &sticker : stickers_) { - array << JsonSticker(sticker.get(), client_); - } - } - - private: - const td::vector> &stickers_; - const Client *client_; -}; - class Client::JsonVideo final : public td::Jsonable { public: JsonVideo(const td_api::video *video, const Client *client) : video_(video), client_(client) { @@ -6397,6 +6423,9 @@ void Client::on_update(object_ptr result) { user_info->photo = full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); + user_info->business_intro = full_info->business_info_ != nullptr && full_info->business_info_->intro_ != nullptr + ? std::move(full_info->business_info_->intro_) + : nullptr; user_info->business_location = full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr ? std::move(full_info->business_info_->location_) diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0e67436..4b235f6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBusinessIntro; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; class JsonBusinessOpeningHours; @@ -797,6 +798,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr business_intro; object_ptr business_location; object_ptr business_opening_hours; From f8525043012d3561ad8fc16e5bfcf94e52f1db47 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:07:43 +0300 Subject: [PATCH 22/42] Store td_api::businessInfo in UserInfo. --- telegram-bot-api/Client.cpp | 31 ++++++++++++------------------- telegram-bot-api/Client.h | 4 +--- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f5a721a..8d132a7 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -935,14 +935,17 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->has_restricted_voice_and_video_messages) { object("has_restricted_voice_and_video_messages", td::JsonTrue()); } - if (user_info->business_intro != nullptr) { - object("business_intro", JsonBusinessIntro(user_info->business_intro.get(), client_)); - } - if (user_info->business_location != nullptr) { - object("business_location", JsonBusinessLocation(user_info->business_location.get())); - } - if (user_info->business_opening_hours != nullptr) { - object("business_opening_hours", JsonBusinessOpeningHours(user_info->business_opening_hours.get())); + if (user_info->business_info != nullptr) { + auto business_info = user_info->business_info.get(); + if (business_info->intro_ != nullptr) { + object("business_intro", JsonBusinessIntro(business_info->intro_.get(), client_)); + } + if (business_info->location_ != nullptr) { + object("business_location", JsonBusinessLocation(business_info->location_.get())); + } + if (business_info->opening_hours_ != nullptr) { + object("business_opening_hours", JsonBusinessOpeningHours(business_info->opening_hours_.get())); + } } } photo = user_info->photo.get(); @@ -6423,17 +6426,7 @@ void Client::on_update(object_ptr result) { user_info->photo = full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); - user_info->business_intro = full_info->business_info_ != nullptr && full_info->business_info_->intro_ != nullptr - ? std::move(full_info->business_info_->intro_) - : nullptr; - user_info->business_location = - full_info->business_info_ != nullptr && full_info->business_info_->location_ != nullptr - ? std::move(full_info->business_info_->location_) - : nullptr; - user_info->business_opening_hours = - full_info->business_info_ != nullptr && full_info->business_info_->opening_hours_ != nullptr - ? std::move(full_info->business_info_->opening_hours_) - : nullptr; + user_info->business_info = std::move(full_info->business_info_); user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 4b235f6..6ddd4fb 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -798,9 +798,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; - object_ptr business_intro; - object_ptr business_location; - object_ptr business_opening_hours; + object_ptr business_info; bool have_access = false; bool can_join_groups = false; From 1adfc80566d00c09d0cf443aead0e3aab95446bd Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 19 Mar 2024 16:31:34 +0300 Subject: [PATCH 23/42] Resolve business intro sticker set. --- telegram-bot-api/Client.cpp | 48 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 49 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8d132a7..da00ed9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4681,6 +4681,39 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal PromisedQueryPtr query_; }; +class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryCallback { + public: + TdOnGetChatBusinessIntroStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, + PromisedQueryPtr query) + : client_(client), chat_id_(chat_id), pinned_message_id_(pinned_message_id), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + auto chat_info = client_->get_chat(chat_id_); + CHECK(chat_info != nullptr); + CHECK(chat_info->type == ChatInfo::Type::Private); + auto user_info = client_->add_user_info(chat_info->user_id); + if (result->get_id() == td_api::error::ID) { + if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr && + user_info->business_info->intro_->sticker_ != nullptr) { + user_info->business_info->intro_->sticker_->set_id_ = 0; + } + } else { + CHECK(result->get_id() == td_api::stickerSet::ID); + auto sticker_set = move_object_as(result); + client_->on_get_sticker_set_name(sticker_set->id_, sticker_set->name_); + } + + answer_query(JsonChat(chat_id_, client_, true, pinned_message_id_), std::move(query_)); + } + + private: + Client *client_; + int64 chat_id_; + int64 pinned_message_id_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetChatStickerSetCallback final : public TdQueryCallback { public: TdOnGetChatStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, PromisedQueryPtr query) @@ -4759,6 +4792,21 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { td::make_unique( client_, chat_id_, pinned_message_id, std::move(query_))); } + } else if (chat_info->type == ChatInfo::Type::Private) { + auto user_info = client_->get_user_info(chat_info->user_id); + CHECK(user_info != nullptr); + + if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr) { + auto *sticker = user_info->business_info->intro_->sticker_.get(); + if (sticker != nullptr) { + auto sticker_set_id = sticker->set_id_; + if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { + return client_->send_request(make_object(sticker_set_id), + td::make_unique( + client_, chat_id_, pinned_message_id, std::move(query_))); + } + } + } } answer_query(JsonChat(chat_id_, client_, true, pinned_message_id), std::move(query_)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6ddd4fb..66b7f8c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -224,6 +224,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatCustomEmojiStickerSetCallback; + class TdOnGetChatBusinessIntroStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; From e327bbe8fe45125d72d476ff33b4ff0e806067c8 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:03:48 +0300 Subject: [PATCH 24/42] Add Message.is_from_offline. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index da00ed9..74d5c5b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2978,6 +2978,9 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (message_->is_topic_message) { object("is_topic_message", td::JsonTrue()); } + if (message_->is_from_offline) { + object("is_from_offline", td::JsonTrue()); + } } class Client::JsonMessageId final : public td::Jsonable { @@ -13406,6 +13409,7 @@ void Client::init_message(MessageInfo *message_info, object_ptr } message_info->can_be_saved = message->can_be_saved_; + message_info->is_from_offline = message->is_from_offline_; message_info->is_topic_message = message->is_topic_message_; message_info->author_signature = std::move(message->author_signature_); message_info->sender_boost_count = message->sender_boost_count_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 66b7f8c..116998c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -911,6 +911,7 @@ class Client final : public WebhookActor::Callback { bool can_be_saved = false; bool is_automatic_forward = false; bool is_topic_message = false; + bool is_from_offline = false; mutable bool is_content_changed = false; }; From d442d4b361e8cc4c5fd708deeab6ee844a1f8739 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:34:26 +0300 Subject: [PATCH 25/42] Add UsersShared.users. --- telegram-bot-api/Client.cpp | 35 +++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 74d5c5b..a5d4935 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2074,18 +2074,49 @@ class Client::JsonUserShared final : public td::Jsonable { const td_api::messageUsersShared *users_shared_; }; +class Client::JsonSharedUser final : public td::Jsonable { + public: + JsonSharedUser(const td_api::sharedUser *shared_user, const Client *client) + : shared_user_(shared_user), client_(client) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("user_id", shared_user_->user_id_); + if (!shared_user_->first_name_.empty()) { + object("first_name", shared_user_->first_name_); + } + if (!shared_user_->last_name_.empty()) { + object("last_name", shared_user_->last_name_); + } + if (!shared_user_->username_.empty()) { + object("username", shared_user_->username_); + } + if (shared_user_->photo_ != nullptr) { + object("photo", JsonPhoto(shared_user_->photo_.get(), client_)); + } + } + + private: + const td_api::sharedUser *shared_user_; + const Client *client_; +}; + class Client::JsonUsersShared final : public td::Jsonable { public: - explicit JsonUsersShared(const td_api::messageUsersShared *users_shared) : users_shared_(users_shared) { + JsonUsersShared(const td_api::messageUsersShared *users_shared, const Client *client) + : users_shared_(users_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("user_ids", td::json_array(users_shared_->users_, [](auto &user) { return user->user_id_; })); + object("users", td::json_array(users_shared_->users_, + [client = client_](auto &user) { return JsonSharedUser(user.get(), client); })); object("request_id", users_shared_->button_id_); } private: const td_api::messageUsersShared *users_shared_; + const Client *client_; }; class Client::JsonChatShared final : public td::Jsonable { @@ -2923,7 +2954,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { if (content->users_.size() == 1) { object("user_shared", JsonUserShared(content)); } - object("users_shared", JsonUsersShared(content)); + object("users_shared", JsonUsersShared(content, client_)); break; } case td_api::messageChatShared::ID: { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 116998c..9dba4fe 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -184,6 +184,7 @@ class Client final : public WebhookActor::Callback { class JsonChatSetMessageAutoDeleteTime; class JsonWriteAccessAllowed; class JsonUserShared; + class JsonSharedUser; class JsonUsersShared; class JsonChatShared; class JsonGiveaway; From e491a5a31dfb88ed8595e1535069e08835283678 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 13:37:31 +0300 Subject: [PATCH 26/42] Add more fields to ChatShared. --- telegram-bot-api/Client.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a5d4935..549e87d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2121,16 +2121,28 @@ class Client::JsonUsersShared final : public td::Jsonable { class Client::JsonChatShared final : public td::Jsonable { public: - explicit JsonChatShared(const td_api::messageChatShared *chat_shared) : chat_shared_(chat_shared) { + JsonChatShared(const td_api::messageChatShared *chat_shared, const Client *client) + : chat_shared_(chat_shared), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("chat_id", chat_shared_->chat_->chat_id_); + auto *shared_chat = chat_shared_->chat_.get(); + object("chat_id", shared_chat->chat_id_); + if (!shared_chat->title_.empty()) { + object("title", shared_chat->title_); + } + if (!shared_chat->username_.empty()) { + object("username", shared_chat->username_); + } + if (shared_chat->photo_ != nullptr) { + object("photo", JsonPhoto(shared_chat->photo_.get(), client_)); + } object("request_id", chat_shared_->button_id_); } private: const td_api::messageChatShared *chat_shared_; + const Client *client_; }; class Client::JsonGiveaway final : public td::Jsonable { @@ -2959,7 +2971,7 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { } case td_api::messageChatShared::ID: { auto content = static_cast(message_->content.get()); - object("chat_shared", JsonChatShared(content)); + object("chat_shared", JsonChatShared(content, client_)); break; } case td_api::messageStory::ID: { From e89489b1b26a8e3ae49c0fea9e88a3d98db549c7 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 14:50:01 +0300 Subject: [PATCH 27/42] Support requesting of additional fields by keyboard buttons. --- telegram-bot-api/Client.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 549e87d..8c93de9 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6947,10 +6947,13 @@ td::Result> Client::get_keyboard_butt auto restrict_user_is_premium = request_user_object.has_field("user_is_premium"); TRY_RESULT(user_is_premium, request_user_object.get_optional_bool_field("user_is_premium")); TRY_RESULT(max_quantity, request_user_object.get_optional_int_field("max_quantity", 1)); + TRY_RESULT(request_name, request_user_object.get_optional_bool_field("request_name")); + TRY_RESULT(request_username, request_user_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_user_object.get_optional_bool_field("request_photo")); return make_object( - text, make_object(id, restrict_user_is_bot, user_is_bot, - restrict_user_is_premium, user_is_premium, - max_quantity, false, false, false)); + text, make_object( + id, restrict_user_is_bot, user_is_bot, restrict_user_is_premium, user_is_premium, max_quantity, + request_name, request_username, request_photo)); } if (object.has_field("request_chat")) { @@ -6975,11 +6978,15 @@ td::Result> Client::get_keyboard_butt get_chat_administrator_rights(request_chat_object.extract_field("bot_administrator_rights"))); } TRY_RESULT(bot_is_member, request_chat_object.get_optional_bool_field("bot_is_member")); + TRY_RESULT(request_title, request_chat_object.get_optional_bool_field("request_title")); + TRY_RESULT(request_username, request_chat_object.get_optional_bool_field("request_username")); + TRY_RESULT(request_photo, request_chat_object.get_optional_bool_field("request_photo")); return make_object( - text, make_object( - id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, - chat_has_username, chat_is_created, std::move(user_administrator_rights), - std::move(bot_administrator_rights), bot_is_member, false, false, false)); + text, + make_object( + id, chat_is_channel, restrict_chat_is_forum, chat_is_forum, restrict_chat_has_username, chat_has_username, + chat_is_created, std::move(user_administrator_rights), std::move(bot_administrator_rights), bot_is_member, + request_title, request_username, request_photo)); } return make_object(text, nullptr); From f684e4c503929f8691f689459331d56ff48c80a3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 15:09:08 +0300 Subject: [PATCH 28/42] Add replaceStickerInSet. --- telegram-bot-api/Client.cpp | 22 ++++++++++++++++++++-- telegram-bot-api/Client.h | 4 +++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8c93de9..47c5660 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -303,6 +303,7 @@ bool Client::init_methods() { methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query); methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query); methods_.emplace("addstickertoset", &Client::process_add_sticker_to_set_query); + methods_.emplace("replacestickerinset", &Client::process_replace_sticker_in_set_query); methods_.emplace("setstickersettitle", &Client::process_set_sticker_set_title_query); methods_.emplace("setstickersetthumb", &Client::process_set_sticker_set_thumbnail_query); methods_.emplace("setstickersetthumbnail", &Client::process_set_sticker_set_thumbnail_query); @@ -8421,8 +8422,9 @@ td::Result>> Client::get_inp return std::move(stickers); } -td::Result> Client::get_sticker_input_file(const Query *query) { - auto file_id = trim(query->arg("sticker")); +td::Result> Client::get_sticker_input_file(const Query *query, + td::Slice field_name) { + auto file_id = trim(query->arg(field_name)); if (file_id.empty()) { return td::Status::Error(400, "Sticker is not specified"); } @@ -11217,6 +11219,22 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) { return td::Status::OK(); } +td::Status Client::process_replace_sticker_in_set_query(PromisedQueryPtr &query) { + TRY_RESULT(user_id, get_user_id(query.get())); + auto name = query->arg("name"); + TRY_RESULT(input_file, get_sticker_input_file(query.get(), "old_sticker")); + TRY_RESULT(sticker, get_input_sticker(query.get())); + + check_user(user_id, std::move(query), + [this, user_id, name, input_file = std::move(input_file), + sticker = std::move(sticker)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, name.str(), std::move(input_file), + std::move(sticker)), + td::make_unique(std::move(query))); + }); + return td::Status::OK(); +} + td::Status Client::process_set_sticker_set_title_query(PromisedQueryPtr &query) { auto name = query->arg("name"); auto title = query->arg("title"); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9dba4fe..147629a 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -502,7 +502,8 @@ class Client final : public WebhookActor::Callback { td::Result>> get_input_stickers(const Query *query) const; - static td::Result> get_sticker_input_file(const Query *query); + static td::Result> get_sticker_input_file(const Query *query, + td::Slice field_name = "sticker"); static td::Result get_passport_element_hash(td::Slice encoded_hash); @@ -697,6 +698,7 @@ class Client final : public WebhookActor::Callback { td::Status process_upload_sticker_file_query(PromisedQueryPtr &query); td::Status process_create_new_sticker_set_query(PromisedQueryPtr &query); td::Status process_add_sticker_to_set_query(PromisedQueryPtr &query); + td::Status process_replace_sticker_in_set_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_title_query(PromisedQueryPtr &query); td::Status process_set_sticker_set_thumbnail_query(PromisedQueryPtr &query); td::Status process_set_custom_emoji_sticker_set_thumbnail_query(PromisedQueryPtr &query); From f706d880553c5f0baedafd318f82746d333c1b7c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 22 Mar 2024 15:26:22 +0300 Subject: [PATCH 29/42] Add Chat.birthdate. --- telegram-bot-api/Client.cpp | 21 +++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 47c5660..96477d6 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -724,6 +724,23 @@ class Client::JsonReactionCount final : public td::Jsonable { const td_api::messageReaction *message_reaction_; }; +class Client::JsonBirthdate final : public td::Jsonable { + public: + explicit JsonBirthdate(const td_api::birthdate *birthdate) : birthdate_(birthdate) { + } + void store(td::JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("day", birthdate_->day_); + object("month", birthdate_->month_); + if (birthdate_->year_ != 0) { + object("year", birthdate_->year_); + } + } + + private: + const td_api::birthdate *birthdate_; +}; + class Client::JsonBusinessIntro final : public td::Jsonable { public: JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { @@ -948,6 +965,9 @@ class Client::JsonChat final : public td::Jsonable { object("business_opening_hours", JsonBusinessOpeningHours(business_info->opening_hours_.get())); } } + if (user_info->birthdate != nullptr) { + object("birthdate", JsonBirthdate(user_info->birthdate.get())); + } } photo = user_info->photo.get(); break; @@ -6521,6 +6541,7 @@ void Client::on_update(object_ptr result) { user_info->photo = full_info->photo_ == nullptr ? std::move(full_info->public_photo_) : std::move(full_info->photo_); user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); + user_info->birthdate = std::move(full_info->birthdate_); user_info->business_info = std::move(full_info->business_info_); user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 147629a..9c68403 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -93,6 +93,7 @@ class Client final : public WebhookActor::Callback { class JsonUsers; class JsonReactionType; class JsonReactionCount; + class JsonBirthdate; class JsonBusinessIntro; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; @@ -802,6 +803,7 @@ class Client final : public WebhookActor::Callback { object_ptr photo; td::string bio; + object_ptr birthdate; object_ptr business_info; bool have_access = false; From 5f6e1a262f9595c6493812c0ee87c5c7be7d2144 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 28 Mar 2024 19:40:12 +0300 Subject: [PATCH 30/42] Add User.can_connect_to_business. --- telegram-bot-api/Client.cpp | 2 ++ telegram-bot-api/Client.h | 1 + 2 files changed, 3 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 96477d6..0dc572c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -416,6 +416,7 @@ class Client::JsonUser final : public td::Jsonable { object("can_join_groups", td::JsonBool(user_info->can_join_groups)); object("can_read_all_group_messages", td::JsonBool(user_info->can_read_all_group_messages)); object("supports_inline_queries", td::JsonBool(user_info->is_inline_bot)); + object("can_connect_to_business", td::JsonBool(user_info->can_connect_to_business)); } } @@ -12115,6 +12116,7 @@ void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->can_join_groups = bot->can_join_groups_; user_info->can_read_all_group_messages = bot->can_read_all_group_messages_; user_info->is_inline_bot = bot->is_inline_; + user_info->can_connect_to_business = bot->can_connect_to_business_; break; } case td_api::userTypeDeleted::ID: diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9c68403..b1cc26a 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -809,6 +809,7 @@ class Client final : public WebhookActor::Callback { bool have_access = false; bool can_join_groups = false; bool can_read_all_group_messages = false; + bool can_connect_to_business = false; bool is_inline_bot = false; bool has_private_forwards = false; bool has_restricted_voice_and_video_messages = false; From c69178b2983c4769942c5dc1a6af8c2baa7424e9 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 28 Mar 2024 19:45:48 +0300 Subject: [PATCH 31/42] Add Chat.personal_chat. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/Client.h | 1 + 2 files changed, 5 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0dc572c..01b1b46 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -969,6 +969,9 @@ class Client::JsonChat final : public td::Jsonable { if (user_info->birthdate != nullptr) { object("birthdate", JsonBirthdate(user_info->birthdate.get())); } + if (user_info->personal_chat_id != 0) { + object("personal_chat", JsonChat(user_info->personal_chat_id, client_)); + } } photo = user_info->photo.get(); break; @@ -6544,6 +6547,7 @@ void Client::on_update(object_ptr result) { user_info->bio = full_info->bio_ != nullptr ? std::move(full_info->bio_->text_) : td::string(); user_info->birthdate = std::move(full_info->birthdate_); user_info->business_info = std::move(full_info->business_info_); + user_info->personal_chat_id = full_info->personal_chat_id_; user_info->has_private_forwards = full_info->has_private_forwards_; user_info->has_restricted_voice_and_video_messages = full_info->has_restricted_voice_and_video_note_messages_; break; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index b1cc26a..f53b8e1 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -805,6 +805,7 @@ class Client final : public WebhookActor::Callback { td::string bio; object_ptr birthdate; object_ptr business_info; + int64 personal_chat_id = 0; bool have_access = false; bool can_join_groups = false; From 6173126371aa7a8d7cf7974d2b00cde22369e51f Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 31 Mar 2024 19:26:26 +0300 Subject: [PATCH 32/42] Update version to 7.2. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f151b7..1028fe4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.2 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 5817ea7..97b8fe7 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "7.1"; + parameters->version_ = "7.2"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From b56b61ba0e12d730fb777771a0dd7590b05c271d Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 21 Apr 2024 22:04:27 +0300 Subject: [PATCH 33/42] Update TDLib to 1.8.28. --- td | 2 +- telegram-bot-api/Client.cpp | 41 +++++++++++++++++++------------------ telegram-bot-api/Client.h | 4 ++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/td b/td index efc6bd5..38d31da 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit efc6bd553b61dea0ae8c0436695e8d2539bf03f9 +Subproject commit 38d31da77a72619cf7ec5d479338a48274cc7446 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 01b1b46..12105fb 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -742,25 +742,26 @@ class Client::JsonBirthdate final : public td::Jsonable { const td_api::birthdate *birthdate_; }; -class Client::JsonBusinessIntro final : public td::Jsonable { +class Client::JsonBusinessStartPage final : public td::Jsonable { public: - JsonBusinessIntro(const td_api::businessIntro *intro, const Client *client) : intro_(intro), client_(client) { + JsonBusinessStartPage(const td_api::businessStartPage *start_page, const Client *client) + : start_page_(start_page), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - if (!intro_->title_.empty()) { - object("title", intro_->title_); + if (!start_page_->title_.empty()) { + object("title", start_page_->title_); } - if (!intro_->message_.empty()) { - object("message", intro_->message_); + if (!start_page_->message_.empty()) { + object("message", start_page_->message_); } - if (intro_->sticker_ != nullptr) { - object("sticker", JsonSticker(intro_->sticker_.get(), client_)); + if (start_page_->sticker_ != nullptr) { + object("sticker", JsonSticker(start_page_->sticker_.get(), client_)); } } private: - const td_api::businessIntro *intro_; + const td_api::businessStartPage *start_page_; const Client *client_; }; @@ -956,8 +957,8 @@ class Client::JsonChat final : public td::Jsonable { } if (user_info->business_info != nullptr) { auto business_info = user_info->business_info.get(); - if (business_info->intro_ != nullptr) { - object("business_intro", JsonBusinessIntro(business_info->intro_.get(), client_)); + if (business_info->start_page_ != nullptr) { + object("business_intro", JsonBusinessStartPage(business_info->start_page_.get(), client_)); } if (business_info->location_ != nullptr) { object("business_location", JsonBusinessLocation(business_info->location_.get())); @@ -4752,10 +4753,10 @@ class Client::TdOnGetChatCustomEmojiStickerSetCallback final : public TdQueryCal PromisedQueryPtr query_; }; -class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryCallback { +class Client::TdOnGetChatBusinessStartPageStickerSetCallback final : public TdQueryCallback { public: - TdOnGetChatBusinessIntroStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, - PromisedQueryPtr query) + TdOnGetChatBusinessStartPageStickerSetCallback(Client *client, int64 chat_id, int64 pinned_message_id, + PromisedQueryPtr query) : client_(client), chat_id_(chat_id), pinned_message_id_(pinned_message_id), query_(std::move(query)) { } @@ -4765,9 +4766,9 @@ class Client::TdOnGetChatBusinessIntroStickerSetCallback final : public TdQueryC CHECK(chat_info->type == ChatInfo::Type::Private); auto user_info = client_->add_user_info(chat_info->user_id); if (result->get_id() == td_api::error::ID) { - if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr && - user_info->business_info->intro_->sticker_ != nullptr) { - user_info->business_info->intro_->sticker_->set_id_ = 0; + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr && + user_info->business_info->start_page_->sticker_ != nullptr) { + user_info->business_info->start_page_->sticker_->set_id_ = 0; } } else { CHECK(result->get_id() == td_api::stickerSet::ID); @@ -4867,13 +4868,13 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { auto user_info = client_->get_user_info(chat_info->user_id); CHECK(user_info != nullptr); - if (user_info->business_info != nullptr && user_info->business_info->intro_ != nullptr) { - auto *sticker = user_info->business_info->intro_->sticker_.get(); + if (user_info->business_info != nullptr && user_info->business_info->start_page_ != nullptr) { + auto *sticker = user_info->business_info->start_page_->sticker_.get(); if (sticker != nullptr) { auto sticker_set_id = sticker->set_id_; if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { return client_->send_request(make_object(sticker_set_id), - td::make_unique( + td::make_unique( client_, chat_id_, pinned_message_id, std::move(query_))); } } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f53b8e1..dd460b0 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -94,7 +94,7 @@ class Client final : public WebhookActor::Callback { class JsonReactionType; class JsonReactionCount; class JsonBirthdate; - class JsonBusinessIntro; + class JsonBusinessStartPage; class JsonBusinessLocation; class JsonBusinessOpeningHoursInterval; class JsonBusinessOpeningHours; @@ -226,7 +226,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatCustomEmojiStickerSetCallback; - class TdOnGetChatBusinessIntroStickerSetCallback; + class TdOnGetChatBusinessStartPageStickerSetCallback; class TdOnGetChatPinnedMessageCallback; class TdOnGetChatPinnedMessageToUnpinCallback; class TdOnGetGroupMembersCallback; From d2ec2fff0018a5a7eaba800694dadb95abe182ce Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 1 May 2024 20:22:31 +0300 Subject: [PATCH 34/42] Add Message.chat_background_set. --- telegram-bot-api/Client.cpp | 129 +++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 3 + 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 12105fb..4f12f8e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1738,6 +1738,128 @@ class Client::JsonStory final : public td::Jsonable { const Client *client_; }; +class Client::JsonBackgroundFill final : public td::Jsonable { + public: + explicit JsonBackgroundFill(const td_api::BackgroundFill *background_fill) : background_fill_(background_fill) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_fill_ != nullptr); + auto object = scope->enter_object(); + switch (background_fill_->get_id()) { + case td_api::backgroundFillSolid::ID: { + auto fill = static_cast(background_fill_); + object("type", "solid"); + object("color", fill->color_); + break; + } + case td_api::backgroundFillGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "gradient"); + object("top_color", fill->top_color_); + object("bottom_color", fill->bottom_color_); + object("rotation_angle", fill->rotation_angle_); + break; + } + case td_api::backgroundFillFreeformGradient::ID: { + auto fill = static_cast(background_fill_); + object("type", "freeform_gradient"); + object("colors", td::json_array(fill->colors_, [](int32 color) { return color; })); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundFill *background_fill_; +}; + +class Client::JsonBackgroundType final : public td::Jsonable { + public: + JsonBackgroundType(const td_api::BackgroundType *background_type, const td_api::document *document, + int32 dark_theme_dimming, const Client *client) + : background_type_(background_type) + , document_(document) + , dark_theme_dimming_(dark_theme_dimming) + , client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(background_type_ != nullptr); + auto object = scope->enter_object(); + switch (background_type_->get_id()) { + case td_api::backgroundTypeWallpaper::ID: { + auto type = static_cast(background_type_); + object("type", "wallpaper"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("dark_theme_dimming", dark_theme_dimming_); + if (type->is_blurred_) { + object("is_blurred", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypePattern::ID: { + auto type = static_cast(background_type_); + object("type", "pattern"); + CHECK(document_ != nullptr); + object("document", JsonDocument(document_, client_)); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("intensity", type->intensity_); + if (type->is_inverted_) { + object("is_inverted", td::JsonTrue()); + } + if (type->is_moving_) { + object("is_moving", td::JsonTrue()); + } + break; + } + case td_api::backgroundTypeFill::ID: { + auto type = static_cast(background_type_); + object("type", "fill"); + object("fill", JsonBackgroundFill(type->fill_.get())); + object("dark_theme_dimming", dark_theme_dimming_); + break; + } + case td_api::backgroundTypeChatTheme::ID: { + auto type = static_cast(background_type_); + object("type", "chat_theme"); + object("theme_name", type->theme_name_); + break; + } + default: + UNREACHABLE(); + } + } + + private: + const td_api::BackgroundType *background_type_; + const td_api::document *document_; + int32 dark_theme_dimming_; + const Client *client_; +}; + +class Client::JsonChatBackground final : public td::Jsonable { + public: + JsonChatBackground(const td_api::chatBackground *chat_background, const Client *client) + : chat_background_(chat_background), client_(client) { + } + void store(td::JsonValueScope *scope) const { + CHECK(chat_background_ != nullptr); + auto object = scope->enter_object(); + auto background = chat_background_->background_.get(); + object("type", JsonBackgroundType(background->type_.get(), background->document_.get(), + chat_background_->dark_theme_dimming_, client_)); + } + + private: + const td_api::chatBackground *chat_background_; + const Client *client_; +}; + class Client::JsonForumTopicCreated final : public td::Jsonable { public: explicit JsonForumTopicCreated(const td_api::messageForumTopicCreated *forum_topic_created) @@ -3005,8 +3127,11 @@ void Client::JsonMessage::store(td::JsonValueScope *scope) const { object("story", JsonStory(content->story_sender_chat_id_, content->story_id_, client_)); break; } - case td_api::messageChatSetBackground::ID: + case td_api::messageChatSetBackground::ID: { + auto content = static_cast(message_->content.get()); + object("chat_background_set", JsonChatBackground(content->background_.get(), client_)); break; + } case td_api::messagePremiumGiftCode::ID: break; case td_api::messagePremiumGiveawayCreated::ID: @@ -12995,8 +13120,6 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Thu, 2 May 2024 17:10:28 +0300 Subject: [PATCH 35/42] Reget inaccessible users. --- telegram-bot-api/Client.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 4f12f8e..1492853 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -5837,7 +5837,7 @@ void Client::check_user_read_access(const UserInfo *user_info, PromisedQueryPtr template void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { return check_user_read_access(user_info, std::move(query), std::move(on_success)); } send_request(make_object(user_id), @@ -5847,7 +5847,7 @@ void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_succ template void Client::check_user_no_fail(int64 user_id, PromisedQueryPtr query, OnSuccess on_success) { const UserInfo *user_info = get_user_info(user_id); - if (user_info != nullptr) { + if (user_info != nullptr && user_info->have_access) { on_success(std::move(query)); return; } @@ -5943,6 +5943,12 @@ void Client::check_chat(td::Slice chat_id_str, AccessRights access_rights, Promi auto chat_id = td::to_integer(chat_id_str); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return check_chat_access(chat_id, access_rights, chat_info, std::move(query), std::move(on_success)); } @@ -5964,6 +5970,12 @@ void Client::check_chat_no_fail(td::Slice chat_id_str, PromisedQueryPtr query, O auto chat_id = r_chat_id.move_as_ok(); auto chat_info = get_chat(chat_id); + if (chat_info != nullptr && chat_info->type == ChatInfo::Type::Private) { + const UserInfo *user_info = get_user_info(chat_info->user_id); + if (user_info == nullptr || !user_info->have_access) { + chat_info = nullptr; + } + } if (chat_info != nullptr) { return on_success(chat_id, std::move(query)); } From a5a1c509ebc568e7811961dd7fb5c9304d7f56bd Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:21:18 +0300 Subject: [PATCH 36/42] Update TDLib to 1.8.29. --- td | 2 +- telegram-bot-api/Client.cpp | 48 ++++++++++++++----------------- telegram-bot-api/Client.h | 2 +- telegram-bot-api/WebhookActor.cpp | 3 +- 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/td b/td index 38d31da..af69dd4 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 38d31da77a72619cf7ec5d479338a48274cc7446 +Subproject commit af69dd4397b6dc1bf23ba0fd0bf429fcba6454f6 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1492853..5b5a065 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1634,7 +1634,7 @@ class Client::JsonPollOption final : public td::Jsonable { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); - object("text", option_->text_); + object("text", option_->text_->text_); object("voter_count", option_->voter_count_); // ignore is_chosen } @@ -1650,7 +1650,7 @@ class Client::JsonPoll final : public td::Jsonable { void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("id", td::to_string(poll_->id_)); - object("question", poll_->question_); + object("question", poll_->question_->text_); object("options", td::json_array(poll_->options_, [](auto &option) { return JsonPollOption(option.get()); })); object("total_voter_count", poll_->total_voter_count_); if (poll_->open_period_ != 0 && poll_->close_date_ != 0) { @@ -2395,7 +2395,7 @@ class Client::JsonGiveawayCompleted final : public td::Jsonable { class Client::JsonChatBoostAdded final : public td::Jsonable { public: - JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { + explicit JsonChatBoostAdded(const td_api::messageChatBoost *chat_boost) : chat_boost_(chat_boost) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); @@ -3895,8 +3895,7 @@ class Client::JsonBusinessMessagesDeleted final : public td::Jsonable { auto object = scope->enter_object(); object("business_connection_id", update_->connection_id_); object("chat", JsonChat(update_->chat_id_, client_)); - object("message_ids", - td::json_array(update_->message_ids_, [](int64 message_id) { return as_client_message_id(message_id); })); + object("message_ids", td::json_array(update_->message_ids_, as_client_message_id)); } private: @@ -6142,7 +6141,7 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters } if (message_thread_id <= 0) { - // if message thread isn't specified, then the message to reply can be only from a different chat + // if message thread isn't specified, then the message to be replied can be only from a different chat if (reply_parameters.reply_in_chat_id == chat_id) { reply_parameters.reply_in_chat_id = 0; } @@ -6172,13 +6171,13 @@ void Client::check_reply_parameters(td::Slice chat_id_str, InputReplyParameters on_success = std::move(on_reply_message_resolved)]( int64 reply_in_chat_id, PromisedQueryPtr query) mutable { if (!have_message_access(reply_in_chat_id)) { - return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to reply not found"); + return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", "message to be replied not found"); } send_request(make_object(reply_in_chat_id, reply_to_message_id), td::make_unique>( - this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, "message to reply", - std::move(query), std::move(on_success))); + this, reply_in_chat_id, reply_to_message_id, allow_sending_without_reply, + "message to be replied", std::move(query), std::move(on_success))); }; if (reply_parameters.reply_in_chat_id.empty()) { return on_reply_chat_resolved(chat_id, std::move(query)); @@ -9249,7 +9248,7 @@ td::Result> Client::get_input_me provider_token.str(), provider_data.str(), start_parameter.str(), std::move(extended_media)); } -td::Result> Client::get_poll_options(const Query *query) { +td::Result>> Client::get_poll_options(const Query *query) { auto input_options = query->arg("options"); LOG(INFO) << "Parsing JSON object: " << input_options; auto r_value = json_decode(input_options); @@ -9263,12 +9262,12 @@ td::Result> Client::get_poll_options(const Query *query) return td::Status::Error(400, "Expected an Array of String as options"); } - td::vector options; + td::vector> options; for (auto &input_option : value.get_array()) { if (input_option.type() != td::JsonValue::Type::String) { return td::Status::Error(400, "Expected an option to be of type String"); } - options.push_back(input_option.get_string().str()); + options.push_back(make_object(input_option.get_string().str(), td::Auto())); } return std::move(options); } @@ -9953,8 +9952,9 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { int32 open_period = get_integer_arg(query.get(), "open_period", 0, 0, 10 * 60); int32 close_date = get_integer_arg(query.get(), "close_date", 0); auto is_closed = to_bool(query->arg("is_closed")); - do_send_message(make_object(question.str(), std::move(options), is_anonymous, - std::move(poll_type), open_period, close_date, is_closed), + do_send_message(make_object(make_object(question.str(), td::Auto()), + std::move(options), is_anonymous, std::move(poll_type), + open_period, close_date, is_closed), std::move(query)); return td::Status::OK(); } @@ -10254,8 +10254,8 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu [this, inline_message_id = inline_message_id.str(), location = std::move(location), heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request( - make_object(inline_message_id, std::move(reply_markup), - std::move(location), heading, proximity_alert_radius), + make_object( + inline_message_id, std::move(reply_markup), std::move(location), 0, heading, proximity_alert_radius), td::make_unique(std::move(query))); }); } else { @@ -10268,8 +10268,8 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(location), heading, - proximity_alert_radius), + chat_id, message_id, std::move(reply_markup), std::move(location), 0, + heading, proximity_alert_radius), td::make_unique(this, std::move(query))); }); }); @@ -10956,7 +10956,7 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); - check_chat(chat_id, AccessRights::ReadMembers, std::move(query), + check_chat(chat_id, user_id == my_id_ ? AccessRights::Read : AccessRights::ReadMembers, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { get_chat_member(chat_id, user_id, std::move(query), [this, chat_type = get_chat_type(chat_id)](object_ptr &&chat_member, @@ -12950,14 +12950,8 @@ void Client::add_update_message_reaction_count(object_ptr &&update) { CHECK(update != nullptr); const auto *connection = add_business_connection(std::move(update->connection_), true); - auto left_time = connection->date_ + 86400 - get_unix_time(); - if (left_time > 0) { - auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); - add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), left_time, webhook_queue_id); - } else { - LOG(DEBUG) << "Skip updateBusinessConnection with date " << connection->date_ << ", because current date is " - << get_unix_time(); - } + auto webhook_queue_id = connection->user_id_ + (static_cast(10) << 33); + add_update(UpdateType::BusinessConnection, JsonBusinessConnection(connection, this), 86400, webhook_queue_id); } void Client::add_update_business_messages_deleted(object_ptr &&update) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 86e10ae..9b140bc 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -563,7 +563,7 @@ class Client final : public WebhookActor::Callback { static object_ptr get_message_send_options(bool disable_notification, bool protect_content); - static td::Result> get_poll_options(const Query *query); + static td::Result>> get_poll_options(const Query *query); static td::Result> get_reaction_type(td::JsonValue &&value); diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 7e04a67..3e0caa0 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -590,8 +590,7 @@ void WebhookActor::send_updates() { void WebhookActor::handle(td::unique_ptr response) { SCOPE_EXIT { - bool dummy = false; - td::Scheduler::instance()->destroy_on_scheduler(SharedData::get_file_gc_scheduler_id(), response, dummy); + td::Scheduler::instance()->destroy_on_scheduler_unique_ptr(SharedData::get_file_gc_scheduler_id(), response); }; auto connection_id = get_link_token(); From 9f4e8eb86758eb97954470c22a269e2273bc500d Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:31:50 +0300 Subject: [PATCH 37/42] Add Chat.max_reaction_count. --- telegram-bot-api/Client.cpp | 31 ++++++++++++++++++++++--------- telegram-bot-api/Client.h | 4 ++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 5b5a065..7778364 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1142,6 +1142,7 @@ class Client::JsonChat final : public td::Jsonable { td::json_array(chat_info->available_reactions->reactions_, [](const auto &reaction) { return JsonReactionType(reaction.get()); })); } + object("max_reaction_count", chat_info->max_reaction_count); CHECK(chat_info->accent_color_id != -1); object("accent_color_id", chat_info->accent_color_id); if (chat_info->background_custom_emoji_id != 0) { @@ -6591,9 +6592,7 @@ void Client::on_update(object_ptr result) { chat->emoji_status_ != nullptr ? chat->emoji_status_->custom_emoji_id_ : 0; chat_info->emoji_status_expiration_date = chat->emoji_status_ != nullptr ? chat->emoji_status_->expiration_date_ : 0; - if (chat->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { - chat_info->available_reactions = move_object_as(chat->available_reactions_); - } + set_chat_available_reactions(chat_info, std::move(chat->available_reactions_)); chat_info->accent_color_id = chat->accent_color_id_; chat_info->background_custom_emoji_id = chat->background_custom_emoji_id_; chat_info->profile_accent_color_id = chat->profile_accent_color_id_; @@ -6643,12 +6642,7 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); CHECK(chat_info->type != ChatInfo::Type::Unknown); - if (update->available_reactions_->get_id() == td_api::chatAvailableReactionsSome::ID) { - chat_info->available_reactions = - move_object_as(update->available_reactions_); - } else { - chat_info->available_reactions = nullptr; - } + set_chat_available_reactions(chat_info, std::move(update->available_reactions_)); break; } case td_api::updateChatAccentColors::ID: { @@ -12349,6 +12343,25 @@ const Client::ChatInfo *Client::get_chat(int64 chat_id) const { return chats_.get_pointer(chat_id); } +void Client::set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions) { + CHECK(chat_info != nullptr); + CHECK(available_reactions != nullptr); + switch (available_reactions->get_id()) { + case td_api::chatAvailableReactionsSome::ID: + chat_info->available_reactions = move_object_as(available_reactions); + chat_info->max_reaction_count = chat_info->available_reactions->max_reaction_count_; + break; + case td_api::chatAvailableReactionsAll::ID: + chat_info->available_reactions = nullptr; + chat_info->max_reaction_count = + static_cast(available_reactions.get())->max_reaction_count_; + break; + default: + UNREACHABLE(); + } +} + Client::ChatType Client::get_chat_type(int64 chat_id) const { auto chat_info = get_chat(chat_id); if (chat_info == nullptr) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 9b140bc..679e077 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -878,6 +878,7 @@ class Client final : public WebhookActor::Callback { int64 background_custom_emoji_id = 0; int64 profile_background_custom_emoji_id = 0; bool has_protected_content = false; + int32 max_reaction_count = 0; object_ptr available_reactions; object_ptr photo_info; object_ptr permissions; @@ -890,6 +891,9 @@ class Client final : public WebhookActor::Callback { ChatInfo *add_chat(int64 chat_id); const ChatInfo *get_chat(int64 chat_id) const; + void set_chat_available_reactions(ChatInfo *chat_info, + object_ptr &&available_reactions); + enum class ChatType { Private, Group, Supergroup, Channel, Unknown }; ChatType get_chat_type(int64 chat_id) const; From 7febd857d6d6084e291f80667ccbd0373959f637 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 00:57:31 +0300 Subject: [PATCH 38/42] Add ChatMemberUpdated.via_join_request. --- telegram-bot-api/Client.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7778364..3502e19 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3655,6 +3655,9 @@ class Client::JsonChatMemberUpdated final : public td::Jsonable { if (update_->invite_link_ != nullptr) { object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_)); } + if (update_->via_join_request_) { + object("via_join_request", td::JsonTrue()); + } if (update_->via_chat_folder_invite_link_) { object("via_chat_folder_invite_link", td::JsonTrue()); } From ff01a73df3794c31670ecaa08d2a30d049ec5c72 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:12:16 +0300 Subject: [PATCH 39/42] Add live_period parameter to editMessageLiveLocation. --- telegram-bot-api/Client.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 3502e19..783c996 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -10235,6 +10235,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &query) { object_ptr location = nullptr; + int32 live_period = get_integer_arg(query.get(), "live_period", 0); int32 heading = get_integer_arg(query.get(), "heading", 0); int32 proximity_alert_radius = get_integer_arg(query.get(), "proximity_alert_radius", 0); if (query->method() == "editmessagelivelocation") { @@ -10248,25 +10249,25 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu TRY_RESULT(inline_message_id, get_inline_message_id(query.get())); resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, inline_message_id = inline_message_id.str(), location = std::move(location), heading, + [this, inline_message_id = inline_message_id.str(), location = std::move(location), live_period, heading, proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { - send_request( - make_object( - inline_message_id, std::move(reply_markup), std::move(location), 0, heading, proximity_alert_radius), - td::make_unique(std::move(query))); + send_request(make_object(inline_message_id, std::move(reply_markup), + std::move(location), live_period, heading, + proximity_alert_radius), + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( std::move(reply_markup), std::move(query), - [this, chat_id = chat_id.str(), message_id, location = std::move(location), heading, proximity_alert_radius]( - object_ptr reply_markup, PromisedQueryPtr query) mutable { + [this, chat_id = chat_id.str(), message_id, location = std::move(location), live_period, heading, + proximity_alert_radius](object_ptr reply_markup, PromisedQueryPtr query) mutable { check_message(chat_id, message_id, false, AccessRights::Edit, "message to edit", std::move(query), - [this, location = std::move(location), heading, proximity_alert_radius, + [this, location = std::move(location), live_period, heading, proximity_alert_radius, reply_markup = std::move(reply_markup)](int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( - chat_id, message_id, std::move(reply_markup), std::move(location), 0, - heading, proximity_alert_radius), + chat_id, message_id, std::move(reply_markup), std::move(location), + live_period, heading, proximity_alert_radius), td::make_unique(this, std::move(query))); }); }); From 1d3a1f2bf16128c88ca3fd0c17fabbfe05d42406 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:49:17 +0300 Subject: [PATCH 40/42] Support custom emoji entities in incoming polls. --- telegram-bot-api/Client.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 783c996..881cbf2 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1631,17 +1631,21 @@ class Client::JsonInvoice final : public td::Jsonable { class Client::JsonPollOption final : public td::Jsonable { public: - explicit JsonPollOption(const td_api::pollOption *option) : option_(option) { + JsonPollOption(const td_api::pollOption *option, const Client *client) : option_(option), client_(client) { } void store(td::JsonValueScope *scope) const { auto object = scope->enter_object(); object("text", option_->text_->text_); + if (!option_->text_->entities_.empty()) { + object("text_entities", JsonVectorEntities(option_->text_->entities_, client_)); + } object("voter_count", option_->voter_count_); // ignore is_chosen } private: const td_api::pollOption *option_; + const Client *client_; }; class Client::JsonPoll final : public td::Jsonable { @@ -1652,7 +1656,12 @@ class Client::JsonPoll final : public td::Jsonable { auto object = scope->enter_object(); object("id", td::to_string(poll_->id_)); object("question", poll_->question_->text_); - object("options", td::json_array(poll_->options_, [](auto &option) { return JsonPollOption(option.get()); })); + if (!poll_->question_->entities_.empty()) { + object("question_entities", JsonVectorEntities(poll_->question_->entities_, client_)); + } + object("options", td::json_array(poll_->options_, [client = client_](auto &option) { + return JsonPollOption(option.get(), client); + })); object("total_voter_count", poll_->total_voter_count_); if (poll_->open_period_ != 0 && poll_->close_date_ != 0) { object("open_period", poll_->open_period_); From 681e67c055ddee40c6d8e12f270bc1dc69825885 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 01:56:10 +0300 Subject: [PATCH 41/42] Support sending polls with custom emoji. --- telegram-bot-api/Client.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 881cbf2..33c3943 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -9271,6 +9271,16 @@ td::Result>> Client::get_po td::vector> options; for (auto &input_option : value.get_array()) { if (input_option.type() != td::JsonValue::Type::String) { + if (input_option.type() == td::JsonValue::Type::Object) { + auto &object = input_option.get_object(); + TRY_RESULT(text, object.get_required_string_field("text")); + TRY_RESULT(parse_mode, object.get_optional_string_field("text_parse_mode")); + TRY_RESULT(option_text, + get_formatted_text(std::move(text), std::move(parse_mode), object.extract_field("text_entities"))); + options.push_back(std::move(option_text)); + continue; + } + return td::Status::Error(400, "Expected an option to be of type String"); } options.push_back(make_object(input_option.get_string().str(), td::Auto())); @@ -9934,7 +9944,8 @@ td::Status Client::process_send_contact_query(PromisedQueryPtr &query) { } td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { - auto question = query->arg("question"); + TRY_RESULT(question, get_formatted_text(query->arg("question").str(), query->arg("question_parse_mode").str(), + get_input_entities(query.get(), "question_entities"))); TRY_RESULT(options, get_poll_options(query.get())); bool is_anonymous = true; if (query->has_arg("is_anonymous")) { @@ -9958,9 +9969,8 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { int32 open_period = get_integer_arg(query.get(), "open_period", 0, 0, 10 * 60); int32 close_date = get_integer_arg(query.get(), "close_date", 0); auto is_closed = to_bool(query->arg("is_closed")); - do_send_message(make_object(make_object(question.str(), td::Auto()), - std::move(options), is_anonymous, std::move(poll_type), - open_period, close_date, is_closed), + do_send_message(make_object(std::move(question), std::move(options), is_anonymous, + std::move(poll_type), open_period, close_date, is_closed), std::move(query)); return td::Status::OK(); } From f95d406da67adb8ac13d9c562291aa57c65398e0 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 4 May 2024 02:37:29 +0300 Subject: [PATCH 42/42] Update version to 7.3. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1028fe4..276606d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 7.2 LANGUAGES CXX) +project(TelegramBotApi VERSION 7.3 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 97b8fe7..f66a522 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -165,7 +165,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "7.2"; + parameters->version_ = "7.3"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();