diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 50733045a..a3907fc1e 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -297,7 +297,7 @@ userTypeBot can_join_groups:Bool can_read_all_group_messages:Bool is_inline:Bool userTypeUnknown = UserType; -//@description Represents commands supported by a bot @command Text of the bot command @param_description Description of the bot command +//@description Represents a command supported by a bot @command Text of the bot command @param_description Description of the bot command botCommand command:string description:string = BotCommand; //@description Provides information about a bot and its supported commands @param_description Long description shown on the user info page @commands A list of commands supported by the bot @@ -3955,6 +3955,9 @@ resendChangePhoneNumberCode = AuthenticationCodeInfo; //@description Checks the authentication code sent to confirm a new phone number of the user @code Verification code received by SMS, phone call or flash call checkChangePhoneNumberCode code:string = Ok; +//@description Sets the list of commands supported by the bot; for bots only @commands List of the bot commands +setCommands commands:vector = Ok; + //@description Returns all active sessions of the current user getActiveSessions = Sessions; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 458fc7d18..7ed494008 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 399c79990..d5383dfe0 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -1005,6 +1005,42 @@ class UpdateUsernameQuery : public Td::ResultHandler { } }; +class SetBotCommandsQuery : public Td::ResultHandler { + Promise promise_; + vector> commands_; + + public: + explicit SetBotCommandsQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(vector> &&commands) { + commands_ = std::move(commands); + send_query( + G()->net_query_creator().create(telegram_api::bots_setBotCommands(transform(commands_, [](const auto &command) { + return make_tl_object(command.first, command.second); + })))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + bool result = result_ptr.ok(); + if (result) { + td->contacts_manager_->on_set_bot_commands_success(std::move(commands_)); + } else { + LOG(ERROR) << "Set bot commands request failed"; + } + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + promise_.set_error(std::move(status)); + } +}; + class CheckChannelUsernameQuery : public Td::ResultHandler { Promise promise_; ChannelId channel_id_; @@ -5221,6 +5257,66 @@ void ContactsManager::set_username(const string &username, Promise &&promi td_->create_handler(std::move(promise))->send(username); } +void ContactsManager::set_commands(vector> &&commands, Promise &&promise) { + vector> new_commands; + for (auto &command : commands) { + if (command == nullptr) { + return promise.set_error(Status::Error(400, "Command must be non-empty")); + } + if (!clean_input_string(command->command_)) { + return promise.set_error(Status::Error(400, "Command must be encoded in UTF-8")); + } + if (!clean_input_string(command->description_)) { + return promise.set_error(Status::Error(400, "Command description must be encoded in UTF-8")); + } + + const size_t MAX_COMMAND_TEXT_LENGTH = 32; + command->command_ = trim(command->command_); + if (command->command_[0] == '/') { + command->command_ = command->command_.substr(1); + } + if (command->command_.empty()) { + return promise.set_error(Status::Error(400, "Command must be non-empty")); + } + if (utf8_length(command->command_) > MAX_COMMAND_TEXT_LENGTH) { + return promise.set_error( + Status::Error(400, PSLICE() << "Command length must not exceed " << MAX_COMMAND_TEXT_LENGTH)); + } + + const size_t MIN_COMMAND_DESCRIPTION_LENGTH = 3; + const size_t MAX_COMMAND_DESCRIPTION_LENGTH = 256; + command->description_ = trim(command->description_); + auto description_length = utf8_length(command->description_); + if (description_length < MIN_COMMAND_DESCRIPTION_LENGTH) { + return promise.set_error(Status::Error( + 400, PSLICE() << "Command description length must be at least " << MIN_COMMAND_DESCRIPTION_LENGTH)); + } + if (description_length > MAX_COMMAND_DESCRIPTION_LENGTH) { + return promise.set_error(Status::Error( + 400, PSLICE() << "Command description length must not exceed " << MAX_COMMAND_DESCRIPTION_LENGTH)); + } + + new_commands.emplace_back(std::move(command->command_), std::move(command->description_)); + } + + td_->create_handler(std::move(promise))->send(std::move(new_commands)); +} + +void ContactsManager::on_set_bot_commands_success(vector> &&commands) { + auto user_id = get_my_id(); + BotInfo *bot_info = get_bot_info_force(user_id); + if (bot_info == nullptr) { + return; + } + if (bot_info->commands == commands) { + return; + } + bot_info->commands = std::move(commands); + bot_info->is_changed = true; + + update_bot_info(bot_info, user_id, true, false); +} + void ContactsManager::set_chat_description(ChatId chat_id, const string &description, Promise &&promise) { auto new_description = strip_empty_characters(description, MAX_DESCRIPTION_LENGTH); auto c = get_chat(chat_id); diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 7345c7609..3864182d4 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -164,6 +164,7 @@ class ContactsManager : public Actor { void on_get_chat_full(tl_object_ptr &&chat_full, Promise &&promise); void on_update_profile_success(int32 flags, const string &first_name, const string &last_name, const string &about); + void on_set_bot_commands_success(vector> &&commands); void on_update_user_name(UserId user_id, string &&first_name, string &&last_name, string &&username); void on_update_user_phone_number(UserId user_id, string &&phone_number); @@ -330,6 +331,8 @@ class ContactsManager : public Actor { void set_username(const string &username, Promise &&promise); + void set_commands(vector> &&commands, Promise &&promise); + void set_chat_description(ChatId chat_id, const string &description, Promise &&promise); void set_channel_username(ChannelId channel_id, const string &username, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index a7602a6d0..50810e8c4 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6197,6 +6197,12 @@ void Td::on_request(uint64 id, td_api::setUsername &request) { contacts_manager_->set_username(request.username_, std::move(promise)); } +void Td::on_request(uint64 id, td_api::setCommands &request) { + CHECK_IS_BOT(); + CREATE_OK_REQUEST_PROMISE(); + contacts_manager_->set_commands(std::move(request.commands_), std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::setLocation &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index ea5583e08..4d59d6e22 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -781,6 +781,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::setUsername &request); + void on_request(uint64 id, td_api::setCommands &request); + void on_request(uint64 id, const td_api::setLocation &request); void on_request(uint64 id, td_api::setProfilePhoto &request);