From 469be958f24256036139bf7a5705f55a7f4e1c10 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 15 Sep 2023 19:07:18 +0300 Subject: [PATCH] Add td_api::getChatBoostLinkInfo. --- CMakeLists.txt | 1 + td/generate/scheme/td_api.tl | 8 +++ td/telegram/DialogBoostLinkInfo.h | 21 +++++++ td/telegram/LinkManager.cpp | 101 +++++++++++++++++++++++++++++- td/telegram/LinkManager.h | 3 + td/telegram/StoryManager.cpp | 23 +++++++ td/telegram/StoryManager.h | 5 ++ td/telegram/Td.cpp | 33 ++++++++++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 2 + 10 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 td/telegram/DialogBoostLinkInfo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ff10a9d9..d95c9e8ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -579,6 +579,7 @@ set(TDLIB_SOURCE td/telegram/DialogAction.h td/telegram/DialogActionBar.h td/telegram/DialogAdministrator.h + td/telegram/DialogBoostLinkInfo.h td/telegram/DialogDate.h td/telegram/DialogDb.h td/telegram/DialogEventLog.h diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 2c11ba5b9..83f02d62f 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -5227,6 +5227,11 @@ messageLinkInfo is_public:Bool chat_id:int53 message_thread_id:int53 message:mes //@description Contains an HTTPS link to boost a chat @link The link @is_public True, if the link will work for non-members of the chat chatBoostLink link:string is_public:Bool = ChatBoostLink; +//@description Contains information about a link to boost a a chat +//@is_public True, if the link will work for non-members of the chat +//@chat_id Identifier of the chat to which the link points; 0 if the chat isn't found +chatBoostLinkInfo is_public:Bool chat_id:int53 = ChatBoostLinkInfo; + //@class BlockList @description Describes a type of a block list @@ -7696,6 +7701,9 @@ boostChat chat_id:int53 = Ok; //@description Returns an HTTPS link to boost the specified channel chat @chat_id Identifier of the chat getChatBoostLink chat_id:int53 = ChatBoostLink; +//@description Returns information about a link to boost a chat. Can be called for any internal link of the type internalLinkTypeChatBoost @url The link to boost a chat +getChatBoostLinkInfo url:string = ChatBoostLinkInfo; + //@description Returns information about a bot that can be added to attachment or side menu @bot_user_id Bot's user identifier getAttachmentMenuBot bot_user_id:int53 = AttachmentMenuBot; diff --git a/td/telegram/DialogBoostLinkInfo.h b/td/telegram/DialogBoostLinkInfo.h new file mode 100644 index 000000000..89c31ec4c --- /dev/null +++ b/td/telegram/DialogBoostLinkInfo.h @@ -0,0 +1,21 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// 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/ChannelId.h" + +#include "td/utils/common.h" + +namespace td { + +struct DialogBoostLinkInfo { + string username; + // or + ChannelId channel_id; +}; + +} // namespace td diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index 1bc0ec0f6..5c550bee3 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -2686,6 +2686,105 @@ Result LinkManager::get_link_custom_emoji_id(Slice url) { return Status::Error(400, "Custom emoji URL must have an emoji identifier"); } +Result LinkManager::get_dialog_boost_link_info(Slice url) { + if (url.empty()) { + return Status::Error("URL must be non-empty"); + } + auto link_info = get_link_info(url); + if (link_info.type_ != LinkType::Tg && link_info.type_ != LinkType::TMe) { + return Status::Error("Invalid chat boost link URL"); + } + url = link_info.query_; + + Slice username; + Slice channel_id_slice; + if (link_info.type_ == LinkType::Tg) { + // boost?domain=username + // boost?channel=123456789 + + if (!begins_with(url, "boost")) { + return Status::Error("Wrong chat boost link URL"); + } + url = url.substr(5); + + if (begins_with(url, "/")) { + url = url.substr(1); + } + if (!begins_with(url, "?")) { + return Status::Error("Wrong chat boost link URL"); + } + url = url.substr(1); + + auto args = full_split(url, '&'); + for (auto arg : args) { + auto key_value = split(arg, '='); + if (key_value.first == "domain") { + username = key_value.second; + } else if (key_value.first == "channel") { + channel_id_slice = key_value.second; + } + } + } else { + // /username?boost + // /c/123456789?boost + + CHECK(!url.empty() && url[0] == '/'); + url.remove_prefix(1); + + size_t username_end_pos = 0; + while (username_end_pos < url.size() && url[username_end_pos] != '/' && url[username_end_pos] != '?' && + url[username_end_pos] != '#') { + username_end_pos++; + } + username = url.substr(0, username_end_pos); + url = url.substr(username_end_pos); + if (!url.empty() && url[0] == '/') { + url = url.substr(1); + } + if (username == "c") { + username = Slice(); + size_t channel_id_end_pos = 0; + while (channel_id_end_pos < url.size() && url[channel_id_end_pos] != '/' && url[channel_id_end_pos] != '?' && + url[channel_id_end_pos] != '#') { + channel_id_end_pos++; + } + channel_id_slice = url.substr(0, channel_id_end_pos); + url = url.substr(channel_id_end_pos); + } + + bool is_boost = false; + auto query_pos = url.find('?'); + if (query_pos != Slice::npos) { + auto args = full_split(url.substr(query_pos + 1), '&'); + for (auto arg : args) { + auto key_value = split(arg, '='); + if (key_value.first == "boost") { + is_boost = true; + } + } + } + + if (!is_boost) { + return Status::Error("Wrong chat boost link URL"); + } + } + + ChannelId channel_id; + if (username.empty()) { + auto r_channel_id = to_integer_safe(channel_id_slice); + if (r_channel_id.is_error() || !ChannelId(r_channel_id.ok()).is_valid()) { + return Status::Error("Wrong channel ID"); + } + channel_id = ChannelId(r_channel_id.ok()); + } + + DialogBoostLinkInfo info; + info.username = username.str(); + info.channel_id = channel_id; + LOG(INFO) << "Have link to boost chat @" << info.username << '/' << channel_id.get(); + return std::move(info); +} + Result LinkManager::get_message_link_info(Slice url) { if (url.empty()) { return Status::Error("URL must be non-empty"); @@ -2885,7 +2984,7 @@ Result LinkManager::get_message_link_info(Slice url) { info.media_timestamp = is_media_timestamp_invalid ? 0 : media_timestamp; info.is_single = is_single; info.for_comment = for_comment; - LOG(INFO) << "Have link to " << info.message_id << " in chat @" << info.username << "/" << channel_id.get(); + LOG(INFO) << "Have link to " << info.message_id << " in chat @" << info.username << '/' << channel_id.get(); return std::move(info); } diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index 4dcb92e6f..1cc1773d3 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/CustomEmojiId.h" +#include "td/telegram/DialogBoostLinkInfo.h" #include "td/telegram/FullMessageId.h" #include "td/telegram/MessageLinkInfo.h" #include "td/telegram/td_api.h" @@ -107,6 +108,8 @@ class LinkManager final : public Actor { static Result get_link_custom_emoji_id(Slice url); + static Result get_dialog_boost_link_info(Slice url); + static Result get_message_link_info(Slice url); private: diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index cf9b1fb20..22d445ba1 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -3016,6 +3016,29 @@ Result> StoryManager::get_dialog_boost_link(DialogId dia return std::make_pair(sb.as_cslice().str(), is_public); } +void StoryManager::get_dialog_boost_link_info(Slice url, Promise &&promise) { + auto r_dialog_boost_link_info = LinkManager::get_dialog_boost_link_info(url); + if (r_dialog_boost_link_info.is_error()) { + return promise.set_error(Status::Error(400, r_dialog_boost_link_info.error().message())); + } + + auto info = r_dialog_boost_link_info.move_as_ok(); + auto query_promise = PromiseCreator::lambda( + [info, promise = std::move(promise)](Result &&result) mutable { promise.set_value(std::move(info)); }); + td_->messages_manager_->resolve_dialog(info.username, info.channel_id, std::move(query_promise)); +} + +td_api::object_ptr StoryManager::get_chat_boost_link_info_object( + const DialogBoostLinkInfo &info) const { + CHECK(info.username.empty() == info.channel_id.is_valid()); + + bool is_public = !info.username.empty(); + DialogId dialog_id = + is_public ? td_->messages_manager_->resolve_dialog_username(info.username) : DialogId(info.channel_id); + return td_api::make_object( + is_public, td_->messages_manager_->get_chat_id_object(dialog_id, "chatBoostLinkInfo")); +} + bool StoryManager::have_story(StoryFullId story_full_id) const { return get_story(story_full_id) != nullptr; } diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index 6aa219ea2..54fb3743b 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/ChannelId.h" +#include "td/telegram/DialogBoostLinkInfo.h" #include "td/telegram/DialogDate.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileId.h" @@ -278,6 +279,10 @@ class StoryManager final : public Actor { Result> get_dialog_boost_link(DialogId dialog_id); + void get_dialog_boost_link_info(Slice url, Promise &&promise); + + td_api::object_ptr get_chat_boost_link_info_object(const DialogBoostLinkInfo &info) const; + void remove_story_notifications_by_story_ids(DialogId dialog_id, const vector &story_ids); StoryId on_get_story(DialogId owner_dialog_id, telegram_api::object_ptr &&story_item_ptr); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 163898a0c..b65f741e3 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -32,6 +32,7 @@ #include "td/telegram/CustomEmojiId.h" #include "td/telegram/DeviceTokenManager.h" #include "td/telegram/DialogAction.h" +#include "td/telegram/DialogBoostLinkInfo.h" #include "td/telegram/DialogEventLog.h" #include "td/telegram/DialogFilter.h" #include "td/telegram/DialogFilterId.h" @@ -1128,6 +1129,33 @@ class GetMessageLinkInfoRequest final : public RequestActor { } }; +class GetDialogBoostLinkInfoRequest final : public RequestActor { + string url_; + + DialogBoostLinkInfo dialog_boost_link_info_; + + void do_run(Promise &&promise) final { + if (get_tries() < 2) { + promise.set_value(std::move(dialog_boost_link_info_)); + return; + } + td_->story_manager_->get_dialog_boost_link_info(url_, std::move(promise)); + } + + void do_set_result(DialogBoostLinkInfo &&result) final { + dialog_boost_link_info_ = std::move(result); + } + + void do_send_result() final { + send_result(td_->story_manager_->get_chat_boost_link_info_object(dialog_boost_link_info_)); + } + + public: + GetDialogBoostLinkInfoRequest(ActorShared td, uint64 request_id, string url) + : RequestActor(std::move(td), request_id), url_(std::move(url)) { + } +}; + class EditMessageTextRequest final : public RequestOnceActor { FullMessageId full_message_id_; tl_object_ptr reply_markup_; @@ -6614,6 +6642,11 @@ void Td::on_request(uint64 id, const td_api::getChatBoostLink &request) { } } +void Td::on_request(uint64 id, td_api::getChatBoostLinkInfo &request) { + CLEAN_INPUT_STRING(request.url_); + CREATE_REQUEST(GetDialogBoostLinkInfoRequest, std::move(request.url_)); +} + void Td::on_request(uint64 id, const td_api::getAttachmentMenuBot &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 38544a021..77ecfbfc8 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -1048,6 +1048,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::getChatBoostLink &request); + void on_request(uint64 id, td_api::getChatBoostLinkInfo &request); + void on_request(uint64 id, const td_api::getAttachmentMenuBot &request); void on_request(uint64 id, const td_api::toggleBotIsAddedToAttachmentMenu &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index ad86d32b3..2001d248a 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -4306,6 +4306,8 @@ class CliClient final : public Actor { ChatId chat_id; get_args(args, chat_id); send_request(td_api::make_object(chat_id)); + } else if (op == "gcbli") { + send_request(td_api::make_object(args)); } else if (op == "gamb") { UserId user_id; get_args(args, user_id);