From b8693ae500a9e596d36edaf402f8bfd52da00f72 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jun 2021 06:48:24 +0300 Subject: [PATCH] Support new bot command methods. --- telegram-bot-api/Client.cpp | 174 ++++++++++++++++++++++++++++++------ telegram-bot-api/Client.h | 20 +++++ 2 files changed, 167 insertions(+), 27 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8b9b191..6edf756 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -178,6 +178,7 @@ bool Client::init_methods() { methods_.emplace("getme", &Client::process_get_me_query); methods_.emplace("getmycommands", &Client::process_get_my_commands_query); methods_.emplace("setmycommands", &Client::process_set_my_commands_query); + methods_.emplace("deletemycommands", &Client::process_delete_my_commands_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); methods_.emplace("sendanimation", &Client::process_send_animation_query); @@ -288,7 +289,7 @@ class Client::JsonDatedFile : public Jsonable { class Client::JsonDatedFiles : public Jsonable { public: - JsonDatedFiles(const td::vector> &files, const Client *client) + JsonDatedFiles(const td::vector> &files, const Client *client) : files_(files), client_(client) { } void store(JsonValueScope *scope) const { @@ -299,7 +300,7 @@ class Client::JsonDatedFiles : public Jsonable { } private: - const td::vector> &files_; + const td::vector> &files_; const Client *client_; }; @@ -3133,9 +3134,9 @@ class Client::TdOnGetMyCommandsCallback : public TdQueryCallback { return fail_query_with_error(std::move(query_), move_object_as(result)); } - CHECK(result->get_id() == td_api::userFullInfo::ID); - auto user_full_info = move_object_as(result); - answer_query(td::json_array(user_full_info->commands_, [](auto &command) { return JsonBotCommand(command.get()); }), + CHECK(result->get_id() == td_api::botCommands::ID); + auto bot_commands = move_object_as(result); + answer_query(td::json_array(bot_commands->commands_, [](auto &command) { return JsonBotCommand(command.get()); }), std::move(query_)); } @@ -3728,6 +3729,36 @@ void Client::check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQ std::move(on_success))); } +template +void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { + CHECK(scope.scope_ != nullptr); + if (scope.chat_id_.empty()) { + on_success(std::move(scope.scope_), std::move(query)); + return; + } + check_chat(scope.chat_id_, AccessRights::ReadMembers, std::move(query), + [this, user_id = scope.user_id_, scope_id = scope.scope_->get_id(), on_success = std::move(on_success)]( + int64 chat_id, PromisedQueryPtr query) mutable { + switch (scope_id) { + case td_api::botCommandScopeChat::ID: + on_success(make_object(chat_id), std::move(query)); + break; + case td_api::botCommandScopeChatAdministrators::ID: + on_success(make_object(chat_id), std::move(query)); + break; + case td_api::botCommandScopeChatMember::ID: + check_user_no_fail( + user_id, std::move(query), + [chat_id, user_id, on_success = std::move(on_success)](PromisedQueryPtr query) mutable { + on_success(make_object(chat_id, user_id), std::move(query)); + }); + break; + default: + UNREACHABLE(); + } + }); +} + template void Client::check_remote_file_id(td::string file_id, PromisedQueryPtr query, OnSuccess on_success) { if (file_id.empty()) { @@ -5415,6 +5446,69 @@ td::Result> Client::get_inlin return Status::Error(400, PSLICE() << "type \"" << type << "\" is unsupported for the inline query result"); } +td::Result Client::get_bot_command_scope(JsonValue &&value) { + if (value.type() != JsonValue::Type::Object) { + return Status::Error(400, "BotCommandScope must be an Object"); + } + + auto &object = value.get_object(); + + TRY_RESULT(type, get_json_object_string_field(object, "type", false)); + if (type == "default") { + return BotCommandScope(make_object()); + } + if (type == "all_private_chats") { + return BotCommandScope(make_object()); + } + if (type == "all_group_chats") { + return BotCommandScope(make_object()); + } + if (type == "all_chat_administrators") { + return BotCommandScope(make_object()); + } + if (type != "chat" && type != "chat_administrators" && type != "chat_member") { + return Status::Error(400, "Unsupported type specified"); + } + + TRY_RESULT(chat_id, get_json_object_string_field(object, "chat_id", false)); + if (chat_id.empty()) { + return Status::Error(400, "Empty chat_id specified"); + } + if (type == "chat") { + return BotCommandScope(make_object(0), std::move(chat_id)); + } + if (type == "chat_administrators") { + return BotCommandScope(make_object(0), std::move(chat_id)); + } + + TRY_RESULT(user_id, get_json_object_int_field(object, "user_id", false)); + if (user_id <= 0) { + return Status::Error(400, "Invalid user_id specified"); + } + CHECK(type == "chat_member"); + return BotCommandScope(make_object(0, user_id), std::move(chat_id), user_id); +} + +td::Result Client::get_bot_command_scope(const Query *query) { + auto scope = query->arg("scope"); + if (scope.empty()) { + return BotCommandScope(make_object()); + } + + LOG(INFO) << "Parsing JSON object: " << scope; + auto r_value = json_decode(scope); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return Status::Error(400, "Can't parse BotCommandScope JSON object"); + } + + auto r_scope = get_bot_command_scope(r_value.move_as_ok()); + if (r_scope.is_error()) { + return Status::Error(400, PSLICE() << "Can't parse BotCommandScope: " << r_scope.error().message()); + } + return r_scope.move_as_ok(); +} + td::Result> Client::get_bot_command(JsonValue &&value) { if (value.type() != JsonValue::Type::Object) { return Status::Error(400, "expected an Object"); @@ -6225,15 +6319,41 @@ td::Status Client::process_get_me_query(PromisedQueryPtr &query) { } td::Status Client::process_get_my_commands_query(PromisedQueryPtr &query) { - send_request(make_object(my_id_), - std::make_unique(std::move(query))); + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope(std::move(scope), std::move(query), + [this](object_ptr &&scope, PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code), + std::make_unique(std::move(query))); + }); return Status::OK(); } td::Status Client::process_set_my_commands_query(PromisedQueryPtr &query) { TRY_RESULT(bot_commands, get_bot_commands(query.get())); - send_request(make_object(nullptr, "", std::move(bot_commands)), - std::make_unique(std::move(query))); + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope( + std::move(scope), std::move(query), + [this, bot_commands = std::move(bot_commands)](object_ptr &&scope, + PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code, std::move(bot_commands)), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_delete_my_commands_query(PromisedQueryPtr &query) { + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope(std::move(scope), std::move(query), + [this](object_ptr &&scope, PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code), + std::make_unique(std::move(query))); + }); return Status::OK(); } @@ -6557,7 +6677,7 @@ td::Status Client::process_copy_message_query(PromisedQueryPtr &query) { TRY_RESULT(from_chat_id, get_required_string_arg(query.get(), "from_chat_id")); auto message_id = get_message_id(query.get()); bool replace_caption = query->has_arg("caption"); - td_api::object_ptr caption; + object_ptr caption; if (replace_caption) { TRY_RESULT_ASSIGN(caption, get_caption(query.get())); } @@ -7176,8 +7296,8 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { check_chat(chat_id, 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)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) { + [this, chat_type = get_chat_type(chat_id)](object_ptr &&chat_member, + PromisedQueryPtr query) { answer_query(JsonChatMember(chat_member.get(), chat_type, this), std::move(query)); }); }); @@ -7272,8 +7392,8 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { get_chat_member( chat_id, user_id, std::move(query), - [this, chat_id, user_id, status = std::move(status)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) mutable { + [this, chat_id, user_id, status = std::move(status)](object_ptr &&chat_member, + PromisedQueryPtr query) mutable { if (chat_member->status_->get_id() == td_api::chatMemberStatusAdministrator::ID) { auto administrator = static_cast(chat_member->status_.get()); @@ -7300,7 +7420,7 @@ td::Status Client::process_set_chat_administrator_custom_title_query(PromisedQue get_chat_member( chat_id, user_id, std::move(query), - [this, chat_id, user_id](td_api::object_ptr &&chat_member, PromisedQueryPtr query) { + [this, chat_id, user_id](object_ptr &&chat_member, PromisedQueryPtr query) { if (chat_member->status_->get_id() == td_api::chatMemberStatusCreator::ID) { return fail_query(400, "Bad Request: only creator can edit their custom title", std::move(query)); } @@ -7358,7 +7478,7 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) { get_chat_member( chat_id, user_id, std::move(query), [this, chat_id, user_id, until_date, is_legacy, permissions = std::move(permissions)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) mutable { + object_ptr &&chat_member, PromisedQueryPtr query) mutable { if (is_legacy && chat_member->status_->get_id() == td_api::chatMemberStatusRestricted::ID) { auto restricted = static_cast(chat_member->status_.get()); @@ -7394,18 +7514,18 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { } if (only_if_banned) { - get_chat_member(chat_id, user_id, std::move(query), - [this, chat_id, user_id](td_api::object_ptr &&chat_member, - PromisedQueryPtr query) { - if (chat_member->status_->get_id() != td_api::chatMemberStatusBanned::ID) { - return answer_query(td::JsonTrue(), std::move(query)); - } + get_chat_member( + chat_id, user_id, std::move(query), + [this, chat_id, user_id](object_ptr &&chat_member, PromisedQueryPtr query) { + if (chat_member->status_->get_id() != td_api::chatMemberStatusBanned::ID) { + return answer_query(td::JsonTrue(), std::move(query)); + } - send_request(make_object( - chat_id, td_api::make_object(user_id), - make_object()), - std::make_unique(std::move(query))); - }); + send_request(make_object( + chat_id, td_api::make_object(user_id), + make_object()), + std::make_unique(std::move(query))); + }); } else { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object( diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 40224b5..02b1f4b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -211,6 +211,7 @@ class Client : public WebhookActor::Callback { struct UserInfo; struct ChatInfo; + struct BotCommandScope; enum class AccessRights { Read, ReadMembers, Edit, Write }; @@ -248,6 +249,9 @@ class Client : public WebhookActor::Callback { template void check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQueryPtr query, OnSuccess on_success); + template + void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); + template void check_remote_file_id(td::string file_id, PromisedQueryPtr query, OnSuccess on_success); @@ -330,6 +334,21 @@ class Client : public WebhookActor::Callback { td::Result>> get_inline_query_results(td::JsonValue &&value); + struct BotCommandScope { + object_ptr scope_; + td::string chat_id_; + td::int32 user_id_ = 0; + + explicit BotCommandScope(object_ptr scope, td::string chat_id = td::string(), + td::int32 user_id = 0) + : scope_(std::move(scope)), chat_id_(std::move(chat_id)), user_id_(user_id) { + } + }; + + static td::Result get_bot_command_scope(const Query *query); + + static td::Result get_bot_command_scope(td::JsonValue &&value); + static td::Result> get_bot_command(td::JsonValue &&value); static td::Result>> get_bot_commands(const Query *query); @@ -416,6 +435,7 @@ class Client : public WebhookActor::Callback { Status process_get_me_query(PromisedQueryPtr &query); Status process_get_my_commands_query(PromisedQueryPtr &query); Status process_set_my_commands_query(PromisedQueryPtr &query); + Status process_delete_my_commands_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); Status process_send_message_query(PromisedQueryPtr &query); Status process_send_animation_query(PromisedQueryPtr &query);