Add CallbackWithPassword buttons support.

GitOrigin-RevId: 99e79f8975d50a9a87183dd78f2641711bbad28d
This commit is contained in:
levlam 2020-08-18 09:32:37 +03:00
parent a9fa751689
commit 3c83aae127
8 changed files with 98 additions and 15 deletions

View File

@ -907,10 +907,13 @@ inlineKeyboardButtonTypeUrl url:string = InlineKeyboardButtonType;
//@description A button that opens a specified URL and automatically logs in in current user if they allowed to do that @url An HTTP URL to open @id Unique button identifier @forward_text If non-empty, new text of the button in forwarded messages
inlineKeyboardButtonTypeLoginUrl url:string id:int32 forward_text:string = InlineKeyboardButtonType;
//@description A button that sends a special callback query to a bot @data Data to be sent to the bot via a callback query
//@description A button that sends a callback query to a bot @data Data to be sent to the bot via a callback query
inlineKeyboardButtonTypeCallback data:bytes = InlineKeyboardButtonType;
//@description A button with a game that sends a special callback query to a bot. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageGame
//@description A button that asks for password of the current user and then sends a callback query to a bot @data Data to be sent to the bot via a callback query
inlineKeyboardButtonTypeCallbackWithPassword data:bytes = InlineKeyboardButtonType;
//@description A button with a game that sends a callback query to a bot. This button must be in the first column and row of the keyboard and can be attached only to a message with content of the type messageGame
inlineKeyboardButtonTypeCallbackGame = InlineKeyboardButtonType;
//@description A button that forces an inline query to the bot to be inserted in the input field @query Inline query to be sent to the bot @in_current_chat True, if the inline query should be sent from the current chat
@ -2131,10 +2134,13 @@ inlineQueryResults inline_query_id:int64 next_offset:string results:vector<Inlin
//@class CallbackQueryPayload @description Represents a payload of a callback query
//@description The payload from a general callback button @data Data that was attached to the callback button
//@description The payload for a general callback button @data Data that was attached to the callback button
callbackQueryPayloadData data:bytes = CallbackQueryPayload;
//@description The payload from a game callback button @game_short_name A short name of the game that was attached to the callback button
//@description The payload for a callback button requiring password @password The password for the current user@data Data that was attached to the callback button
callbackQueryPayloadDataWithPassword password:string data:bytes = CallbackQueryPayload;
//@description The payload for a game callback button @game_short_name A short name of the game that was attached to the callback button
callbackQueryPayloadGame game_short_name:string = CallbackQueryPayload;

Binary file not shown.

View File

@ -18,6 +18,7 @@
#include "td/telegram/Global.h"
#include "td/telegram/InlineQueriesManager.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/PasswordManager.h"
#include "td/telegram/Td.h"
#include "td/utils/common.h"
@ -38,7 +39,7 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
}
void send(DialogId dialog_id, MessageId message_id, const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
int64 result_id) {
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id) {
result_id_ = result_id;
dialog_id_ = dialog_id;
message_id_ = message_id;
@ -54,6 +55,12 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
flags = telegram_api::messages_getBotCallbackAnswer::DATA_MASK;
data = BufferSlice(static_cast<const td_api::callbackQueryPayloadData *>(payload.get())->data_);
break;
case td_api::callbackQueryPayloadDataWithPassword::ID:
CHECK(password != nullptr);
flags = telegram_api::messages_getBotCallbackAnswer::DATA_MASK |
telegram_api::messages_getBotCallbackAnswer::PASSWORD_MASK;
data = BufferSlice(static_cast<const td_api::callbackQueryPayloadDataWithPassword *>(payload.get())->data_);
break;
case td_api::callbackQueryPayloadGame::ID:
flags = telegram_api::messages_getBotCallbackAnswer::GAME_MASK;
break;
@ -63,7 +70,7 @@ class GetBotCallbackAnswerQuery : public Td::ResultHandler {
auto net_query = G()->net_query_creator().create(telegram_api::messages_getBotCallbackAnswer(
flags, false /*ignored*/, std::move(input_peer), message_id.get_server_message_id().get(), std::move(data),
nullptr));
std::move(password)));
net_query->need_resend_on_503_ = false;
send_query(std::move(net_query));
}
@ -221,7 +228,7 @@ void CallbackQueriesManager::on_new_inline_query(
}
int64 CallbackQueriesManager::send_callback_query(FullMessageId full_message_id,
const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
Promise<Unit> &&promise) {
if (td_->auth_manager_->is_bot()) {
promise.set_error(Status::Error(5, "Bot can't send callback queries to other bot"));
@ -259,12 +266,44 @@ int64 CallbackQueriesManager::send_callback_query(FullMessageId full_message_id,
} while (callback_query_answers_.find(result_id) != callback_query_answers_.end());
callback_query_answers_[result_id]; // reserve place for result
td_->create_handler<GetBotCallbackAnswerQuery>(std::move(promise))
->send(dialog_id, full_message_id.get_message_id(), payload, result_id);
if (payload->get_id() == td_api::callbackQueryPayloadDataWithPassword::ID) {
auto password = static_cast<const td_api::callbackQueryPayloadDataWithPassword *>(payload.get())->password_;
send_closure(td_->password_manager_, &PasswordManager::get_input_check_password_srp, std::move(password),
PromiseCreator::lambda(
[this, full_message_id, payload = std::move(payload), result_id, promise = std::move(promise)](
Result<tl_object_ptr<telegram_api::InputCheckPasswordSRP>> result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
if (G()->close_flag()) {
return promise.set_error(Status::Error(500, "Request aborted"));
}
send_get_callback_answer_query(full_message_id, std::move(payload), result.move_as_ok(),
result_id, std::move(promise));
}));
} else {
send_get_callback_answer_query(full_message_id, std::move(payload), nullptr, result_id, std::move(promise));
}
return result_id;
}
void CallbackQueriesManager::send_get_callback_answer_query(
FullMessageId full_message_id, tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id, Promise<Unit> &&promise) {
auto dialog_id = full_message_id.get_dialog_id();
if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
if (!td_->messages_manager_->have_message_force(full_message_id, "send_callback_query")) {
return promise.set_error(Status::Error(5, "Message not found"));
}
td_->create_handler<GetBotCallbackAnswerQuery>(std::move(promise))
->send(dialog_id, full_message_id.get_message_id(), payload, std::move(password), result_id);
}
void CallbackQueriesManager::on_get_callback_query_answer(
int64 result_id, tl_object_ptr<telegram_api::messages_botCallbackAnswer> &&answer) {
LOG(INFO) << "Receive answer for callback query " << result_id;

View File

@ -39,7 +39,7 @@ class CallbackQueriesManager {
tl_object_ptr<telegram_api::inputBotInlineMessageID> &&inline_message_id, BufferSlice &&data,
int64 chat_instance, string &&game_short_name);
int64 send_callback_query(FullMessageId full_message_id, const tl_object_ptr<td_api::CallbackQueryPayload> &payload,
int64 send_callback_query(FullMessageId full_message_id, tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
Promise<Unit> &&promise);
void on_get_callback_query_answer(int64 result_id, tl_object_ptr<telegram_api::messages_botCallbackAnswer> &&answer);
@ -60,6 +60,11 @@ class CallbackQueriesManager {
tl_object_ptr<td_api::CallbackQueryPayload> get_query_payload(int32 flags, BufferSlice &&data,
string &&game_short_name);
void send_get_callback_answer_query(FullMessageId full_message_id,
tl_object_ptr<td_api::CallbackQueryPayload> &&payload,
tl_object_ptr<telegram_api::InputCheckPasswordSRP> &&password, int64 result_id,
Promise<Unit> &&promise);
std::unordered_map<int64, CallbackQueryAnswer> callback_query_answers_;
Td *td_;

View File

@ -84,6 +84,9 @@ static StringBuilder &operator<<(StringBuilder &string_builder, const InlineKeyb
case InlineKeyboardButton::Type::UrlAuth:
string_builder << "UrlAuth, id = " << keyboard_button.id;
break;
case InlineKeyboardButton::Type::CallbackWithPassword:
string_builder << "CallbackWithPassword";
break;
default:
UNREACHABLE();
}
@ -219,7 +222,8 @@ static InlineKeyboardButton get_inline_keyboard_button(
}
case telegram_api::keyboardButtonCallback::ID: {
auto keyboard_button = move_tl_object_as<telegram_api::keyboardButtonCallback>(keyboard_button_ptr);
button.type = InlineKeyboardButton::Type::Callback;
button.type = keyboard_button->requires_password_ ? InlineKeyboardButton::Type::CallbackWithPassword
: InlineKeyboardButton::Type::Callback;
button.text = std::move(keyboard_button->text_);
button.data = keyboard_button->data_.as_slice().str();
break;
@ -435,6 +439,8 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
case td_api::inlineKeyboardButtonTypeCallbackGame::ID:
current_button.type = InlineKeyboardButton::Type::CallbackGame;
break;
case td_api::inlineKeyboardButtonTypeCallbackWithPassword::ID:
return Status::Error(400, "Can't use CallbackWithPassword inline button");
case td_api::inlineKeyboardButtonTypeSwitchInline::ID: {
auto switch_inline_button = move_tl_object_as<td_api::inlineKeyboardButtonTypeSwitchInline>(button->type_);
if (!switch_inline_buttons_allowed) {
@ -653,6 +659,9 @@ static tl_object_ptr<telegram_api::KeyboardButton> get_inline_keyboard_button(
keyboard_button.forward_text,
keyboard_button.data, std::move(input_user));
}
case InlineKeyboardButton::Type::CallbackWithPassword:
UNREACHABLE();
break;
default:
UNREACHABLE();
return nullptr;
@ -762,6 +771,9 @@ static tl_object_ptr<td_api::inlineKeyboardButton> get_inline_keyboard_button_ob
type = make_tl_object<td_api::inlineKeyboardButtonTypeLoginUrl>(keyboard_button.data, keyboard_button.id,
keyboard_button.forward_text);
break;
case InlineKeyboardButton::Type::CallbackWithPassword:
type = make_tl_object<td_api::inlineKeyboardButtonTypeCallbackWithPassword>(keyboard_button.data);
break;
default:
UNREACHABLE();
return nullptr;

View File

@ -31,7 +31,16 @@ struct KeyboardButton {
struct InlineKeyboardButton {
// append only
enum class Type : int32 { Url, Callback, CallbackGame, SwitchInline, SwitchInlineCurrentDialog, Buy, UrlAuth };
enum class Type : int32 {
Url,
Callback,
CallbackGame,
SwitchInline,
SwitchInlineCurrentDialog,
Buy,
UrlAuth,
CallbackWithPassword
};
Type type;
int32 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id
string text;

View File

@ -2901,7 +2901,8 @@ class GetCallbackQueryAnswerRequest : public RequestOnceActor {
int64 result_id_;
void do_run(Promise<Unit> &&promise) override {
result_id_ = td->callback_queries_manager_->send_callback_query(full_message_id_, payload_, std::move(promise));
result_id_ =
td->callback_queries_manager_->send_callback_query(full_message_id_, std::move(payload_), std::move(promise));
}
void do_send_result() override {

View File

@ -3100,7 +3100,7 @@ class CliClient final : public Actor {
auto chat = as_chat_id(chat_id);
send_request(td_api::make_object<td_api::sendInlineQueryResultMessage>(
chat, 0, default_message_send_options(), to_integer<int64>(query_id), result_id, op == "siqrh"));
} else if (op == "gcqr") {
} else if (op == "gcqa") {
string chat_id;
string message_id;
string data;
@ -3108,7 +3108,18 @@ class CliClient final : public Actor {
std::tie(message_id, data) = split(args);
send_request(td_api::make_object<td_api::getCallbackQueryAnswer>(
as_chat_id(chat_id), as_message_id(message_id), td_api::make_object<td_api::callbackQueryPayloadData>(data)));
} else if (op == "gcgqr") {
} else if (op == "gcpqa") {
string chat_id;
string message_id;
string password;
string data;
std::tie(chat_id, args) = split(args);
std::tie(message_id, args) = split(args);
std::tie(password, data) = split(args);
send_request(td_api::make_object<td_api::getCallbackQueryAnswer>(
as_chat_id(chat_id), as_message_id(message_id),
td_api::make_object<td_api::callbackQueryPayloadDataWithPassword>(password, data)));
} else if (op == "gcgqa") {
string chat_id;
string message_id;
std::tie(chat_id, message_id) = split(args);