Add inlineKeyboardButtonTypeUser.

This commit is contained in:
levlam 2021-11-10 17:14:00 +03:00
parent 6ace4fdf36
commit ae987f2211
8 changed files with 162 additions and 34 deletions

View File

@ -1070,6 +1070,9 @@ inlineKeyboardButtonTypeSwitchInline query:string in_current_chat:Bool = InlineK
//@description A button to buy something. 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 messageInvoice
inlineKeyboardButtonTypeBuy = InlineKeyboardButtonType;
//@description A button to open a chat with a user @user_id User identifier
inlineKeyboardButtonTypeUser user_id:int53 = InlineKeyboardButtonType;
//@description Represents a single button in an inline keyboard @text Text of the button @type Type of the button
inlineKeyboardButton text:string type:InlineKeyboardButtonType = InlineKeyboardButton;

View File

@ -23833,6 +23833,7 @@ void MessagesManager::add_message_dependencies(Dependencies &dependencies, const
add_message_sender_dependencies(dependencies, recent_replier_dialog_id);
}
add_message_content_dependencies(dependencies, m->content.get());
add_reply_markup_dependencies(dependencies, m->reply_markup.get());
}
class MessagesManager::SendMessageLogEvent {

View File

@ -7,6 +7,7 @@
#include "td/telegram/ReplyMarkup.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/Dependencies.h"
#include "td/telegram/Global.h"
#include "td/telegram/LinkManager.h"
#include "td/telegram/misc.h"
@ -90,6 +91,9 @@ static StringBuilder &operator<<(StringBuilder &string_builder, const InlineKeyb
case InlineKeyboardButton::Type::CallbackWithPassword:
string_builder << "CallbackWithPassword";
break;
case InlineKeyboardButton::Type::User:
string_builder << "User " << keyboard_button.user_id.get();
break;
default:
UNREACHABLE();
}
@ -264,9 +268,14 @@ static InlineKeyboardButton get_inline_keyboard_button(
button.id = keyboard_button->button_id_;
button.text = std::move(keyboard_button->text_);
button.data = std::move(keyboard_button->url_);
if ((keyboard_button->flags_ & telegram_api::keyboardButtonUrlAuth::FWD_TEXT_MASK) != 0) {
button.forward_text = std::move(keyboard_button->fwd_text_);
}
button.forward_text = std::move(keyboard_button->fwd_text_);
break;
}
case telegram_api::keyboardButtonUserProfile::ID: {
auto keyboard_button = move_tl_object_as<telegram_api::keyboardButtonUserProfile>(keyboard_button_ptr);
button.type = InlineKeyboardButton::Type::User;
button.text = std::move(keyboard_button->text_);
button.user_id = UserId(keyboard_button->user_id_);
break;
}
default:
@ -434,42 +443,42 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
int32 button_type_id = button->type_->get_id();
switch (button_type_id) {
case td_api::inlineKeyboardButtonTypeUrl::ID: {
current_button.type = InlineKeyboardButton::Type::Url;
auto r_url =
LinkManager::check_link(static_cast<const td_api::inlineKeyboardButtonTypeUrl *>(button->type_.get())->url_);
auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeUrl>(button->type_);
auto r_url = LinkManager::check_link(button_type->url_);
if (r_url.is_error()) {
return Status::Error(400, "Inline keyboard button URL is invalid");
}
current_button.type = InlineKeyboardButton::Type::Url;
current_button.data = r_url.move_as_ok();
if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button URL must be encoded in UTF-8");
}
break;
}
case td_api::inlineKeyboardButtonTypeCallback::ID:
case td_api::inlineKeyboardButtonTypeCallback::ID: {
auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeCallback>(button->type_);
current_button.type = InlineKeyboardButton::Type::Callback;
current_button.data =
std::move(static_cast<td_api::inlineKeyboardButtonTypeCallback *>(button->type_.get())->data_);
current_button.data = std::move(button_type->data_);
break;
}
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_);
auto button_type = move_tl_object_as<td_api::inlineKeyboardButtonTypeSwitchInline>(button->type_);
if (!switch_inline_buttons_allowed) {
const char *button_name =
switch_inline_button->in_current_chat_ ? "switch_inline_query_current_chat" : "switch_inline_query";
button_type->in_current_chat_ ? "switch_inline_query_current_chat" : "switch_inline_query";
return Status::Error(400, PSLICE() << "Can't use " << button_name
<< " in a channel chat, because a user will not be able to use the button "
"without knowing bot's username");
}
current_button.type = switch_inline_button->in_current_chat_
? InlineKeyboardButton::Type::SwitchInlineCurrentDialog
: InlineKeyboardButton::Type::SwitchInline;
current_button.data = std::move(switch_inline_button->query_);
current_button.type = button_type->in_current_chat_ ? InlineKeyboardButton::Type::SwitchInlineCurrentDialog
: InlineKeyboardButton::Type::SwitchInline;
current_button.data = std::move(button_type->query_);
if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button switch inline query must be encoded in UTF-8");
}
@ -479,26 +488,36 @@ static Result<InlineKeyboardButton> get_inline_keyboard_button(tl_object_ptr<td_
current_button.type = InlineKeyboardButton::Type::Buy;
break;
case td_api::inlineKeyboardButtonTypeLoginUrl::ID: {
current_button.type = InlineKeyboardButton::Type::UrlAuth;
auto login_url = td_api::move_object_as<td_api::inlineKeyboardButtonTypeLoginUrl>(button->type_);
auto r_url = LinkManager::check_link(login_url->url_);
auto button_type = td_api::move_object_as<td_api::inlineKeyboardButtonTypeLoginUrl>(button->type_);
auto r_url = LinkManager::check_link(button_type->url_);
if (r_url.is_error()) {
return Status::Error(400, "Inline keyboard button login URL is invalid");
}
current_button.type = InlineKeyboardButton::Type::UrlAuth;
current_button.data = r_url.move_as_ok();
current_button.forward_text = std::move(login_url->forward_text_);
current_button.forward_text = std::move(button_type->forward_text_);
if (!clean_input_string(current_button.data)) {
return Status::Error(400, "Inline keyboard button login URL must be encoded in UTF-8");
}
if (!clean_input_string(current_button.forward_text)) {
return Status::Error(400, "Inline keyboard button forward text must be encoded in UTF-8");
}
current_button.id = login_url->id_;
if (current_button.id == 0 || current_button.id == std::numeric_limits<int64>::min()) {
current_button.id = button_type->id_;
if (current_button.id == std::numeric_limits<int64>::min() ||
!UserId(current_button.id >= 0 ? current_button.id : -current_button.id).is_valid()) {
return Status::Error(400, "Invalid bot_user_id specified");
}
break;
}
case td_api::inlineKeyboardButtonTypeUser::ID: {
auto button_type = td_api::move_object_as<td_api::inlineKeyboardButtonTypeUser>(button->type_);
current_button.type = InlineKeyboardButton::Type::User;
current_button.user_id = UserId(button_type->user_id_);
if (!current_button.user_id.is_valid()) {
return Status::Error(400, "Invalid user_id specified");
}
break;
}
default:
UNREACHABLE();
}
@ -683,6 +702,14 @@ static tl_object_ptr<telegram_api::KeyboardButton> get_inline_keyboard_button(
case InlineKeyboardButton::Type::CallbackWithPassword:
UNREACHABLE();
break;
case InlineKeyboardButton::Type::User: {
auto input_user = G()->td().get_actor_unsafe()->contacts_manager_->get_input_user(keyboard_button.user_id);
if (input_user == nullptr) {
LOG(ERROR) << "Failed to get InputUser for " << keyboard_button.user_id;
input_user = make_tl_object<telegram_api::inputUserEmpty>();
}
return make_tl_object<telegram_api::inputKeyboardButtonUserProfile>(keyboard_button.text, std::move(input_user));
}
default:
UNREACHABLE();
return nullptr;
@ -796,6 +823,11 @@ static tl_object_ptr<td_api::inlineKeyboardButton> get_inline_keyboard_button_ob
case InlineKeyboardButton::Type::CallbackWithPassword:
type = make_tl_object<td_api::inlineKeyboardButtonTypeCallbackWithPassword>(keyboard_button.data);
break;
case InlineKeyboardButton::Type::User:
type = make_tl_object<td_api::inlineKeyboardButtonTypeUser>(
G()->td().get_actor_unsafe()->contacts_manager_->get_user_id_object(keyboard_button.user_id,
"get_inline_keyboard_button_object"));
break;
default:
UNREACHABLE();
return nullptr;
@ -860,4 +892,17 @@ tl_object_ptr<td_api::ReplyMarkup> get_reply_markup_object(const unique_ptr<Repl
return reply_markup->get_reply_markup_object();
}
void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup) {
if (reply_markup == nullptr) {
return;
}
for (auto &row : reply_markup->inline_keyboard) {
for (auto &button : row) {
if (button.user_id.is_valid()) {
dependencies.user_ids.insert(button.user_id);
}
}
}
}
} // namespace td

View File

@ -8,6 +8,7 @@
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
@ -15,6 +16,8 @@
namespace td {
struct Dependencies;
struct KeyboardButton {
// append only
enum class Type : int32 {
@ -39,10 +42,12 @@ struct InlineKeyboardButton {
SwitchInlineCurrentDialog,
Buy,
UrlAuth,
CallbackWithPassword
CallbackWithPassword,
User
};
Type type;
int64 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id
int64 id = 0; // UrlAuth only, button_id or (2 * request_write_access - 1) * bot_user_id
UserId user_id; // User only
string text;
string forward_text; // UrlAuth only
string data;
@ -85,4 +90,6 @@ tl_object_ptr<telegram_api::ReplyMarkup> get_input_reply_markup(const unique_ptr
tl_object_ptr<td_api::ReplyMarkup> get_reply_markup_object(const unique_ptr<ReplyMarkup> &reply_markup);
void add_reply_markup_dependencies(Dependencies &dependencies, const ReplyMarkup *reply_markup);
} // namespace td

View File

@ -15,40 +15,91 @@ namespace td {
template <class StorerT>
void store(KeyboardButton button, StorerT &storer) {
BEGIN_STORE_FLAGS();
END_STORE_FLAGS();
store(button.type, storer);
store(button.text, storer);
}
template <class ParserT>
void parse(KeyboardButton &button, ParserT &parser) {
if (parser.version() >= static_cast<int32>(Version::AddKeyboardButtonFlags)) {
BEGIN_PARSE_FLAGS();
END_PARSE_FLAGS();
}
parse(button.type, parser);
parse(button.text, parser);
}
template <class StorerT>
void store(InlineKeyboardButton button, StorerT &storer) {
bool has_id = button.id != 0;
bool has_user_id = button.user_id.is_valid();
bool has_forward_text = !button.forward_text.empty();
bool has_data = !button.data.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_id);
STORE_FLAG(has_user_id);
STORE_FLAG(has_forward_text);
STORE_FLAG(has_data);
END_STORE_FLAGS();
store(button.type, storer);
if (button.type == InlineKeyboardButton::Type::UrlAuth) {
if (has_id) {
store(button.id, storer);
}
if (has_user_id) {
store(button.user_id, storer);
}
store(button.text, storer);
store(button.data, storer);
if (has_forward_text) {
store(button.forward_text, storer);
}
if (has_data) {
store(button.data, storer);
}
}
template <class ParserT>
void parse(InlineKeyboardButton &button, ParserT &parser) {
parse(button.type, parser);
if (button.type == InlineKeyboardButton::Type::UrlAuth) {
if (parser.version() >= static_cast<int32>(Version::Support64BitIds)) {
if (parser.version() >= static_cast<int32>(Version::AddKeyboardButtonFlags)) {
bool has_id;
bool has_user_id;
bool has_forward_text;
bool has_data;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_id);
PARSE_FLAG(has_user_id);
PARSE_FLAG(has_forward_text);
PARSE_FLAG(has_data);
END_PARSE_FLAGS();
parse(button.type, parser);
if (has_id) {
parse(button.id, parser);
} else {
int32 old_id;
parse(old_id, parser);
button.id = old_id;
}
if (has_user_id) {
parse(button.user_id, parser);
}
parse(button.text, parser);
if (has_forward_text) {
parse(button.forward_text, parser);
}
if (has_data) {
parse(button.data, parser);
}
} else {
parse(button.type, parser);
if (button.type == InlineKeyboardButton::Type::UrlAuth) {
if (parser.version() >= static_cast<int32>(Version::Support64BitIds)) {
parse(button.id, parser);
} else {
int32 old_id;
parse(old_id, parser);
button.id = old_id;
}
}
parse(button.text, parser);
parse(button.data, parser);
}
parse(button.text, parser);
parse(button.data, parser);
}
template <class StorerT>

View File

@ -536,6 +536,24 @@ bool UpdatesManager::is_acceptable_message_entities(
return true;
}
bool UpdatesManager::is_acceptable_reply_markup(const tl_object_ptr<telegram_api::ReplyMarkup> &reply_markup) const {
if (reply_markup == nullptr || reply_markup->get_id() != telegram_api::replyInlineMarkup::ID) {
return true;
}
for (const auto &row : static_cast<const telegram_api::replyInlineMarkup *>(reply_markup.get())->rows_) {
for (const auto &button : row->buttons_) {
if (button->get_id() == telegram_api::keyboardButtonUserProfile::ID) {
auto user_profile_button = static_cast<const telegram_api::keyboardButtonUserProfile *>(button.get());
UserId user_id(user_profile_button->user_id_);
if (!is_acceptable_user(user_id) || !td_->contacts_manager_->have_input_user(user_id)) {
return false;
}
}
}
}
return true;
}
bool UpdatesManager::is_acceptable_message_reply_header(
const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const {
if (header == nullptr) {

View File

@ -356,6 +356,8 @@ class UpdatesManager final : public Actor {
bool is_acceptable_message_entities(const vector<tl_object_ptr<telegram_api::MessageEntity>> &message_entities) const;
bool is_acceptable_reply_markup(const tl_object_ptr<telegram_api::ReplyMarkup> &reply_markup) const;
bool is_acceptable_message_reply_header(
const telegram_api::object_ptr<telegram_api::messageReplyHeader> &header) const;

View File

@ -48,6 +48,7 @@ enum class Version : int32 {
RemovePhotoVolumeAndLocalId,
Support64BitIds,
AddInviteLinksRequiringApproval,
AddKeyboardButtonFlags, // 35
Next
};