Partly move report_dialog to DialogManager.

This commit is contained in:
levlam 2024-01-04 22:46:13 +03:00
parent c24bd49cce
commit 884a16f1ed
5 changed files with 253 additions and 233 deletions

View File

@ -13,9 +13,11 @@
#include "td/telegram/ContactsManager.h"
#include "td/telegram/FileReferenceManager.h"
#include "td/telegram/files/FileManager.h"
#include "td/telegram/files/FileType.h"
#include "td/telegram/Global.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/ReportReason.h"
#include "td/telegram/SecretChatId.h"
#include "td/telegram/StickerPhotoSize.h"
#include "td/telegram/Td.h"
@ -246,6 +248,118 @@ class ToggleNoForwardsQuery final : public Td::ResultHandler {
}
};
class ReportPeerQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit ReportPeerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&report_reason) {
dialog_id_ = dialog_id;
auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
if (message_ids.empty()) {
send_query(G()->net_query_creator().create(telegram_api::account_reportPeer(
std::move(input_peer), report_reason.get_input_report_reason(), report_reason.get_message())));
} else {
send_query(G()->net_query_creator().create(
telegram_api::messages_report(std::move(input_peer), MessageId::get_server_message_ids(message_ids),
report_reason.get_input_report_reason(), report_reason.get_message())));
}
}
void on_result(BufferSlice packet) final {
static_assert(
std::is_same<telegram_api::account_reportPeer::ReturnType, telegram_api::messages_report::ReturnType>::value,
"");
auto result_ptr = fetch_result<telegram_api::account_reportPeer>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.ok();
if (!result) {
return on_error(Status::Error(400, "Receive false as result"));
}
promise_.set_value(Unit());
}
void on_error(Status status) final {
td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "ReportPeerQuery");
td_->messages_manager_->reget_dialog_action_bar(dialog_id_, "ReportPeerQuery");
promise_.set_error(std::move(status));
}
};
class ReportProfilePhotoQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
FileId file_id_;
string file_reference_;
ReportReason report_reason_;
public:
explicit ReportProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, FileId file_id, tl_object_ptr<telegram_api::InputPhoto> &&input_photo,
ReportReason &&report_reason) {
dialog_id_ = dialog_id;
file_id_ = file_id;
file_reference_ = FileManager::extract_file_reference(input_photo);
report_reason_ = std::move(report_reason);
auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::account_reportProfilePhoto(
std::move(input_peer), std::move(input_photo), report_reason_.get_input_report_reason(),
report_reason_.get_message())));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_reportProfilePhoto>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.ok();
if (!result) {
return on_error(Status::Error(400, "Receive false as result"));
}
promise_.set_value(Unit());
}
void on_error(Status status) final {
LOG(INFO) << "Receive error for report chat photo: " << status;
if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td_->file_manager_->delete_file_reference(file_id_, file_reference_);
td_->file_reference_manager_->repair_file_reference(
file_id_,
PromiseCreator::lambda([dialog_id = dialog_id_, file_id = file_id_, report_reason = std::move(report_reason_),
promise = std::move(promise_)](Result<Unit> result) mutable {
if (result.is_error()) {
LOG(INFO) << "Reported photo " << file_id << " is likely to be deleted";
return promise.set_value(Unit());
}
send_closure(G()->dialog_manager(), &DialogManager::report_dialog_photo, dialog_id, file_id,
std::move(report_reason), std::move(promise));
}));
return;
}
td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "ReportProfilePhotoQuery");
promise_.set_error(std::move(status));
}
};
class DialogManager::UploadDialogPhotoCallback final : public FileManager::UploadCallback {
public:
void on_upload_ok(FileId file_id, telegram_api::object_ptr<telegram_api::InputFile> input_file) final {
@ -1329,6 +1443,95 @@ void DialogManager::set_dialog_description(DialogId dialog_id, const string &des
}
}
bool DialogManager::can_report_dialog(DialogId dialog_id) const {
// doesn't include possibility of report from action bar
switch (dialog_id.get_type()) {
case DialogType::User:
return td_->contacts_manager_->can_report_user(dialog_id.get_user_id());
case DialogType::Chat:
return false;
case DialogType::Channel:
return !td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).is_creator();
case DialogType::SecretChat:
return false;
case DialogType::None:
default:
UNREACHABLE();
return false;
}
}
void DialogManager::report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
Promise<Unit> &&promise) {
if (!have_dialog_force(dialog_id, "report_dialog")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
MessagesManager::ReportDialogFromActionBar report_from_action_bar;
if (reason.is_spam() && message_ids.empty()) {
// can be a report from action bar
report_from_action_bar = td_->messages_manager_->report_dialog_from_action_bar(dialog_id, promise);
if (report_from_action_bar.is_reported_) {
return;
}
}
if (!can_report_dialog(dialog_id)) {
if (report_from_action_bar.know_action_bar_) {
return promise.set_value(Unit());
}
return promise.set_error(Status::Error(400, "Chat can't be reported"));
}
vector<MessageId> server_message_ids;
for (auto message_id : message_ids) {
if (message_id.is_scheduled()) {
return promise.set_error(Status::Error(400, "Can't report scheduled messages"));
}
if (message_id.is_valid() && message_id.is_server()) {
server_message_ids.push_back(message_id);
}
}
if (dialog_id.get_type() == DialogType::Channel && reason.is_unrelated_location()) {
td_->messages_manager_->hide_dialog_action_bar(dialog_id);
}
td_->create_handler<ReportPeerQuery>(std::move(promise))->send(dialog_id, server_message_ids, std::move(reason));
}
void DialogManager::report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason,
Promise<Unit> &&promise) {
if (!have_dialog_force(dialog_id, "report_dialog_photo")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (!have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
if (!can_report_dialog(dialog_id)) {
return promise.set_error(Status::Error(400, "Chat photo can't be reported"));
}
auto file_view = td_->file_manager_->get_file_view(file_id);
if (file_view.empty()) {
return promise.set_error(Status::Error(400, "Unknown file identifier"));
}
if (get_main_file_type(file_view.get_type()) != FileType::Photo || !file_view.has_remote_location() ||
!file_view.remote_location().is_photo()) {
return promise.set_error(Status::Error(400, "Only full chat photos can be reported"));
}
td_->create_handler<ReportProfilePhotoQuery>(std::move(promise))
->send(dialog_id, file_id, file_view.remote_location().as_input_photo(), std::move(reason));
}
Status DialogManager::can_pin_messages(DialogId dialog_id) const {
switch (dialog_id.get_type()) {
case DialogType::User:

View File

@ -14,6 +14,7 @@
#include "td/telegram/EmojiStatus.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/InputDialogId.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/NotificationSettingsScope.h"
#include "td/telegram/Photo.h"
#include "td/telegram/td_api.h"
@ -30,6 +31,7 @@
namespace td {
class ReportReason;
class Td;
class DialogManager final : public Actor {
@ -140,6 +142,13 @@ class DialogManager final : public Actor {
void set_dialog_description(DialogId dialog_id, const string &description, Promise<Unit> &&promise);
bool can_report_dialog(DialogId dialog_id) const;
void report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
Promise<Unit> &&promise);
void report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason, Promise<Unit> &&promise);
Status can_pin_messages(DialogId dialog_id) const;
bool is_dialog_removed_from_dialog_list(DialogId dialog_id) const;

View File

@ -68,7 +68,6 @@
#include "td/telegram/RepliedMessageInfo.hpp"
#include "td/telegram/ReplyMarkup.h"
#include "td/telegram/ReplyMarkup.hpp"
#include "td/telegram/ReportReason.h"
#include "td/telegram/SecretChatsManager.h"
#include "td/telegram/SponsoredMessageManager.h"
#include "td/telegram/StickerType.h"
@ -4083,118 +4082,6 @@ class ReportEncryptedSpamQuery final : public Td::ResultHandler {
}
};
class ReportPeerQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
public:
explicit ReportPeerQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&report_reason) {
dialog_id_ = dialog_id;
auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
if (message_ids.empty()) {
send_query(G()->net_query_creator().create(telegram_api::account_reportPeer(
std::move(input_peer), report_reason.get_input_report_reason(), report_reason.get_message())));
} else {
send_query(G()->net_query_creator().create(
telegram_api::messages_report(std::move(input_peer), MessageId::get_server_message_ids(message_ids),
report_reason.get_input_report_reason(), report_reason.get_message())));
}
}
void on_result(BufferSlice packet) final {
static_assert(
std::is_same<telegram_api::account_reportPeer::ReturnType, telegram_api::messages_report::ReturnType>::value,
"");
auto result_ptr = fetch_result<telegram_api::account_reportPeer>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.ok();
if (!result) {
return on_error(Status::Error(400, "Receive false as result"));
}
promise_.set_value(Unit());
}
void on_error(Status status) final {
td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "ReportPeerQuery");
td_->messages_manager_->reget_dialog_action_bar(dialog_id_, "ReportPeerQuery");
promise_.set_error(std::move(status));
}
};
class ReportProfilePhotoQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
FileId file_id_;
string file_reference_;
ReportReason report_reason_;
public:
explicit ReportProfilePhotoQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(DialogId dialog_id, FileId file_id, tl_object_ptr<telegram_api::InputPhoto> &&input_photo,
ReportReason &&report_reason) {
dialog_id_ = dialog_id;
file_id_ = file_id;
file_reference_ = FileManager::extract_file_reference(input_photo);
report_reason_ = std::move(report_reason);
auto input_peer = td_->dialog_manager_->get_input_peer(dialog_id, AccessRights::Read);
CHECK(input_peer != nullptr);
send_query(G()->net_query_creator().create(telegram_api::account_reportProfilePhoto(
std::move(input_peer), std::move(input_photo), report_reason_.get_input_report_reason(),
report_reason_.get_message())));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::account_reportProfilePhoto>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
bool result = result_ptr.ok();
if (!result) {
return on_error(Status::Error(400, "Receive false as result"));
}
promise_.set_value(Unit());
}
void on_error(Status status) final {
LOG(INFO) << "Receive error for report chat photo: " << status;
if (!td_->auth_manager_->is_bot() && FileReferenceManager::is_file_reference_error(status)) {
VLOG(file_references) << "Receive " << status << " for " << file_id_;
td_->file_manager_->delete_file_reference(file_id_, file_reference_);
td_->file_reference_manager_->repair_file_reference(
file_id_,
PromiseCreator::lambda([dialog_id = dialog_id_, file_id = file_id_, report_reason = std::move(report_reason_),
promise = std::move(promise_)](Result<Unit> result) mutable {
if (result.is_error()) {
LOG(INFO) << "Reported photo " << file_id << " is likely to be deleted";
return promise.set_value(Unit());
}
send_closure(G()->messages_manager(), &MessagesManager::report_dialog_photo, dialog_id, file_id,
std::move(report_reason), std::move(promise));
}));
return;
}
td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "ReportProfilePhotoQuery");
promise_.set_error(std::move(status));
}
};
class EditPeerFoldersQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
@ -8366,109 +8253,6 @@ void MessagesManager::toggle_dialog_report_spam_state_on_server(DialogId dialog_
}
}
bool MessagesManager::can_report_dialog(DialogId dialog_id) const {
// doesn't include possibility of report from action bar
switch (dialog_id.get_type()) {
case DialogType::User:
return td_->contacts_manager_->can_report_user(dialog_id.get_user_id());
case DialogType::Chat:
return false;
case DialogType::Channel:
return !td_->contacts_manager_->get_channel_status(dialog_id.get_channel_id()).is_creator();
case DialogType::SecretChat:
return false;
case DialogType::None:
default:
UNREACHABLE();
return false;
}
}
void MessagesManager::report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(dialog_id, "report_dialog");
if (d == nullptr) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (!td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
Dialog *user_d = d;
bool is_dialog_spam_report = false;
bool can_report_spam = false;
if (reason.is_spam() && message_ids.empty()) {
// report from action bar
if (dialog_id.get_type() == DialogType::SecretChat) {
auto user_dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
user_d = get_dialog_force(user_dialog_id, "report_dialog 2");
if (user_d == nullptr) {
return promise.set_error(Status::Error(400, "Chat with the user not found"));
}
}
is_dialog_spam_report = user_d->know_action_bar;
can_report_spam = user_d->action_bar != nullptr && user_d->action_bar->can_report_spam();
}
if (is_dialog_spam_report && can_report_spam) {
hide_dialog_action_bar(user_d);
return toggle_dialog_report_spam_state_on_server(dialog_id, true, 0, std::move(promise));
}
if (!can_report_dialog(dialog_id)) {
if (is_dialog_spam_report) {
return promise.set_value(Unit());
}
return promise.set_error(Status::Error(400, "Chat can't be reported"));
}
vector<MessageId> server_message_ids;
for (auto message_id : message_ids) {
if (message_id.is_scheduled()) {
return promise.set_error(Status::Error(400, "Can't report scheduled messages"));
}
if (message_id.is_valid() && message_id.is_server()) {
server_message_ids.push_back(message_id);
}
}
if (dialog_id.get_type() == DialogType::Channel && reason.is_unrelated_location()) {
hide_dialog_action_bar(d);
}
td_->create_handler<ReportPeerQuery>(std::move(promise))->send(dialog_id, server_message_ids, std::move(reason));
}
void MessagesManager::report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason,
Promise<Unit> &&promise) {
Dialog *d = get_dialog_force(dialog_id, "report_dialog_photo");
if (d == nullptr) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (!td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
return promise.set_error(Status::Error(400, "Can't access the chat"));
}
if (!can_report_dialog(dialog_id)) {
return promise.set_error(Status::Error(400, "Chat photo can't be reported"));
}
auto file_view = td_->file_manager_->get_file_view(file_id);
if (file_view.empty()) {
return promise.set_error(Status::Error(400, "Unknown file ID"));
}
if (get_main_file_type(file_view.get_type()) != FileType::Photo || !file_view.has_remote_location() ||
!file_view.remote_location().is_photo()) {
return promise.set_error(Status::Error(400, "Only full chat photos can be reported"));
}
td_->create_handler<ReportProfilePhotoQuery>(std::move(promise))
->send(dialog_id, file_id, file_view.remote_location().as_input_photo(), std::move(reason));
}
void MessagesManager::on_get_peer_settings(DialogId dialog_id,
tl_object_ptr<telegram_api::peerSettings> &&peer_settings,
bool ignore_privacy_exception) {
@ -17691,6 +17475,32 @@ bool MessagesManager::is_message_edited_recently(MessageFullId message_full_id,
return m->edit_date >= G()->unix_time() - seconds;
}
MessagesManager::ReportDialogFromActionBar MessagesManager::report_dialog_from_action_bar(DialogId dialog_id,
Promise<Unit> &promise) {
ReportDialogFromActionBar result;
Dialog *d = nullptr;
if (dialog_id.get_type() == DialogType::SecretChat) {
auto user_dialog_id = DialogId(td_->contacts_manager_->get_secret_chat_user_id(dialog_id.get_secret_chat_id()));
d = get_dialog_force(user_dialog_id, "report_dialog_from_action_bar");
if (d == nullptr) {
promise.set_error(Status::Error(400, "Chat with the user not found"));
result.is_reported_ = true;
return result;
}
} else {
d = get_dialog(dialog_id);
CHECK(d != nullptr);
}
result.know_action_bar_ = d->know_action_bar;
if (d->know_action_bar && d->action_bar != nullptr && d->action_bar->can_report_spam()) {
result.is_reported_ = true;
hide_dialog_action_bar(d);
toggle_dialog_report_spam_state_on_server(dialog_id, true, 0, std::move(promise));
}
return result;
}
Status MessagesManager::can_get_media_timestamp_link(DialogId dialog_id, const Message *m) {
if (m == nullptr) {
return Status::Error(400, "Message not found");
@ -19947,11 +19757,11 @@ td_api::object_ptr<td_api::chat> MessagesManager::get_chat_object(const Dialog *
get_chat_positions_object(d), get_default_message_sender_object(d), block_list_id.get_block_list_object(),
td_->dialog_manager_->get_dialog_has_protected_content(d->dialog_id), is_translatable, d->is_marked_as_unread,
get_dialog_view_as_topics(d), get_dialog_has_scheduled_messages(d), can_delete.for_self_,
can_delete.for_all_users_, can_report_dialog(d->dialog_id), d->notification_settings.silent_send_message,
d->server_unread_count + d->local_unread_count, d->last_read_inbox_message_id.get(),
d->last_read_outbox_message_id.get(), d->unread_mention_count, d->unread_reaction_count,
get_chat_notification_settings_object(&d->notification_settings), std::move(available_reactions),
d->message_ttl.get_message_auto_delete_time_object(),
can_delete.for_all_users_, td_->dialog_manager_->can_report_dialog(d->dialog_id),
d->notification_settings.silent_send_message, d->server_unread_count + d->local_unread_count,
d->last_read_inbox_message_id.get(), d->last_read_outbox_message_id.get(), d->unread_mention_count,
d->unread_reaction_count, get_chat_notification_settings_object(&d->notification_settings),
std::move(available_reactions), d->message_ttl.get_message_auto_delete_time_object(),
td_->dialog_manager_->get_dialog_emoji_status_object(d->dialog_id), get_chat_background_object(d),
get_dialog_theme_name(d), get_chat_action_bar_object(d), get_video_chat_object(d),
get_chat_join_requests_info_object(d), d->reply_markup_message_id.get(), std::move(draft_message),

View File

@ -111,7 +111,6 @@ class DraftMessage;
struct InputMessageContent;
class MessageContent;
struct MessageReactions;
class ReportReason;
class Td;
class MessagesManager final : public Actor {
@ -611,6 +610,12 @@ class MessagesManager final : public Actor {
bool is_message_edited_recently(MessageFullId message_full_id, int32 seconds);
struct ReportDialogFromActionBar {
bool know_action_bar_ = false;
bool is_reported_ = false;
};
ReportDialogFromActionBar report_dialog_from_action_bar(DialogId dialog_id, Promise<Unit> &promise);
bool is_deleted_secret_chat(DialogId dialog_id) const;
Result<std::pair<string, bool>> get_message_link(MessageFullId message_full_id, int32 media_timestamp, bool for_group,
@ -851,11 +856,6 @@ class MessagesManager final : public Actor {
void reget_dialog_action_bar(DialogId dialog_id, const char *source, bool is_repair = true);
void report_dialog(DialogId dialog_id, const vector<MessageId> &message_ids, ReportReason &&reason,
Promise<Unit> &&promise);
void report_dialog_photo(DialogId dialog_id, FileId file_id, ReportReason &&reason, Promise<Unit> &&promise);
void on_get_peer_settings(DialogId dialog_id, tl_object_ptr<telegram_api::peerSettings> &&peer_settings,
bool ignore_privacy_exception = false);
@ -1752,8 +1752,6 @@ class MessagesManager final : public Actor {
bool can_edit_message(DialogId dialog_id, const Message *m, bool is_editing, bool only_reply_markup = false) const;
bool can_report_dialog(DialogId dialog_id) const;
static Status can_get_media_timestamp_link(DialogId dialog_id, const Message *m);
bool can_report_message_reactions(DialogId dialog_id, const Message *m) const;

View File

@ -8239,7 +8239,7 @@ void Td::on_request(uint64 id, td_api::reportChat &request) {
return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message());
}
CREATE_OK_REQUEST_PROMISE();
messages_manager_->report_dialog(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_),
dialog_manager_->report_dialog(DialogId(request.chat_id_), MessageId::get_message_ids(request.message_ids_),
r_report_reason.move_as_ok(), std::move(promise));
}
@ -8250,7 +8250,7 @@ void Td::on_request(uint64 id, td_api::reportChatPhoto &request) {
return send_error_raw(id, r_report_reason.error().code(), r_report_reason.error().message());
}
CREATE_OK_REQUEST_PROMISE();
messages_manager_->report_dialog_photo(DialogId(request.chat_id_), FileId(request.file_id_, 0),
dialog_manager_->report_dialog_photo(DialogId(request.chat_id_), FileId(request.file_id_, 0),
r_report_reason.move_as_ok(), std::move(promise));
}