Add internalLinkTypeAttachMenuBot.

This commit is contained in:
levlam 2022-04-01 14:00:34 +03:00
parent 2992d1e5e4
commit 7364334ebe
6 changed files with 123 additions and 7 deletions

View File

@ -881,7 +881,7 @@ messageCalendar total_count:int32 days:vector<messageCalendarDay> = MessageCalen
//@message_id Message identifier; unique for the chat to which the sponsored message belongs among both ordinary and sponsored messages
//@sponsor_chat_id Sponsor chat identifier; 0 if the sponsor chat is accessible through an invite link
//@sponsor_chat_info Information about the sponsor chat; may be null unless sponsor_chat_id == 0
//@link An internal link to be opened when the sponsored message is clicked; may be null. If null, the sponsor chat needs to be opened instead
//@link An internal link to be opened when the sponsored message is clicked; may be null if the sponsor chat needs to be opened instead
//@content Content of the message. Currently, can be only of the type messageText
sponsoredMessage message_id:int53 sponsor_chat_id:int53 sponsor_chat_info:chatInviteLinkInfo link:InternalLinkType content:MessageContent = SponsoredMessage;
@ -3335,6 +3335,13 @@ chatReportReasonCustom = ChatReportReason;
//@description The link is a link to the active sessions section of the app. Use getActiveSessions to handle the link
internalLinkTypeActiveSessions = InternalLinkType;
//@description The link is a link to an attach menu bot to be opened in the specified chat. Process given chat_link to open corresponding chat.
//-Then call searchPublicChat with the given bot username, check that the user is a bot and can be added to attach menu. Then use getAttachMenuBot to receive information about the bot.
//-If the bot isn't added to attach menu, then user needs to confirm adding the bot to attach menu. If user confirms adding, then use toggleBotIsAddedToAttachMenu to add it.
//-If attach menu bots can't be used in the current chat, show an error to the user. If the bot is added to attach menu, then use openWebApp with the given url
//@chat_link An internal link pointing to a chat; may be null if the current chat needs to be kept @bot_username Username of the bot @url URL to be passed to openWebApp
internalLinkTypeAttachMenuBot chat_link:InternalLinkType bot_username:string url:string = InternalLinkType;
//@description The link contains an authentication code. Call checkAuthenticationCode with the code if the current authorization state is authorizationStateWaitCode @code The authentication code
internalLinkTypeAuthenticationCode code:string = InternalLinkType;
@ -4872,7 +4879,8 @@ getWebAppUrl bot_user_id:int53 url:string theme:themeParameters = HttpUrl;
//@bot_user_id Identifier of the target bot @button_text Text of the keyboardButtonTypeWebApp button, which opened the web app @data Received data
sendWebAppData bot_user_id:int53 button_text:string data:string = Ok;
//@description Informs TDLib that a web app is being opened from attach menu, bot menu, internalLinkTypeAttachMenuBot links, or an inlineKeyboardButtonTypeWebApp button
//@description Informs TDLib that a web app is being opened from attach menu, bot menu, an internalLinkTypeAttachMenuBot link, or an inlineKeyboardButtonTypeWebApp button.
//-For each bot, a confirmation alert about data sent to the bot must be shown once
//@chat_id Identifier of the chat in which the web app is opened. Web apps can be opened only in private chats for now
//@bot_user_id Identifier of the bot, providing the web app
//@url The URL from the inlineKeyboardButtonTypeWebApp button or the internalLinkTypeAttachMenuBot link, or an empty string otherwise

View File

@ -108,6 +108,25 @@ class LinkManager::InternalLinkActiveSessions final : public InternalLink {
}
};
class LinkManager::InternalLinkAttachMenuBot final : public InternalLink {
unique_ptr<InternalLink> dialog_link_;
string bot_username_;
string url_;
td_api::object_ptr<td_api::InternalLinkType> get_internal_link_type_object() const final {
return td_api::make_object<td_api::internalLinkTypeAttachMenuBot>(
dialog_link_ == nullptr ? nullptr : dialog_link_->get_internal_link_type_object(), bot_username_, url_);
}
public:
InternalLinkAttachMenuBot(unique_ptr<InternalLink> dialog_link, string bot_username, Slice start_parameter)
: dialog_link_(std::move(dialog_link)), bot_username_(std::move(bot_username)) {
if (!start_parameter.empty()) {
url_ = PSTRING() << "start://" << start_parameter;
}
}
};
class LinkManager::InternalLinkAuthenticationCode final : public InternalLink {
string code_;
@ -830,18 +849,30 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
return td::make_unique<InternalLinkVoiceChat>(std::move(username), arg.second, arg.first == "livestream");
}
if (arg.first == "start" && is_valid_start_parameter(arg.second)) {
// resolve?domain=<bot_username>?start=<parameter>
// resolve?domain=<bot_username>&start=<parameter>
return td::make_unique<InternalLinkBotStart>(std::move(username), arg.second);
}
if (arg.first == "startgroup" && is_valid_start_parameter(arg.second)) {
// resolve?domain=<bot_username>?startgroup=<parameter>
// resolve?domain=<bot_username>&startgroup=<parameter>
return td::make_unique<InternalLinkBotStartInGroup>(std::move(username), arg.second);
}
if (arg.first == "game" && !arg.second.empty()) {
// resolve?domain=<bot_username>?game=<short_name>
// resolve?domain=<bot_username>&game=<short_name>
return td::make_unique<InternalLinkGame>(std::move(username), arg.second);
}
}
if (!url_query.get_arg("attach").empty()) {
// resolve?domain=<username>&attach=<bot_username>
// resolve?domain=<username>&attach=<bot_username>&startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(
td::make_unique<InternalLinkPublicDialog>(std::move(username)), url_query.get_arg("attach").str(),
url_query.get_arg("startattach"));
} else if (url_query.has_arg("startattach")) {
// resolve?domain=<bot_username>&startattach
// resolve?domain=<bot_username>&startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(nullptr, std::move(username),
url_query.get_arg("startattach"));
}
if (username == "telegrampassport") {
// resolve?domain=telegrampassport&bot_id=<bot_user_id>&scope=<scope>&public_key=<public_key>&nonce=<nonce>
return get_internal_link_passport(query, url_query.args_);
@ -849,8 +880,15 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
// resolve?domain=<username>
return td::make_unique<InternalLinkPublicDialog>(std::move(username));
} else if (is_valid_phone_number(get_arg("phone"))) {
auto user_link = td::make_unique<InternalLinkUserPhoneNumber>(get_arg("phone"));
if (!url_query.get_arg("attach").empty()) {
// resolve?phone=<phone_number>&attach=<bot_username>
// resolve?phone=<phone_number>&attach=<bot_username>&startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(std::move(user_link), url_query.get_arg("attach").str(),
url_query.get_arg("startattach"));
}
// resolve?phone=12345
return td::make_unique<InternalLinkUserPhoneNumber>(get_arg("phone"));
return user_link;
}
} else if (path.size() == 1 && path[0] == "login") {
// login?code=123456
@ -1016,8 +1054,15 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
} else if (path[0][0] == ' ' || path[0][0] == '+') {
if (path[0].size() >= 2) {
if (is_valid_phone_number(Slice(path[0]).substr(1))) {
auto user_link = td::make_unique<InternalLinkUserPhoneNumber>(path[0].substr(1));
if (!url_query.get_arg("attach").empty()) {
// /+<phone_number>?attach=<bot_username>
// /+<phone_number>?attach=<bot_username>&startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(std::move(user_link), url_query.get_arg("attach").str(),
url_query.get_arg("startattach"));
}
// /+<phone_number>
return td::make_unique<InternalLinkUserPhoneNumber>(path[0].substr(1));
return user_link;
} else {
// /+<link>
return td::make_unique<InternalLinkDialogInvite>(PSTRING() << "tg:join?invite="
@ -1114,6 +1159,18 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
return td::make_unique<InternalLinkGame>(std::move(username), arg.second);
}
}
if (!url_query.get_arg("attach").empty()) {
// /<username>?attach=<bot_username>
// /<username>?attach=<bot_username>&startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(td::make_unique<InternalLinkPublicDialog>(std::move(username)),
url_query.get_arg("attach").str(),
url_query.get_arg("startattach"));
} else if (url_query.has_arg("startattach")) {
// /<bot_username>?startattach
// /<bot_username>?startattach=<start_parameter>
return td::make_unique<InternalLinkAttachMenuBot>(nullptr, std::move(username), url_query.get_arg("startattach"));
}
// /<username>
return td::make_unique<InternalLinkPublicDialog>(std::move(username));
}

View File

@ -82,6 +82,7 @@ class LinkManager final : public Actor {
void tear_down() final;
class InternalLinkActiveSessions;
class InternalLinkAttachMenuBot;
class InternalLinkAuthenticationCode;
class InternalLinkBackground;
class InternalLinkBotStart;

View File

@ -220,6 +220,12 @@ HttpUrlQuery parse_url_query(Slice query) {
return result;
}
bool HttpUrlQuery::has_arg(Slice key) const {
auto it =
std::find_if(args_.begin(), args_.end(), [&key](const std::pair<string, string> &s) { return s.first == key; });
return it != args_.end();
}
Slice HttpUrlQuery::get_arg(Slice key) const {
auto it =
std::find_if(args_.begin(), args_.end(), [&key](const std::pair<string, string> &s) { return s.first == key; });

View File

@ -48,6 +48,8 @@ class HttpUrlQuery {
vector<string> path_;
vector<std::pair<string, string>> args_;
bool has_arg(Slice key) const;
Slice get_arg(Slice key) const;
};

View File

@ -98,6 +98,11 @@ TEST(Link, parse_internal_link) {
auto active_sessions = [] {
return td::td_api::make_object<td::td_api::internalLinkTypeActiveSessions>();
};
auto attach_menu_bot = [](td::td_api::object_ptr<td::td_api::InternalLinkType> chat_link,
const td::string &bot_username, const td::string &start_parameter) {
return td::td_api::make_object<td::td_api::internalLinkTypeAttachMenuBot>(
std::move(chat_link), bot_username, start_parameter.empty() ? td::string() : "start://" + start_parameter);
};
auto authentication_code = [](const td::string &code) {
return td::td_api::make_object<td::td_api::internalLinkTypeAuthenticationCode>(code);
};
@ -209,6 +214,8 @@ TEST(Link, parse_internal_link) {
parse_internal_link("tg:resolve?domain=username&post=12345&single",
message("tg:resolve?domain=username&post=12345&single"));
parse_internal_link("tg:resolve?domain=username&post=12345&single&startattach=1&attach=test",
message("tg:resolve?domain=username&post=12345&single"));
parse_internal_link("tg:resolve?domain=user%31name&post=%312345&single&comment=456&t=789&single&thread=123%20%31",
message("tg:resolve?domain=user1name&post=12345&single&thread=123%201&comment=456&t=789"));
parse_internal_link("TG://resolve?domain=username&post=12345&single&voicechat=aasd",
@ -222,9 +229,27 @@ TEST(Link, parse_internal_link) {
parse_internal_link("tg:resolve?domain=telegram&post=&single", public_chat("telegram"));
parse_internal_link("tg:resolve?domain=123456&post=&single",
unknown_deep_link("tg://resolve?domain=123456&post=&single"));
parse_internal_link("tg:resolve?domain=telegram&startattach", attach_menu_bot(nullptr, "telegram", ""));
parse_internal_link("tg:resolve?domain=telegram&startattach=1", attach_menu_bot(nullptr, "telegram", "1"));
parse_internal_link("tg:resolve?domain=telegram&attach=&startattach", attach_menu_bot(nullptr, "telegram", ""));
parse_internal_link("tg:resolve?domain=telegram&attach=&startattach=1", attach_menu_bot(nullptr, "telegram", "1"));
parse_internal_link("tg:resolve?domain=telegram&attach=test&startattach",
attach_menu_bot(public_chat("telegram"), "test", ""));
parse_internal_link("tg:resolve?domain=telegram&attach=test&startattach=1",
attach_menu_bot(public_chat("telegram"), "test", "1"));
parse_internal_link("tg:resolve?phone=1", user_phone_number("1"));
parse_internal_link("tg:resolve?phone=123456", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&startattach", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&startattach=123", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&attach=", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&attach=&startattach", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&attach=&startattach=123", user_phone_number("123456"));
parse_internal_link("tg:resolve?phone=123456&attach=test", attach_menu_bot(user_phone_number("123456"), "test", ""));
parse_internal_link("tg:resolve?phone=123456&attach=test&startattach",
attach_menu_bot(user_phone_number("123456"), "test", ""));
parse_internal_link("tg:resolve?phone=123456&attach=test&startattach=123",
attach_menu_bot(user_phone_number("123456"), "test", "123"));
parse_internal_link("tg:resolve?phone=01234567890123456789012345678912",
user_phone_number("01234567890123456789012345678912"));
parse_internal_link("tg:resolve?phone=012345678901234567890123456789123",
@ -249,6 +274,14 @@ TEST(Link, parse_internal_link) {
parse_internal_link("t.me/username/-12345", public_chat("username"));
parse_internal_link("t.me//12345?single", nullptr);
parse_internal_link("https://telegram.dog/telegram/?single", public_chat("telegram"));
parse_internal_link("t.me/username?startattach", attach_menu_bot(nullptr, "username", ""));
parse_internal_link("t.me/username?startattach=1", attach_menu_bot(nullptr, "username", "1"));
parse_internal_link("t.me/username?attach=", public_chat("username"));
parse_internal_link("t.me/username?attach=&startattach", attach_menu_bot(nullptr, "username", ""));
parse_internal_link("t.me/username?attach=&startattach=1", attach_menu_bot(nullptr, "username", "1"));
parse_internal_link("t.me/username?attach=bot", attach_menu_bot(public_chat("username"), "bot", ""));
parse_internal_link("t.me/username?attach=bot&startattach", attach_menu_bot(public_chat("username"), "bot", ""));
parse_internal_link("t.me/username?attach=bot&startattach=1", attach_menu_bot(public_chat("username"), "bot", "1"));
parse_internal_link("tg:privatepost?domain=username/12345&single",
unknown_deep_link("tg://privatepost?domain=username/12345&single"));
@ -411,6 +444,15 @@ TEST(Link, parse_internal_link) {
parse_internal_link("t.me/+123456", user_phone_number("123456"));
parse_internal_link("t.me/ 123456/123123/12/31/a/s//21w/?asdas#test", user_phone_number("123456"));
parse_internal_link("t.me/ /123456/123123/12/31/a/s//21w/?asdas#test", nullptr);
parse_internal_link("t.me/+123456?startattach", user_phone_number("123456"));
parse_internal_link("t.me/+123456?startattach=1", user_phone_number("123456"));
parse_internal_link("t.me/+123456?attach=", user_phone_number("123456"));
parse_internal_link("t.me/+123456?attach=&startattach", user_phone_number("123456"));
parse_internal_link("t.me/+123456?attach=&startattach=1", user_phone_number("123456"));
parse_internal_link("t.me/+123456?attach=bot", attach_menu_bot(user_phone_number("123456"), "bot", ""));
parse_internal_link("t.me/+123456?attach=bot&startattach", attach_menu_bot(user_phone_number("123456"), "bot", ""));
parse_internal_link("t.me/+123456?attach=bot&startattach=1",
attach_menu_bot(user_phone_number("123456"), "bot", "1"));
parse_internal_link("tg:join?invite=abcdef", chat_invite("abcdef"));
parse_internal_link("tg:join?invite=abc%20def", chat_invite("abc%20def"));