2021-08-24 22:44:47 +02:00
|
|
|
//
|
2024-01-01 01:07:21 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
|
2021-08-24 22:44:47 +02:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
2021-09-07 14:49:34 +02:00
|
|
|
#include "td/telegram/SponsoredMessageManager.h"
|
2021-08-24 22:44:47 +02:00
|
|
|
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/telegram/ChannelId.h"
|
2024-04-02 12:06:22 +02:00
|
|
|
#include "td/telegram/ChatManager.h"
|
2024-01-08 11:25:31 +01:00
|
|
|
#include "td/telegram/DialogInviteLinkManager.h"
|
2024-01-03 21:07:50 +01:00
|
|
|
#include "td/telegram/DialogManager.h"
|
2021-08-25 21:34:18 +02:00
|
|
|
#include "td/telegram/Global.h"
|
2021-12-30 12:15:04 +01:00
|
|
|
#include "td/telegram/LinkManager.h"
|
2021-08-24 22:44:47 +02:00
|
|
|
#include "td/telegram/MessageContent.h"
|
|
|
|
#include "td/telegram/MessageEntity.h"
|
2024-01-30 13:07:21 +01:00
|
|
|
#include "td/telegram/MessageSelfDestructType.h"
|
2021-08-25 21:34:18 +02:00
|
|
|
#include "td/telegram/net/NetQueryCreator.h"
|
2022-08-18 16:00:18 +02:00
|
|
|
#include "td/telegram/OptionManager.h"
|
2023-06-02 13:42:28 +02:00
|
|
|
#include "td/telegram/Photo.h"
|
2021-10-08 14:29:40 +02:00
|
|
|
#include "td/telegram/ServerMessageId.h"
|
2021-08-24 22:44:47 +02:00
|
|
|
#include "td/telegram/Td.h"
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/telegram/telegram_api.h"
|
2022-10-12 14:59:58 +02:00
|
|
|
#include "td/telegram/UserId.h"
|
2024-04-02 02:52:34 +02:00
|
|
|
#include "td/telegram/UserManager.h"
|
2023-11-20 12:34:56 +01:00
|
|
|
#include "td/telegram/WebApp.h"
|
2021-08-24 22:44:47 +02:00
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
#include "td/utils/algorithm.h"
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/utils/buffer.h"
|
|
|
|
#include "td/utils/logging.h"
|
2021-11-04 10:46:08 +01:00
|
|
|
#include "td/utils/SliceBuilder.h"
|
2021-09-01 19:31:39 +02:00
|
|
|
#include "td/utils/Status.h"
|
2021-08-25 21:34:18 +02:00
|
|
|
|
2021-08-24 22:44:47 +02:00
|
|
|
namespace td {
|
|
|
|
|
|
|
|
class GetSponsoredMessagesQuery final : public Td::ResultHandler {
|
2022-10-07 17:04:00 +02:00
|
|
|
Promise<telegram_api::object_ptr<telegram_api::messages_SponsoredMessages>> promise_;
|
2021-08-24 22:44:47 +02:00
|
|
|
ChannelId channel_id_;
|
|
|
|
|
|
|
|
public:
|
2021-09-07 16:21:18 +02:00
|
|
|
explicit GetSponsoredMessagesQuery(
|
2022-10-07 17:04:00 +02:00
|
|
|
Promise<telegram_api::object_ptr<telegram_api::messages_SponsoredMessages>> &&promise)
|
2021-08-24 22:44:47 +02:00
|
|
|
: promise_(std::move(promise)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(ChannelId channel_id) {
|
|
|
|
channel_id_ = channel_id;
|
2024-04-02 12:06:22 +02:00
|
|
|
auto input_channel = td_->chat_manager_->get_input_channel(channel_id);
|
2021-08-24 22:44:47 +02:00
|
|
|
if (input_channel == nullptr) {
|
2021-09-24 09:59:51 +02:00
|
|
|
return promise_.set_error(Status::Error(400, "Chat info not found"));
|
2021-08-24 22:44:47 +02:00
|
|
|
}
|
|
|
|
send_query(G()->net_query_creator().create(telegram_api::channels_getSponsoredMessages(std::move(input_channel))));
|
|
|
|
}
|
|
|
|
|
2021-11-08 12:19:57 +01:00
|
|
|
void on_result(BufferSlice packet) final {
|
2021-08-24 22:44:47 +02:00
|
|
|
auto result_ptr = fetch_result<telegram_api::channels_getSponsoredMessages>(packet);
|
|
|
|
if (result_ptr.is_error()) {
|
2021-11-08 12:19:57 +01:00
|
|
|
return on_error(result_ptr.move_as_error());
|
2021-08-24 22:44:47 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 14:13:20 +02:00
|
|
|
auto ptr = result_ptr.move_as_ok();
|
|
|
|
LOG(DEBUG) << "Receive result for GetSponsoredMessagesQuery: " << to_string(ptr);
|
|
|
|
promise_.set_value(std::move(ptr));
|
2021-08-24 22:44:47 +02:00
|
|
|
}
|
|
|
|
|
2021-11-08 12:19:57 +01:00
|
|
|
void on_error(Status status) final {
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->on_get_channel_error(channel_id_, status, "GetSponsoredMessagesQuery");
|
2021-08-24 22:44:47 +02:00
|
|
|
promise_.set_error(std::move(status));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-08-25 21:34:18 +02:00
|
|
|
class ViewSponsoredMessageQuery final : public Td::ResultHandler {
|
|
|
|
ChannelId channel_id_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void send(ChannelId channel_id, const string &message_id) {
|
|
|
|
channel_id_ = channel_id;
|
2024-04-02 12:06:22 +02:00
|
|
|
auto input_channel = td_->chat_manager_->get_input_channel(channel_id);
|
2021-08-25 21:34:18 +02:00
|
|
|
if (input_channel == nullptr) {
|
2021-12-27 16:17:02 +01:00
|
|
|
return;
|
2021-08-25 21:34:18 +02:00
|
|
|
}
|
|
|
|
send_query(G()->net_query_creator().create(
|
|
|
|
telegram_api::channels_viewSponsoredMessage(std::move(input_channel), BufferSlice(message_id))));
|
|
|
|
}
|
|
|
|
|
2021-11-08 12:19:57 +01:00
|
|
|
void on_result(BufferSlice packet) final {
|
2021-08-25 21:34:18 +02:00
|
|
|
auto result_ptr = fetch_result<telegram_api::channels_viewSponsoredMessage>(packet);
|
|
|
|
if (result_ptr.is_error()) {
|
2021-11-08 12:19:57 +01:00
|
|
|
return on_error(result_ptr.move_as_error());
|
2021-08-25 21:34:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-08 12:19:57 +01:00
|
|
|
void on_error(Status status) final {
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->on_get_channel_error(channel_id_, status, "ViewSponsoredMessageQuery");
|
2021-08-25 21:34:18 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-05-04 16:21:50 +02:00
|
|
|
class ClickSponsoredMessageQuery final : public Td::ResultHandler {
|
|
|
|
Promise<Unit> promise_;
|
|
|
|
ChannelId channel_id_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit ClickSponsoredMessageQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(ChannelId channel_id, const string &message_id) {
|
|
|
|
channel_id_ = channel_id;
|
2024-04-02 12:06:22 +02:00
|
|
|
auto input_channel = td_->chat_manager_->get_input_channel(channel_id);
|
2023-05-04 16:21:50 +02:00
|
|
|
if (input_channel == nullptr) {
|
|
|
|
return promise_.set_value(Unit());
|
|
|
|
}
|
|
|
|
send_query(G()->net_query_creator().create(
|
|
|
|
telegram_api::channels_clickSponsoredMessage(std::move(input_channel), BufferSlice(message_id))));
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
|
|
auto result_ptr = fetch_result<telegram_api::channels_clickSponsoredMessage>(packet);
|
|
|
|
if (result_ptr.is_error()) {
|
|
|
|
return on_error(result_ptr.move_as_error());
|
|
|
|
}
|
|
|
|
promise_.set_value(Unit());
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_error(Status status) final {
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->on_get_channel_error(channel_id_, status, "ClickSponsoredMessageQuery");
|
2023-05-04 16:21:50 +02:00
|
|
|
promise_.set_error(std::move(status));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-03-28 16:24:39 +01:00
|
|
|
class ReportSponsoredMessageQuery final : public Td::ResultHandler {
|
|
|
|
Promise<td_api::object_ptr<td_api::ReportChatSponsoredMessageResult>> promise_;
|
|
|
|
ChannelId channel_id_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit ReportSponsoredMessageQuery(Promise<td_api::object_ptr<td_api::ReportChatSponsoredMessageResult>> &&promise)
|
|
|
|
: promise_(std::move(promise)) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(ChannelId channel_id, const string &message_id, const string &option_id) {
|
|
|
|
channel_id_ = channel_id;
|
2024-04-02 12:06:22 +02:00
|
|
|
auto input_channel = td_->chat_manager_->get_input_channel(channel_id);
|
2024-03-28 16:24:39 +01:00
|
|
|
if (input_channel == nullptr) {
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultFailed>());
|
|
|
|
}
|
|
|
|
send_query(G()->net_query_creator().create(telegram_api::channels_reportSponsoredMessage(
|
|
|
|
std::move(input_channel), BufferSlice(message_id), BufferSlice(option_id))));
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
|
|
auto result_ptr = fetch_result<telegram_api::channels_reportSponsoredMessage>(packet);
|
|
|
|
if (result_ptr.is_error()) {
|
|
|
|
return on_error(result_ptr.move_as_error());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ptr = result_ptr.move_as_ok();
|
|
|
|
LOG(DEBUG) << "Receive result for ReportSponsoredMessageQuery: " << to_string(ptr);
|
|
|
|
switch (ptr->get_id()) {
|
|
|
|
case telegram_api::channels_sponsoredMessageReportResultReported::ID:
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultOk>());
|
|
|
|
case telegram_api::channels_sponsoredMessageReportResultAdsHidden::ID:
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultAdsHidden>());
|
|
|
|
case telegram_api::channels_sponsoredMessageReportResultChooseOption::ID: {
|
|
|
|
auto options =
|
|
|
|
telegram_api::move_object_as<telegram_api::channels_sponsoredMessageReportResultChooseOption>(ptr);
|
|
|
|
if (options->options_.empty()) {
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultFailed>());
|
|
|
|
}
|
|
|
|
vector<td_api::object_ptr<td_api::reportChatSponsoredMessageOption>> report_options;
|
|
|
|
for (auto &option : options->options_) {
|
|
|
|
report_options.push_back(td_api::make_object<td_api::reportChatSponsoredMessageOption>(
|
|
|
|
option->option_.as_slice().str(), option->text_));
|
|
|
|
}
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultOptionRequired>(
|
|
|
|
options->title_, std::move(report_options)));
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_error(Status status) final {
|
|
|
|
if (status.message() == "AD_EXPIRED") {
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultFailed>());
|
|
|
|
}
|
|
|
|
if (status.message() == "PREMIUM_ACCOUNT_REQUIRED") {
|
|
|
|
return promise_.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultPremiumRequired>());
|
|
|
|
}
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->on_get_channel_error(channel_id_, status, "ReportSponsoredMessageQuery");
|
2024-03-28 16:24:39 +01:00
|
|
|
promise_.set_error(std::move(status));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
struct SponsoredMessageManager::SponsoredMessage {
|
2021-12-27 14:49:11 +01:00
|
|
|
int64 local_id = 0;
|
2022-05-07 11:12:16 +02:00
|
|
|
bool is_recommended = false;
|
2024-03-23 21:52:06 +01:00
|
|
|
bool can_be_reported = false;
|
2022-10-21 13:26:35 +02:00
|
|
|
bool show_dialog_photo = false;
|
2021-09-07 16:21:18 +02:00
|
|
|
DialogId sponsor_dialog_id;
|
2021-10-08 14:29:40 +02:00
|
|
|
ServerMessageId server_message_id;
|
2021-09-07 16:21:18 +02:00
|
|
|
string start_param;
|
2021-12-30 12:15:04 +01:00
|
|
|
string invite_hash;
|
2023-11-20 12:34:56 +01:00
|
|
|
WebApp web_app;
|
2021-09-07 16:21:18 +02:00
|
|
|
unique_ptr<MessageContent> content;
|
2023-11-17 13:06:20 +01:00
|
|
|
string button_text;
|
2023-02-24 14:02:45 +01:00
|
|
|
string sponsor_info;
|
|
|
|
string additional_info;
|
2023-06-02 14:13:20 +02:00
|
|
|
string site_url;
|
|
|
|
string site_name;
|
|
|
|
DialogPhoto site_photo;
|
2021-09-07 16:21:18 +02:00
|
|
|
|
2024-03-23 21:52:06 +01:00
|
|
|
SponsoredMessage(int64 local_id, bool is_recommended, bool can_be_reported, bool show_dialog_photo,
|
|
|
|
DialogId sponsor_dialog_id, ServerMessageId server_message_id, string start_param,
|
|
|
|
string invite_hash, WebApp web_app, unique_ptr<MessageContent> content, string button_text,
|
|
|
|
string sponsor_info, string additional_info, string site_url, string site_name,
|
|
|
|
DialogPhoto site_photo)
|
2021-09-10 10:44:50 +02:00
|
|
|
: local_id(local_id)
|
2022-05-07 11:12:16 +02:00
|
|
|
, is_recommended(is_recommended)
|
2024-03-23 21:52:06 +01:00
|
|
|
, can_be_reported(can_be_reported)
|
2022-10-21 13:26:35 +02:00
|
|
|
, show_dialog_photo(show_dialog_photo)
|
2021-09-07 16:21:18 +02:00
|
|
|
, sponsor_dialog_id(sponsor_dialog_id)
|
2021-10-08 14:29:40 +02:00
|
|
|
, server_message_id(server_message_id)
|
2021-09-07 16:21:18 +02:00
|
|
|
, start_param(std::move(start_param))
|
2021-12-30 12:15:04 +01:00
|
|
|
, invite_hash(std::move(invite_hash))
|
2023-11-20 12:34:56 +01:00
|
|
|
, web_app(std::move(web_app))
|
2023-02-24 14:02:45 +01:00
|
|
|
, content(std::move(content))
|
2023-11-17 13:06:20 +01:00
|
|
|
, button_text(std::move(button_text))
|
2023-02-24 14:02:45 +01:00
|
|
|
, sponsor_info(std::move(sponsor_info))
|
2023-06-02 14:13:20 +02:00
|
|
|
, additional_info(std::move(additional_info))
|
|
|
|
, site_url(std::move(site_url))
|
|
|
|
, site_name(std::move(site_name))
|
|
|
|
, site_photo(std::move(site_photo)) {
|
2021-09-07 16:21:18 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-05-04 16:33:35 +02:00
|
|
|
struct SponsoredMessageManager::SponsoredMessageInfo {
|
|
|
|
string random_id_;
|
|
|
|
bool is_viewed_ = false;
|
|
|
|
bool is_clicked_ = false;
|
|
|
|
};
|
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
struct SponsoredMessageManager::DialogSponsoredMessages {
|
2022-10-21 14:04:56 +02:00
|
|
|
vector<Promise<td_api::object_ptr<td_api::sponsoredMessages>>> promises;
|
2021-09-07 16:21:18 +02:00
|
|
|
vector<SponsoredMessage> messages;
|
2023-05-04 16:33:35 +02:00
|
|
|
FlatHashMap<int64, SponsoredMessageInfo> message_infos;
|
2022-10-21 14:04:56 +02:00
|
|
|
int32 messages_between = 0;
|
2022-10-21 14:51:32 +02:00
|
|
|
bool is_premium = false;
|
2021-09-07 16:21:18 +02:00
|
|
|
};
|
|
|
|
|
2021-09-07 14:49:34 +02:00
|
|
|
SponsoredMessageManager::SponsoredMessageManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
|
2021-09-07 19:27:04 +02:00
|
|
|
delete_cached_sponsored_messages_timeout_.set_callback(on_delete_cached_sponsored_messages_timeout_callback);
|
|
|
|
delete_cached_sponsored_messages_timeout_.set_callback_data(static_cast<void *>(this));
|
2021-09-07 14:49:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SponsoredMessageManager::~SponsoredMessageManager() = default;
|
|
|
|
|
|
|
|
void SponsoredMessageManager::tear_down() {
|
|
|
|
parent_.reset();
|
|
|
|
}
|
|
|
|
|
2021-09-07 19:27:04 +02:00
|
|
|
void SponsoredMessageManager::on_delete_cached_sponsored_messages_timeout_callback(void *sponsored_message_manager_ptr,
|
|
|
|
int64 dialog_id_int) {
|
|
|
|
if (G()->close_flag()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto sponsored_message_manager = static_cast<SponsoredMessageManager *>(sponsored_message_manager_ptr);
|
|
|
|
send_closure_later(sponsored_message_manager->actor_id(sponsored_message_manager),
|
|
|
|
&SponsoredMessageManager::delete_cached_sponsored_messages, DialogId(dialog_id_int));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SponsoredMessageManager::delete_cached_sponsored_messages(DialogId dialog_id) {
|
|
|
|
if (G()->close_flag()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = dialog_sponsored_messages_.find(dialog_id);
|
2022-10-21 14:51:32 +02:00
|
|
|
if (it != dialog_sponsored_messages_.end() && it->second->promises.empty()) {
|
|
|
|
dialog_sponsored_messages_.erase(it);
|
|
|
|
}
|
2021-09-07 19:27:04 +02:00
|
|
|
}
|
|
|
|
|
2023-06-02 13:42:28 +02:00
|
|
|
td_api::object_ptr<td_api::messageSponsor> SponsoredMessageManager::get_message_sponsor_object(
|
|
|
|
const SponsoredMessage &sponsored_message) const {
|
|
|
|
td_api::object_ptr<td_api::MessageSponsorType> type;
|
|
|
|
td_api::object_ptr<td_api::chatPhotoInfo> photo;
|
2021-10-08 14:00:13 +02:00
|
|
|
switch (sponsored_message.sponsor_dialog_id.get_type()) {
|
|
|
|
case DialogType::User: {
|
|
|
|
auto user_id = sponsored_message.sponsor_dialog_id.get_user_id();
|
2024-04-02 02:52:34 +02:00
|
|
|
if (!td_->user_manager_->is_user_bot(user_id)) {
|
2023-06-02 12:01:32 +02:00
|
|
|
LOG(ERROR) << "Sponsor " << user_id << " is not a bot";
|
|
|
|
return nullptr;
|
2021-10-08 14:00:13 +02:00
|
|
|
}
|
2024-04-02 02:52:34 +02:00
|
|
|
auto bot_username = td_->user_manager_->get_user_first_username(user_id);
|
2021-10-08 14:00:13 +02:00
|
|
|
if (bot_username.empty()) {
|
2023-06-02 12:01:32 +02:00
|
|
|
LOG(ERROR) << "Sponsor " << user_id << " has no username";
|
|
|
|
return nullptr;
|
2021-10-08 14:00:13 +02:00
|
|
|
}
|
2023-11-20 12:34:56 +01:00
|
|
|
if (!sponsored_message.web_app.is_empty()) {
|
|
|
|
type = sponsored_message.web_app.get_message_sponsor_type_web_app(bot_username, sponsored_message.start_param);
|
|
|
|
} else {
|
|
|
|
type = td_api::make_object<td_api::messageSponsorTypeBot>(
|
2024-04-02 02:52:34 +02:00
|
|
|
td_->user_manager_->get_user_id_object(user_id, "messageSponsorTypeBot"),
|
2023-11-20 12:34:56 +01:00
|
|
|
td_api::make_object<td_api::internalLinkTypeBotStart>(bot_username, sponsored_message.start_param, false));
|
|
|
|
}
|
2023-06-02 13:42:28 +02:00
|
|
|
if (sponsored_message.show_dialog_photo) {
|
2024-04-02 02:52:34 +02:00
|
|
|
photo =
|
|
|
|
get_chat_photo_info_object(td_->file_manager_.get(), td_->user_manager_->get_user_dialog_photo(user_id));
|
2023-06-02 13:42:28 +02:00
|
|
|
}
|
2021-10-08 14:00:13 +02:00
|
|
|
break;
|
|
|
|
}
|
2023-06-02 12:01:32 +02:00
|
|
|
case DialogType::Channel: {
|
|
|
|
auto channel_id = sponsored_message.sponsor_dialog_id.get_channel_id();
|
2024-04-02 12:06:22 +02:00
|
|
|
if (!td_->chat_manager_->is_broadcast_channel(channel_id)) {
|
2023-06-02 12:01:32 +02:00
|
|
|
LOG(ERROR) << "Sponsor " << channel_id << " is not a channel";
|
|
|
|
return nullptr;
|
|
|
|
}
|
2023-06-02 13:42:28 +02:00
|
|
|
td_api::object_ptr<td_api::InternalLinkType> link;
|
2021-11-27 11:36:17 +01:00
|
|
|
if (sponsored_message.server_message_id.is_valid()) {
|
|
|
|
link = td_api::make_object<td_api::internalLinkTypeMessage>(
|
2023-03-01 21:49:22 +01:00
|
|
|
PSTRING() << LinkManager::get_t_me_url() << "c/" << channel_id.get() << '/'
|
|
|
|
<< sponsored_message.server_message_id.get());
|
2021-11-27 11:36:17 +01:00
|
|
|
}
|
2023-06-02 13:42:28 +02:00
|
|
|
type = td_api::make_object<td_api::messageSponsorTypePublicChannel>(
|
2024-01-04 14:13:20 +01:00
|
|
|
td_->dialog_manager_->get_chat_id_object(sponsored_message.sponsor_dialog_id, "sponsoredMessage"),
|
2023-06-02 13:42:28 +02:00
|
|
|
std::move(link));
|
|
|
|
if (sponsored_message.show_dialog_photo) {
|
|
|
|
photo = get_chat_photo_info_object(td_->file_manager_.get(),
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->get_channel_dialog_photo(channel_id));
|
2023-06-02 13:42:28 +02:00
|
|
|
}
|
2021-10-08 14:29:40 +02:00
|
|
|
break;
|
2023-06-02 12:01:32 +02:00
|
|
|
}
|
2021-12-30 12:15:04 +01:00
|
|
|
case DialogType::None: {
|
2023-06-02 14:13:20 +02:00
|
|
|
if (sponsored_message.invite_hash.empty()) {
|
2023-11-20 12:34:56 +01:00
|
|
|
if (sponsored_message.site_url.empty()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2023-06-02 14:13:20 +02:00
|
|
|
type = td_api::make_object<td_api::messageSponsorTypeWebsite>(sponsored_message.site_url,
|
|
|
|
sponsored_message.site_name);
|
|
|
|
if (sponsored_message.show_dialog_photo) {
|
|
|
|
photo = get_chat_photo_info_object(td_->file_manager_.get(), &sponsored_message.site_photo);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-12-30 12:15:04 +01:00
|
|
|
auto invite_link = LinkManager::get_dialog_invite_link(sponsored_message.invite_hash, false);
|
2024-01-08 11:25:31 +01:00
|
|
|
auto chat_invite_link_info = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(invite_link);
|
2021-12-30 12:15:04 +01:00
|
|
|
if (chat_invite_link_info == nullptr) {
|
|
|
|
LOG(ERROR) << "Failed to get invite link info for " << invite_link;
|
|
|
|
return nullptr;
|
|
|
|
}
|
2023-09-11 17:33:44 +02:00
|
|
|
if (chat_invite_link_info->type_->get_id() != td_api::inviteLinkChatTypeChannel::ID) {
|
2023-06-02 12:01:32 +02:00
|
|
|
LOG(ERROR) << "Receive sponsor chat of a wrong type " << to_string(chat_invite_link_info->type_);
|
|
|
|
return nullptr;
|
|
|
|
}
|
2023-06-02 13:42:28 +02:00
|
|
|
type = td_api::make_object<td_api::messageSponsorTypePrivateChannel>(chat_invite_link_info->title_, invite_link);
|
|
|
|
if (sponsored_message.show_dialog_photo) {
|
|
|
|
photo = std::move(chat_invite_link_info->photo_);
|
|
|
|
}
|
|
|
|
break;
|
2021-12-30 12:15:04 +01:00
|
|
|
}
|
2021-10-08 14:00:13 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2023-06-02 13:42:28 +02:00
|
|
|
return td_api::make_object<td_api::messageSponsor>(std::move(type), std::move(photo), sponsored_message.sponsor_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
td_api::object_ptr<td_api::sponsoredMessage> SponsoredMessageManager::get_sponsored_message_object(
|
|
|
|
DialogId dialog_id, const SponsoredMessage &sponsored_message) const {
|
|
|
|
auto sponsor = get_message_sponsor_object(sponsored_message);
|
|
|
|
if (sponsor == nullptr) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-09-07 16:21:18 +02:00
|
|
|
return td_api::make_object<td_api::sponsoredMessage>(
|
2024-03-23 21:52:06 +01:00
|
|
|
sponsored_message.local_id, sponsored_message.is_recommended, sponsored_message.can_be_reported,
|
2023-11-01 19:55:12 +01:00
|
|
|
get_message_content_object(sponsored_message.content.get(), td_, dialog_id, 0, false, true, -1, false, false),
|
2023-11-17 13:06:20 +01:00
|
|
|
std::move(sponsor), sponsored_message.button_text, sponsored_message.additional_info);
|
2021-09-07 16:21:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-21 14:04:56 +02:00
|
|
|
td_api::object_ptr<td_api::sponsoredMessages> SponsoredMessageManager::get_sponsored_messages_object(
|
2021-09-07 16:21:18 +02:00
|
|
|
DialogId dialog_id, const DialogSponsoredMessages &sponsored_messages) const {
|
2022-10-21 14:04:56 +02:00
|
|
|
auto messages = transform(sponsored_messages.messages, [this, dialog_id](const SponsoredMessage &message) {
|
|
|
|
return get_sponsored_message_object(dialog_id, message);
|
|
|
|
});
|
2023-06-02 12:01:32 +02:00
|
|
|
td::remove_if(messages, [](const auto &message) { return message == nullptr; });
|
2022-10-21 14:04:56 +02:00
|
|
|
return td_api::make_object<td_api::sponsoredMessages>(std::move(messages), sponsored_messages.messages_between);
|
2021-09-07 16:21:18 +02:00
|
|
|
}
|
|
|
|
|
2022-10-21 14:04:56 +02:00
|
|
|
void SponsoredMessageManager::get_dialog_sponsored_messages(
|
|
|
|
DialogId dialog_id, Promise<td_api::object_ptr<td_api::sponsoredMessages>> &&promise) {
|
2024-01-04 13:26:42 +01:00
|
|
|
if (!td_->dialog_manager_->have_dialog_force(dialog_id, "get_dialog_sponsored_message")) {
|
2021-08-24 22:44:47 +02:00
|
|
|
return promise.set_error(Status::Error(400, "Chat not found"));
|
|
|
|
}
|
2022-04-04 14:48:33 +02:00
|
|
|
if (dialog_id.get_type() != DialogType::Channel) {
|
2022-10-21 14:04:56 +02:00
|
|
|
return promise.set_value(td_api::make_object<td_api::sponsoredMessages>());
|
2021-08-24 22:44:47 +02:00
|
|
|
}
|
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
auto &messages = dialog_sponsored_messages_[dialog_id];
|
2021-09-07 19:27:04 +02:00
|
|
|
if (messages != nullptr && messages->promises.empty()) {
|
2022-10-21 14:51:32 +02:00
|
|
|
if (messages->is_premium == td_->option_manager_->get_option_boolean("is_premium", false)) {
|
|
|
|
// use cached value
|
|
|
|
return promise.set_value(get_sponsored_messages_object(dialog_id, *messages));
|
|
|
|
} else {
|
|
|
|
// drop cache
|
|
|
|
messages = nullptr;
|
|
|
|
delete_cached_sponsored_messages_timeout_.cancel_timeout(dialog_id.get());
|
|
|
|
}
|
2021-09-07 19:27:04 +02:00
|
|
|
}
|
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
if (messages == nullptr) {
|
|
|
|
messages = make_unique<DialogSponsoredMessages>();
|
|
|
|
}
|
|
|
|
messages->promises.push_back(std::move(promise));
|
|
|
|
if (messages->promises.size() == 1) {
|
|
|
|
auto query_promise = PromiseCreator::lambda(
|
|
|
|
[actor_id = actor_id(this),
|
2022-10-07 17:04:00 +02:00
|
|
|
dialog_id](Result<telegram_api::object_ptr<telegram_api::messages_SponsoredMessages>> &&result) mutable {
|
2021-09-07 16:21:18 +02:00
|
|
|
send_closure(actor_id, &SponsoredMessageManager::on_get_dialog_sponsored_messages, dialog_id,
|
|
|
|
std::move(result));
|
|
|
|
});
|
|
|
|
td_->create_handler<GetSponsoredMessagesQuery>(std::move(query_promise))->send(dialog_id.get_channel_id());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SponsoredMessageManager::on_get_dialog_sponsored_messages(
|
2022-10-07 17:04:00 +02:00
|
|
|
DialogId dialog_id, Result<telegram_api::object_ptr<telegram_api::messages_SponsoredMessages>> &&result) {
|
2023-02-16 11:35:27 +01:00
|
|
|
G()->ignore_result_if_closing(result);
|
2022-08-10 12:57:41 +02:00
|
|
|
|
2021-09-07 16:21:18 +02:00
|
|
|
auto &messages = dialog_sponsored_messages_[dialog_id];
|
|
|
|
CHECK(messages != nullptr);
|
|
|
|
auto promises = std::move(messages->promises);
|
|
|
|
reset_to_empty(messages->promises);
|
2021-09-10 10:44:50 +02:00
|
|
|
CHECK(messages->messages.empty());
|
2023-05-04 16:33:35 +02:00
|
|
|
CHECK(messages->message_infos.empty());
|
2021-09-07 16:21:18 +02:00
|
|
|
|
|
|
|
if (result.is_error()) {
|
2021-09-07 19:27:04 +02:00
|
|
|
dialog_sponsored_messages_.erase(dialog_id);
|
2022-04-13 16:40:12 +02:00
|
|
|
fail_promises(promises, result.move_as_error());
|
2021-09-07 16:21:18 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-07 17:04:00 +02:00
|
|
|
auto sponsored_messages_ptr = result.move_as_ok();
|
|
|
|
switch (sponsored_messages_ptr->get_id()) {
|
|
|
|
case telegram_api::messages_sponsoredMessages::ID: {
|
|
|
|
auto sponsored_messages =
|
|
|
|
telegram_api::move_object_as<telegram_api::messages_sponsoredMessages>(sponsored_messages_ptr);
|
|
|
|
|
2024-04-02 02:52:34 +02:00
|
|
|
td_->user_manager_->on_get_users(std::move(sponsored_messages->users_), "on_get_dialog_sponsored_messages");
|
2024-04-02 12:06:22 +02:00
|
|
|
td_->chat_manager_->on_get_chats(std::move(sponsored_messages->chats_), "on_get_dialog_sponsored_messages");
|
2024-04-21 20:57:10 +02:00
|
|
|
/*
|
2022-10-07 17:04:00 +02:00
|
|
|
for (auto &sponsored_message : sponsored_messages->messages_) {
|
|
|
|
DialogId sponsor_dialog_id;
|
|
|
|
ServerMessageId server_message_id;
|
|
|
|
string invite_hash;
|
2023-06-02 14:13:20 +02:00
|
|
|
string site_url;
|
|
|
|
string site_name;
|
|
|
|
DialogPhoto site_photo;
|
2022-10-07 17:04:00 +02:00
|
|
|
if (sponsored_message->from_id_ != nullptr) {
|
|
|
|
sponsor_dialog_id = DialogId(sponsored_message->from_id_);
|
2023-08-26 04:00:15 +02:00
|
|
|
if (!sponsor_dialog_id.is_valid() ||
|
2024-01-03 21:07:50 +01:00
|
|
|
!td_->dialog_manager_->have_dialog_info_force(sponsor_dialog_id, "on_get_dialog_sponsored_messages")) {
|
2022-10-07 17:04:00 +02:00
|
|
|
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();
|
|
|
|
}
|
2024-01-04 13:38:01 +01:00
|
|
|
td_->dialog_manager_->force_create_dialog(sponsor_dialog_id, "on_get_dialog_sponsored_messages");
|
2022-10-07 17:04:00 +02:00
|
|
|
} 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_);
|
2024-01-08 11:25:31 +01:00
|
|
|
td_->dialog_invite_link_manager_->on_get_dialog_invite_link_info(
|
2022-10-07 17:04:00 +02:00
|
|
|
invite_link, std::move(sponsored_message->chat_invite_), Promise<Unit>());
|
2024-01-08 11:25:31 +01:00
|
|
|
auto chat_invite_link_info = td_->dialog_invite_link_manager_->get_chat_invite_link_info_object(invite_link);
|
2022-10-07 17:04:00 +02:00
|
|
|
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_);
|
2023-06-02 14:13:20 +02:00
|
|
|
} else if (sponsored_message->webpage_ != nullptr && !sponsored_message->webpage_->url_.empty()) {
|
|
|
|
site_url = std::move(sponsored_message->webpage_->url_);
|
|
|
|
site_name = std::move(sponsored_message->webpage_->site_name_);
|
|
|
|
if (sponsored_message->webpage_->photo_ != nullptr) {
|
|
|
|
auto photo = get_photo(td_, std::move(sponsored_message->webpage_->photo_), DialogId());
|
|
|
|
site_photo = as_fake_dialog_photo(photo, DialogId(), false);
|
|
|
|
}
|
2022-10-07 17:04:00 +02:00
|
|
|
} else {
|
|
|
|
LOG(ERROR) << "Receive " << to_string(sponsored_message);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-04-02 02:52:34 +02:00
|
|
|
auto message_text = get_message_text(td_->user_manager_.get(), std::move(sponsored_message->message_),
|
2022-10-07 17:04:00 +02:00
|
|
|
std::move(sponsored_message->entities_), true, true, 0, false,
|
|
|
|
"on_get_dialog_sponsored_messages");
|
2024-01-30 13:07:21 +01:00
|
|
|
MessageSelfDestructType ttl;
|
2024-02-02 11:38:40 +01:00
|
|
|
auto content = get_message_content(td_, std::move(message_text), nullptr, sponsor_dialog_id, G()->unix_time(),
|
|
|
|
true, UserId(), &ttl, nullptr, "on_get_dialog_sponsored_messages");
|
2024-01-30 13:07:21 +01:00
|
|
|
if (!ttl.is_empty()) {
|
|
|
|
LOG(ERROR) << "Receive sponsored message with " << ttl;
|
2022-10-07 17:04:00 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
current_sponsored_message_id_ = current_sponsored_message_id_.get_next_message_id(MessageType::Local);
|
|
|
|
if (!current_sponsored_message_id_.is_valid_sponsored()) {
|
2023-06-02 14:13:20 +02:00
|
|
|
LOG(ERROR) << "Sponsored message identifier overflowed";
|
2022-10-07 17:04:00 +02:00
|
|
|
current_sponsored_message_id_ = MessageId::max().get_next_message_id(MessageType::Local);
|
|
|
|
CHECK(current_sponsored_message_id_.is_valid_sponsored());
|
|
|
|
}
|
|
|
|
auto local_id = current_sponsored_message_id_.get();
|
|
|
|
CHECK(!current_sponsored_message_id_.is_valid());
|
|
|
|
CHECK(!current_sponsored_message_id_.is_scheduled());
|
2023-05-04 16:33:35 +02:00
|
|
|
SponsoredMessageInfo message_info;
|
|
|
|
message_info.random_id_ = sponsored_message->random_id_.as_slice().str();
|
|
|
|
auto is_inserted = messages->message_infos.emplace(local_id, std::move(message_info)).second;
|
2022-10-07 17:04:00 +02:00
|
|
|
CHECK(is_inserted);
|
2023-11-20 12:34:56 +01:00
|
|
|
WebApp web_app;
|
|
|
|
if (sponsored_message->app_ != nullptr && sponsored_message->app_->get_id() == telegram_api::botApp::ID) {
|
|
|
|
web_app = WebApp(td_, telegram_api::move_object_as<telegram_api::botApp>(sponsored_message->app_), dialog_id);
|
|
|
|
}
|
2022-10-21 13:26:35 +02:00
|
|
|
messages->messages.emplace_back(
|
2024-03-23 21:52:06 +01:00
|
|
|
local_id, sponsored_message->recommended_, sponsored_message->can_report_,
|
|
|
|
sponsored_message->show_peer_photo_, sponsor_dialog_id, server_message_id,
|
|
|
|
std::move(sponsored_message->start_param_), std::move(invite_hash), std::move(web_app), std::move(content),
|
|
|
|
std::move(sponsored_message->button_text_), std::move(sponsored_message->sponsor_info_),
|
2023-11-17 13:06:20 +01:00
|
|
|
std::move(sponsored_message->additional_info_), std::move(site_url), std::move(site_name),
|
|
|
|
std::move(site_photo));
|
2021-12-30 12:15:04 +01:00
|
|
|
}
|
2024-04-21 20:57:10 +02:00
|
|
|
*/
|
2022-10-21 14:04:56 +02:00
|
|
|
messages->messages_between = sponsored_messages->posts_between_;
|
|
|
|
break;
|
2021-12-28 15:19:18 +01:00
|
|
|
}
|
2022-10-07 17:04:00 +02:00
|
|
|
case telegram_api::messages_sponsoredMessagesEmpty::ID:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
2021-09-07 16:21:18 +02:00
|
|
|
}
|
2022-10-21 14:51:32 +02:00
|
|
|
messages->is_premium = td_->option_manager_->get_option_boolean("is_premium", false);
|
2021-09-07 16:21:18 +02:00
|
|
|
|
|
|
|
for (auto &promise : promises) {
|
2022-10-21 14:04:56 +02:00
|
|
|
promise.set_value(get_sponsored_messages_object(dialog_id, *messages));
|
2021-09-07 16:21:18 +02:00
|
|
|
}
|
2021-09-07 19:27:04 +02:00
|
|
|
delete_cached_sponsored_messages_timeout_.set_timeout_in(dialog_id.get(), 300.0);
|
2021-08-24 22:44:47 +02:00
|
|
|
}
|
|
|
|
|
2021-12-27 16:17:02 +01:00
|
|
|
void SponsoredMessageManager::view_sponsored_message(DialogId dialog_id, MessageId sponsored_message_id) {
|
2021-09-10 10:44:50 +02:00
|
|
|
auto it = dialog_sponsored_messages_.find(dialog_id);
|
|
|
|
if (it == dialog_sponsored_messages_.end()) {
|
2021-12-27 16:17:02 +01:00
|
|
|
return;
|
2021-09-10 10:44:50 +02:00
|
|
|
}
|
2023-05-04 16:33:35 +02:00
|
|
|
auto random_id_it = it->second->message_infos.find(sponsored_message_id.get());
|
|
|
|
if (random_id_it == it->second->message_infos.end() || random_id_it->second.is_viewed_) {
|
2021-12-27 16:17:02 +01:00
|
|
|
return;
|
2021-08-25 21:34:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 16:33:35 +02:00
|
|
|
random_id_it->second.is_viewed_ = true;
|
|
|
|
td_->create_handler<ViewSponsoredMessageQuery>()->send(dialog_id.get_channel_id(), random_id_it->second.random_id_);
|
2021-08-25 21:34:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 16:21:50 +02:00
|
|
|
void SponsoredMessageManager::click_sponsored_message(DialogId dialog_id, MessageId sponsored_message_id,
|
|
|
|
Promise<Unit> &&promise) {
|
|
|
|
if (!dialog_id.is_valid() || !sponsored_message_id.is_valid_sponsored()) {
|
|
|
|
return promise.set_error(Status::Error(400, "Invalid message specified"));
|
|
|
|
}
|
|
|
|
auto it = dialog_sponsored_messages_.find(dialog_id);
|
|
|
|
if (it == dialog_sponsored_messages_.end()) {
|
|
|
|
return promise.set_value(Unit());
|
|
|
|
}
|
2023-05-04 16:33:35 +02:00
|
|
|
auto random_id_it = it->second->message_infos.find(sponsored_message_id.get());
|
|
|
|
if (random_id_it == it->second->message_infos.end() || random_id_it->second.is_clicked_) {
|
2023-05-04 16:21:50 +02:00
|
|
|
return promise.set_value(Unit());
|
|
|
|
}
|
|
|
|
|
2023-05-04 16:33:35 +02:00
|
|
|
random_id_it->second.is_clicked_ = true;
|
|
|
|
td_->create_handler<ClickSponsoredMessageQuery>(std::move(promise))
|
|
|
|
->send(dialog_id.get_channel_id(), random_id_it->second.random_id_);
|
2023-05-04 16:21:50 +02:00
|
|
|
}
|
|
|
|
|
2024-03-28 16:24:39 +01:00
|
|
|
void SponsoredMessageManager::report_sponsored_message(
|
|
|
|
DialogId dialog_id, MessageId sponsored_message_id, const string &option_id,
|
|
|
|
Promise<td_api::object_ptr<td_api::ReportChatSponsoredMessageResult>> &&promise) {
|
|
|
|
if (!dialog_id.is_valid() || !sponsored_message_id.is_valid_sponsored()) {
|
|
|
|
return promise.set_error(Status::Error(400, "Invalid message specified"));
|
|
|
|
}
|
|
|
|
auto it = dialog_sponsored_messages_.find(dialog_id);
|
|
|
|
if (it == dialog_sponsored_messages_.end()) {
|
|
|
|
return promise.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultFailed>());
|
|
|
|
}
|
|
|
|
auto random_id_it = it->second->message_infos.find(sponsored_message_id.get());
|
|
|
|
if (random_id_it == it->second->message_infos.end()) {
|
|
|
|
return promise.set_value(td_api::make_object<td_api::reportChatSponsoredMessageResultFailed>());
|
|
|
|
}
|
|
|
|
|
|
|
|
td_->create_handler<ReportSponsoredMessageQuery>(std::move(promise))
|
|
|
|
->send(dialog_id.get_channel_id(), random_id_it->second.random_id_, option_id);
|
|
|
|
}
|
|
|
|
|
2021-08-24 22:44:47 +02:00
|
|
|
} // namespace td
|