From fce20df018a8ec23e440637e3557694ab36b44f4 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 30 Dec 2021 14:15:04 +0300 Subject: [PATCH] Add support for sponsored chats with an invite link. --- td/generate/scheme/td_api.tl | 5 +- td/telegram/LinkManager.cpp | 11 ++++ td/telegram/LinkManager.h | 2 + td/telegram/SponsoredMessageManager.cpp | 68 +++++++++++++++++++------ 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 3582fe5dd..f1bb3f809 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -831,10 +831,11 @@ messageCalendar total_count:int32 days:vector = MessageCalen //@description Describes a sponsored message //@message_id Message identifier; unique for the chat to which the sponsored message belongs among both ordinary and sponsored messages -//@sponsor_chat_id Chat identifier +//@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 //@content Content of the message. Currently, can be only of the type messageText -sponsoredMessage message_id:int53 sponsor_chat_id:int53 link:InternalLinkType content:MessageContent = SponsoredMessage; +sponsoredMessage message_id:int53 sponsor_chat_id:int53 sponsor_chat_info:chatInviteLinkInfo link:InternalLinkType content:MessageContent = SponsoredMessage; //@class NotificationSettingsScope @description Describes the types of chats to which notification settings are relevant diff --git a/td/telegram/LinkManager.cpp b/td/telegram/LinkManager.cpp index a4481c77e..1749facc3 100644 --- a/td/telegram/LinkManager.cpp +++ b/td/telegram/LinkManager.cpp @@ -1235,6 +1235,17 @@ string LinkManager::get_dialog_invite_link_hash(Slice invite_link) { return get_url_query_hash(link_info.is_tg_, url_query); } +string LinkManager::get_dialog_invite_link(Slice hash, bool is_internal) { + if (!is_base64url_characters(hash)) { + return string(); + } + if (is_internal) { + return PSTRING() << "tg:join?invite=" << hash; + } else { + return PSTRING() << G()->shared_config().get_option_string("t_me_url", "https://t.me/") << '+' << hash; + } +} + UserId LinkManager::get_link_user_id(Slice url) { string lower_cased_url = to_lower(url); url = lower_cased_url; diff --git a/td/telegram/LinkManager.h b/td/telegram/LinkManager.h index 2bc65a72b..6749ad3af 100644 --- a/td/telegram/LinkManager.h +++ b/td/telegram/LinkManager.h @@ -70,6 +70,8 @@ class LinkManager final : public Actor { static string get_dialog_invite_link_hash(Slice invite_link); + static string get_dialog_invite_link(Slice hash, bool is_internal); + static UserId get_link_user_id(Slice url); static Result get_message_link_info(Slice url); diff --git a/td/telegram/SponsoredMessageManager.cpp b/td/telegram/SponsoredMessageManager.cpp index 5e52e9c86..930b47ef9 100644 --- a/td/telegram/SponsoredMessageManager.cpp +++ b/td/telegram/SponsoredMessageManager.cpp @@ -10,6 +10,7 @@ #include "td/telegram/ConfigShared.h" #include "td/telegram/ContactsManager.h" #include "td/telegram/Global.h" +#include "td/telegram/LinkManager.h" #include "td/telegram/MessageContent.h" #include "td/telegram/MessageEntity.h" #include "td/telegram/MessagesManager.h" @@ -94,15 +95,17 @@ struct SponsoredMessageManager::SponsoredMessage { DialogId sponsor_dialog_id; ServerMessageId server_message_id; string start_param; + string invite_hash; unique_ptr content; SponsoredMessage() = default; SponsoredMessage(int64 local_id, DialogId sponsor_dialog_id, ServerMessageId server_message_id, string start_param, - unique_ptr content) + string invite_hash, unique_ptr content) : local_id(local_id) , sponsor_dialog_id(sponsor_dialog_id) , server_message_id(server_message_id) , start_param(std::move(start_param)) + , invite_hash(std::move(invite_hash)) , content(std::move(content)) { } }; @@ -148,6 +151,7 @@ void SponsoredMessageManager::delete_cached_sponsored_messages(DialogId dialog_i td_api::object_ptr SponsoredMessageManager::get_sponsored_message_object( DialogId dialog_id, const SponsoredMessage &sponsored_message) const { + td_api::object_ptr chat_invite_link_info; td_api::object_ptr link; switch (sponsored_message.sponsor_dialog_id.get_type()) { case DialogType::User: { @@ -170,12 +174,23 @@ td_api::object_ptr SponsoredMessageManager::get_sponso PSTRING() << t_me << "c/" << channel_id.get() << '/' << sponsored_message.server_message_id.get()); } break; + case DialogType::None: { + CHECK(!sponsored_message.invite_hash.empty()); + auto invite_link = LinkManager::get_dialog_invite_link(sponsored_message.invite_hash, false); + chat_invite_link_info = td_->contacts_manager_->get_chat_invite_link_info_object(invite_link); + if (chat_invite_link_info == nullptr) { + LOG(ERROR) << "Failed to get invite link info for " << invite_link; + return nullptr; + } + link = td_api::make_object( + LinkManager::get_dialog_invite_link(sponsored_message.invite_hash, true)); + } default: break; } return td_api::make_object( - sponsored_message.local_id, sponsored_message.sponsor_dialog_id.get(), std::move(link), - get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1)); + sponsored_message.local_id, sponsored_message.sponsor_dialog_id.get(), std::move(chat_invite_link_info), + std::move(link), get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1)); } td_api::object_ptr SponsoredMessageManager::get_sponsored_message_object( @@ -243,21 +258,41 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages( td_->contacts_manager_->on_get_chats(std::move(sponsored_messages->chats_), "on_get_dialog_sponsored_messages"); for (auto &sponsored_message : sponsored_messages->messages_) { - if (sponsored_message->from_id_ == nullptr) { + DialogId sponsor_dialog_id; + ServerMessageId server_message_id; + string invite_hash; + if (sponsored_message->from_id_ != nullptr) { + sponsor_dialog_id = DialogId(sponsored_message->from_id_); + if (!sponsor_dialog_id.is_valid() || !td_->messages_manager_->have_dialog_info_force(sponsor_dialog_id)) { + LOG(ERROR) << "Receive unknown sponsor " << sponsor_dialog_id; + continue; + } + server_message_id = ServerMessageId(sponsored_message->channel_post_); + if (!server_message_id.is_valid() && server_message_id != ServerMessageId()) { + LOG(ERROR) << "Receive invalid channel post in " << to_string(sponsored_message); + server_message_id = ServerMessageId(); + } + td_->messages_manager_->force_create_dialog(sponsor_dialog_id, "on_get_dialog_sponsored_messages"); + } else if (sponsored_message->chat_invite_ != nullptr && !sponsored_message->chat_invite_hash_.empty()) { + auto invite_link = LinkManager::get_dialog_invite_link(sponsored_message->chat_invite_hash_, false); + if (invite_link.empty()) { + LOG(ERROR) << "Receive invalid invite link hash in " << to_string(sponsored_message); + continue; + } + auto chat_invite = to_string(sponsored_message->chat_invite_); + td_->contacts_manager_->on_get_dialog_invite_link_info(invite_link, std::move(sponsored_message->chat_invite_), + Promise()); + auto chat_invite_link_info = td_->contacts_manager_->get_chat_invite_link_info_object(invite_link); + if (chat_invite_link_info == nullptr) { + LOG(ERROR) << "Failed to get invite link info from " << chat_invite << " for " << to_string(sponsored_message); + continue; + } + invite_hash = std::move(sponsored_message->chat_invite_hash_); + } else { + LOG(ERROR) << "Receive " << to_string(sponsored_message); continue; } - DialogId sponsor_dialog_id(sponsored_message->from_id_); - if (!sponsor_dialog_id.is_valid() || !td_->messages_manager_->have_dialog_info_force(sponsor_dialog_id)) { - LOG(ERROR) << "Receive unknown sponsor " << sponsor_dialog_id; - continue; - } - auto server_message_id = ServerMessageId(sponsored_message->channel_post_); - if (!server_message_id.is_valid() && server_message_id != ServerMessageId()) { - LOG(ERROR) << "Receive invalid channel post in " << to_string(sponsored_message); - server_message_id = ServerMessageId(); - } - td_->messages_manager_->force_create_dialog(sponsor_dialog_id, "on_get_dialog_sponsored_messages"); auto message_text = get_message_text(td_->contacts_manager_.get(), std::move(sponsored_message->message_), std::move(sponsored_message->entities_), true, true, 0, false, "on_get_dialog_sponsored_messages"); @@ -283,7 +318,8 @@ void SponsoredMessageManager::on_get_dialog_sponsored_messages( CHECK(messages->message_random_ids.count(local_id) == 0); messages->message_random_ids[local_id] = sponsored_message->random_id_.as_slice().str(); messages->messages.emplace_back(local_id, sponsor_dialog_id, server_message_id, - std::move(sponsored_message->start_param_), std::move(content)); + std::move(sponsored_message->start_param_), std::move(invite_hash), + std::move(content)); } for (auto &promise : promises) {