Add BotCommandScope to setCommands.

This commit is contained in:
levlam 2021-06-19 04:00:23 +03:00
parent 16f52b59ab
commit 62a543cb35
7 changed files with 231 additions and 30 deletions

View File

@ -278,6 +278,7 @@ set(TDLIB_SOURCE
td/telegram/AutoDownloadSettings.cpp
td/telegram/BackgroundManager.cpp
td/telegram/BackgroundType.cpp
td/telegram/BotCommandScope.cpp
td/telegram/CallActor.cpp
td/telegram/CallDiscardReason.cpp
td/telegram/CallManager.cpp
@ -443,6 +444,7 @@ set(TDLIB_SOURCE
td/telegram/BackgroundId.h
td/telegram/BackgroundManager.h
td/telegram/BackgroundType.h
td/telegram/BotCommandScope.h
td/telegram/CallActor.h
td/telegram/CallDiscardReason.h
td/telegram/CallId.h

View File

@ -3469,6 +3469,30 @@ vectorPathCommandLine end_point:point = VectorPathCommand;
vectorPathCommandCubicBezierCurve start_control_point:point end_control_point:point end_point:point = VectorPathCommand;
//@class BotCommandScope @description Represents the scope to which bot commands are applied
//@description A scope covering all users
botCommandScopeDefault = BotCommandScope;
//@description A scope covering all private chats
botCommandScopeAllPrivateChats = BotCommandScope;
//@description A scope covering all group and supergroup chats
botCommandScopeAllGroupChats = BotCommandScope;
//@description A scope covering all group and supergroup chat administrators
botCommandScopeAllChatAdministrators = BotCommandScope;
//@description A scope covering all members of a chat @chat_id Chat identifier
botCommandScopeChat chat_id:int53 = BotCommandScope;
//@description A scope covering all administrators of a chat @chat_id Chat identifier
botCommandScopeChatAdministrators chat_id:int53 = BotCommandScope;
//@description A scope covering a member of a chat @chat_id Chat identifier @user_id User identifier
botCommandScopeChatMember chat_id:int53 user_id:int32 = BotCommandScope;
//@class Update @description Contains notifications about data changes
//@description The user authorization state has changed @authorization_state New authorization state
@ -4990,8 +5014,10 @@ 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's commands
setCommands commands:vector<botCommand> = Ok;
//@description Sets the list of commands supported by the bot for the given user scope and language; for bots only @scope The scope to which the commands are applied
//@language_code A two-letter ISO 639-1 country code. If empty, the commands will be applied to all users from the given scope, for which language there are no dedicated commands
//@commands List of the bot's commands
setCommands scope:BotCommandScope language_code:string commands:vector<botCommand> = Ok;
//@description Returns all active sessions of the current user

View File

@ -0,0 +1,136 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/BotCommandScope.h"
#include "td/telegram/AuthManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/Td.h"
namespace td {
BotCommandScope::BotCommandScope(Type type, DialogId dialog_id, UserId user_id)
: type_(type), dialog_id_(dialog_id), user_id_(user_id) {
}
Result<BotCommandScope> BotCommandScope::get_bot_command_scope(Td *td,
td_api::object_ptr<td_api::BotCommandScope> scope_ptr) {
if (scope_ptr == nullptr) {
return BotCommandScope(Type::Default);
}
CHECK(td->auth_manager_->is_bot());
Type type;
DialogId dialog_id;
UserId user_id;
switch (scope_ptr->get_id()) {
case td_api::botCommandScopeDefault::ID:
return BotCommandScope(Type::Default);
case td_api::botCommandScopeAllPrivateChats::ID:
return BotCommandScope(Type::AllUsers);
case td_api::botCommandScopeAllGroupChats::ID:
return BotCommandScope(Type::AllChats);
case td_api::botCommandScopeAllChatAdministrators::ID:
return BotCommandScope(Type::AllChatAdministrators);
case td_api::botCommandScopeChat::ID: {
auto scope = td_api::move_object_as<td_api::botCommandScopeChat>(scope_ptr);
type = Type::Dialog;
dialog_id = DialogId(scope->chat_id_);
break;
}
case td_api::botCommandScopeChatAdministrators::ID: {
auto scope = td_api::move_object_as<td_api::botCommandScopeChatAdministrators>(scope_ptr);
type = Type::DialogAdministrators;
dialog_id = DialogId(scope->chat_id_);
break;
}
case td_api::botCommandScopeChatMember::ID: {
auto scope = td_api::move_object_as<td_api::botCommandScopeChatMember>(scope_ptr);
type = Type::DialogParticipant;
dialog_id = DialogId(scope->chat_id_);
user_id = UserId(scope->user_id_);
if (!user_id.is_valid()) {
return Status::Error(400, "User not found");
}
break;
}
default:
UNREACHABLE();
return BotCommandScope(Type::Default);
}
if (!td->messages_manager_->have_dialog_force(dialog_id, "get_bot_command_scope")) {
return Status::Error(400, "Chat not found");
}
if (!td->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
return Status::Error(400, "Can't access the chat");
}
switch (dialog_id.get_type()) {
case DialogType::User:
if (type != Type::Dialog) {
return Status::Error(400, "Can't use specified scope in private chats");
}
break;
case DialogType::Chat:
// ok
break;
case DialogType::Channel:
if (td->contacts_manager_->get_channel_type(dialog_id.get_channel_id()) !=
ContactsManager::ChannelType::Megagroup) {
return Status::Error(400, "Can't change commands in channel chats");
}
break;
case DialogType::SecretChat:
default:
return Status::Error(400, "Can't access the chat");
}
return BotCommandScope(type, dialog_id, user_id);
}
bool BotCommandScope::have_input_bot_command_scope(const Td *td) const {
if (dialog_id_.is_valid() && !td->messages_manager_->have_input_peer(dialog_id_, AccessRights::Read)) {
return false;
}
if (user_id_.is_valid() && !td->contacts_manager_->have_input_user(user_id_)) {
return false;
}
return true;
}
telegram_api::object_ptr<telegram_api::BotCommandScope> BotCommandScope::get_input_bot_command_scope(
const Td *td) const {
auto input_peer =
dialog_id_.is_valid() ? td->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read) : nullptr;
auto input_user = user_id_.is_valid() ? td->contacts_manager_->get_input_user(user_id_) : nullptr;
switch (type_) {
case Type::Default:
return telegram_api::make_object<telegram_api::botCommandScopeDefault>();
case Type::AllUsers:
return telegram_api::make_object<telegram_api::botCommandScopeUsers>();
case Type::AllChats:
return telegram_api::make_object<telegram_api::botCommandScopeChats>();
case Type::AllChatAdministrators:
return telegram_api::make_object<telegram_api::botCommandScopeChatAdmins>();
case Type::Dialog:
CHECK(input_peer != nullptr);
return telegram_api::make_object<telegram_api::botCommandScopePeer>(std::move(input_peer));
case Type::DialogAdministrators:
CHECK(input_peer != nullptr);
return telegram_api::make_object<telegram_api::botCommandScopePeerAdmins>(std::move(input_peer));
case Type::DialogParticipant:
CHECK(input_peer != nullptr);
CHECK(input_user != nullptr);
return telegram_api::make_object<telegram_api::botCommandScopePeerUser>(std::move(input_peer),
std::move(input_user));
default:
UNREACHABLE();
return nullptr;
}
}
} // namespace td

View File

@ -0,0 +1,44 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
namespace td {
class Td;
class BotCommandScope {
enum class Type : int32 {
Default,
AllUsers,
AllChats,
AllChatAdministrators,
Dialog,
DialogAdministrators,
DialogParticipant
};
Type type_ = Type::Default;
DialogId dialog_id_;
UserId user_id_;
explicit BotCommandScope(Type type, DialogId dialog_id = DialogId(), UserId user_id = UserId());
public:
static Result<BotCommandScope> get_bot_command_scope(Td *td, td_api::object_ptr<td_api::BotCommandScope> scope_ptr);
bool have_input_bot_command_scope(const Td *td) const;
telegram_api::object_ptr<telegram_api::BotCommandScope> get_input_bot_command_scope(const Td *td) const;
};
} // namespace td

View File

@ -11,6 +11,7 @@
#include "td/telegram/telegram_api.hpp"
#include "td/telegram/AuthManager.h"
#include "td/telegram/BotCommandScope.h"
#include "td/telegram/ConfigManager.h"
#include "td/telegram/ConfigShared.h"
#include "td/telegram/Dependencies.h"
@ -981,16 +982,14 @@ class UpdateUsernameQuery : public Td::ResultHandler {
class SetBotCommandsQuery : public Td::ResultHandler {
Promise<Unit> promise_;
vector<std::pair<string, string>> commands_;
public:
explicit SetBotCommandsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(vector<std::pair<string, string>> &&commands) {
commands_ = std::move(commands);
void send(BotCommandScope scope, const string &language_code, vector<std::pair<string, string>> &&commands) {
send_query(G()->net_query_creator().create(telegram_api::bots_setBotCommands(
make_tl_object<telegram_api::botCommandScopeDefault>(), string(), transform(commands_, [](const auto &command) {
scope.get_input_bot_command_scope(td), language_code, transform(commands, [](const auto &command) {
return make_tl_object<telegram_api::botCommand>(command.first, command.second);
}))));
}
@ -1001,10 +1000,7 @@ class SetBotCommandsQuery : public Td::ResultHandler {
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 {
if (!result_ptr.ok()) {
LOG(ERROR) << "Set bot commands request failed";
}
promise_.set_value(Unit());
@ -6255,7 +6251,18 @@ void ContactsManager::set_username(const string &username, Promise<Unit> &&promi
td_->create_handler<UpdateUsernameQuery>(std::move(promise))->send(username);
}
void ContactsManager::set_commands(vector<td_api::object_ptr<td_api::botCommand>> &&commands, Promise<Unit> &&promise) {
void ContactsManager::set_commands(td_api::object_ptr<td_api::BotCommandScope> &&scope_ptr, string &&language_code,
vector<td_api::object_ptr<td_api::botCommand>> &&commands, Promise<Unit> &&promise) {
TRY_RESULT_PROMISE(promise, scope, BotCommandScope::get_bot_command_scope(td_, std::move(scope_ptr)));
if (!language_code.empty() && (language_code.size() != 2 || language_code[0] < 'a' || language_code[0] > 'z' ||
language_code[1] < 'a' || language_code[1] > 'z')) {
return promise.set_error(Status::Error(400, "Invalid language code specified"));
}
if (!scope.have_input_bot_command_scope(td_)) {
return promise.set_error(Status::Error(400, "Invalid scope specified"));
}
vector<std::pair<string, string>> new_commands;
for (auto &command : commands) {
if (command == nullptr) {
@ -6297,22 +6304,7 @@ void ContactsManager::set_commands(vector<td_api::object_ptr<td_api::botCommand>
new_commands.emplace_back(std::move(command->command_), std::move(command->description_));
}
td_->create_handler<SetBotCommandsQuery>(std::move(promise))->send(std::move(new_commands));
}
void ContactsManager::on_set_bot_commands_success(vector<std::pair<string, string>> &&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);
td_->create_handler<SetBotCommandsQuery>(std::move(promise))->send(scope, language_code, std::move(new_commands));
}
void ContactsManager::set_chat_description(ChatId chat_id, const string &description, Promise<Unit> &&promise) {

View File

@ -160,7 +160,6 @@ class ContactsManager : public Actor {
void on_get_channel_full_failed(ChannelId channel_id);
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<std::pair<string, string>> &&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);
@ -329,7 +328,8 @@ class ContactsManager : public Actor {
void set_username(const string &username, Promise<Unit> &&promise);
void set_commands(vector<td_api::object_ptr<td_api::botCommand>> &&commands, Promise<Unit> &&promise);
void set_commands(td_api::object_ptr<td_api::BotCommandScope> &&scope_ptr, string &&language_code,
vector<td_api::object_ptr<td_api::botCommand>> &&commands, Promise<Unit> &&promise);
void set_chat_description(ChatId chat_id, const string &description, Promise<Unit> &&promise);

View File

@ -6874,7 +6874,8 @@ void Td::on_request(uint64 id, td_api::setUsername &request) {
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));
contacts_manager_->set_commands(std::move(request.scope_), std::move(request.language_code_),
std::move(request.commands_), std::move(promise));
}
void Td::on_request(uint64 id, const td_api::setLocation &request) {