From 7364334ebea732378ea41d725257feab170ea6a4 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 1 Apr 2022 14:00:34 +0300 Subject: [PATCH] Add internalLinkTypeAttachMenuBot. --- td/generate/scheme/td_api.tl | 12 +++++-- td/telegram/LinkManager.cpp | 67 +++++++++++++++++++++++++++++++++--- td/telegram/LinkManager.h | 1 + tdutils/td/utils/HttpUrl.cpp | 6 ++++ tdutils/td/utils/HttpUrl.h | 2 ++ test/link.cpp | 42 ++++++++++++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index e79e04e8a..89fd87848 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -881,7 +881,7 @@ messageCalendar total_count:int32 days:vector = 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 diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index c61bd59a7..7e27a3800 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -108,6 +108,25 @@ class LinkManager::InternalLinkActiveSessions final : public InternalLink { } }; +class LinkManager::InternalLinkAttachMenuBot final : public InternalLink { + unique_ptr dialog_link_; + string bot_username_; + string url_; + + td_api::object_ptr get_internal_link_type_object() const final { + return td_api::make_object( + dialog_link_ == nullptr ? nullptr : dialog_link_->get_internal_link_type_object(), bot_username_, url_); + } + + public: + InternalLinkAttachMenuBot(unique_ptr 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::parse_tg_link_query(Slice que return td::make_unique(std::move(username), arg.second, arg.first == "livestream"); } if (arg.first == "start" && is_valid_start_parameter(arg.second)) { - // resolve?domain=?start= + // resolve?domain=&start= return td::make_unique(std::move(username), arg.second); } if (arg.first == "startgroup" && is_valid_start_parameter(arg.second)) { - // resolve?domain=?startgroup= + // resolve?domain=&startgroup= return td::make_unique(std::move(username), arg.second); } if (arg.first == "game" && !arg.second.empty()) { - // resolve?domain=?game= + // resolve?domain=&game= return td::make_unique(std::move(username), arg.second); } } + if (!url_query.get_arg("attach").empty()) { + // resolve?domain=&attach= + // resolve?domain=&attach=&startattach= + return td::make_unique( + td::make_unique(std::move(username)), url_query.get_arg("attach").str(), + url_query.get_arg("startattach")); + } else if (url_query.has_arg("startattach")) { + // resolve?domain=&startattach + // resolve?domain=&startattach= + return td::make_unique(nullptr, std::move(username), + url_query.get_arg("startattach")); + } if (username == "telegrampassport") { // resolve?domain=telegrampassport&bot_id=&scope=&public_key=&nonce= return get_internal_link_passport(query, url_query.args_); @@ -849,8 +880,15 @@ unique_ptr LinkManager::parse_tg_link_query(Slice que // resolve?domain= return td::make_unique(std::move(username)); } else if (is_valid_phone_number(get_arg("phone"))) { + auto user_link = td::make_unique(get_arg("phone")); + if (!url_query.get_arg("attach").empty()) { + // resolve?phone=&attach= + // resolve?phone=&attach=&startattach= + return td::make_unique(std::move(user_link), url_query.get_arg("attach").str(), + url_query.get_arg("startattach")); + } // resolve?phone=12345 - return td::make_unique(get_arg("phone")); + return user_link; } } else if (path.size() == 1 && path[0] == "login") { // login?code=123456 @@ -1016,8 +1054,15 @@ unique_ptr 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(path[0].substr(1)); + if (!url_query.get_arg("attach").empty()) { + // /+?attach= + // /+?attach=&startattach= + return td::make_unique(std::move(user_link), url_query.get_arg("attach").str(), + url_query.get_arg("startattach")); + } // /+ - return td::make_unique(path[0].substr(1)); + return user_link; } else { // /+ return td::make_unique(PSTRING() << "tg:join?invite=" @@ -1114,6 +1159,18 @@ unique_ptr LinkManager::parse_t_me_link_query(Slice q return td::make_unique(std::move(username), arg.second); } } + if (!url_query.get_arg("attach").empty()) { + // /?attach= + // /?attach=&startattach= + return td::make_unique(td::make_unique(std::move(username)), + url_query.get_arg("attach").str(), + url_query.get_arg("startattach")); + } else if (url_query.has_arg("startattach")) { + // /?startattach + // /?startattach= + return td::make_unique(nullptr, std::move(username), url_query.get_arg("startattach")); + } + // / return td::make_unique(std::move(username)); } diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index 3e39cc3a8..832326421 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -82,6 +82,7 @@ class LinkManager final : public Actor { void tear_down() final; class InternalLinkActiveSessions; + class InternalLinkAttachMenuBot; class InternalLinkAuthenticationCode; class InternalLinkBackground; class InternalLinkBotStart; diff --git a/tdutils/td/utils/HttpUrl.cpp b/tdutils/td/utils/HttpUrl.cpp index 963a29245..ced0a2860 100644 --- a/tdutils/td/utils/HttpUrl.cpp +++ b/tdutils/td/utils/HttpUrl.cpp @@ -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 &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 &s) { return s.first == key; }); diff --git a/tdutils/td/utils/HttpUrl.h b/tdutils/td/utils/HttpUrl.h index c5f1bb47b..8ac5e5623 100644 --- a/tdutils/td/utils/HttpUrl.h +++ b/tdutils/td/utils/HttpUrl.h @@ -48,6 +48,8 @@ class HttpUrlQuery { vector path_; vector> args_; + bool has_arg(Slice key) const; + Slice get_arg(Slice key) const; }; diff --git a/test/link.cpp b/test/link.cpp index 34e867d43..af130b7ca 100644 --- a/test/link.cpp +++ b/test/link.cpp @@ -98,6 +98,11 @@ TEST(Link, parse_internal_link) { auto active_sessions = [] { return td::td_api::make_object(); }; + auto attach_menu_bot = [](td::td_api::object_ptr chat_link, + const td::string &bot_username, const td::string &start_parameter) { + return td::td_api::make_object( + 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(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"));