From 07a29ef56b45466b32b313ce5f53696509deed52 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 23 Mar 2024 23:15:04 +0300 Subject: [PATCH] Move chat suggested actions to DialogManager. --- td/telegram/ContactsManager.cpp | 150 +++++--------------------------- td/telegram/ContactsManager.h | 12 +-- td/telegram/DialogManager.cpp | 117 +++++++++++++++++++++++++ td/telegram/DialogManager.h | 12 +++ td/telegram/SuggestedAction.cpp | 4 +- 5 files changed, 155 insertions(+), 140 deletions(-) diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9e48fc738..a3fb80f42 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -59,6 +59,7 @@ #include "td/telegram/StickerPhotoSize.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StoryManager.h" +#include "td/telegram/SuggestedAction.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" #include "td/telegram/telegram_api.h" @@ -96,38 +97,6 @@ namespace td { -class DismissSuggestionQuery final : public Td::ResultHandler { - Promise promise_; - DialogId dialog_id_; - - public: - explicit DismissSuggestionQuery(Promise &&promise) : promise_(std::move(promise)) { - } - - void send(SuggestedAction action) { - dialog_id_ = action.dialog_id_; - 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::help_dismissSuggestion(std::move(input_peer), action.get_suggested_action_str()))); - } - - void on_result(BufferSlice packet) final { - auto result_ptr = fetch_result(packet); - if (result_ptr.is_error()) { - return on_error(result_ptr.move_as_error()); - } - - promise_.set_value(Unit()); - } - - void on_error(Status status) final { - td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "DismissSuggestionQuery"); - promise_.set_error(std::move(status)); - } -}; - class GetContactsQuery final : public Td::ResultHandler { public: void send(int64 hash) { @@ -6787,18 +6756,12 @@ void ContactsManager::toggle_channel_is_forum(ChannelId channel_id, bool is_foru } void ContactsManager::convert_channel_to_gigagroup(ChannelId channel_id, Promise &&promise) { - auto c = get_channel(channel_id); - if (c == nullptr) { - return promise.set_error(Status::Error(400, "Supergroup not found")); - } - if (!get_channel_status(c).is_creator()) { - return promise.set_error(Status::Error(400, "Not enough rights to convert group to broadcast group")); - } - if (get_channel_type(c) != ChannelType::Megagroup) { - return promise.set_error(Status::Error(400, "Chat must be a supergroup")); + if (!can_convert_channel_to_gigagroup(channel_id)) { + return promise.set_error(Status::Error(400, "Can't convert the chat to a broadcast group")); } - remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); + td_->dialog_manager_->remove_dialog_suggested_action( + SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); td_->create_handler(std::move(promise))->send(channel_id); } @@ -7019,6 +6982,15 @@ bool ContactsManager::can_get_channel_story_statistics(ChannelId channel_id) con return c->status.can_post_messages(); } +bool ContactsManager::can_convert_channel_to_gigagroup(ChannelId channel_id) const { + const Channel *c = get_channel(channel_id); + return c == nullptr || get_channel_type(c) != ChannelType::Megagroup || !get_channel_status(c).is_creator() || + c->is_gigagroup || + c->default_permissions != RestrictedRights(false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + ChannelType::Unknown); +} + void ContactsManager::report_channel_spam(ChannelId channel_id, const vector &message_ids, Promise &&promise) { auto c = get_channel(channel_id); @@ -7494,62 +7466,6 @@ void ContactsManager::unregister_message_channels(MessageFullId message_full_id, } } -void ContactsManager::remove_dialog_suggested_action(SuggestedAction action) { - auto it = dialog_suggested_actions_.find(action.dialog_id_); - if (it == dialog_suggested_actions_.end()) { - return; - } - remove_suggested_action(it->second, action); - if (it->second.empty()) { - dialog_suggested_actions_.erase(it); - } -} - -void ContactsManager::dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise) { - auto dialog_id = action.dialog_id_; - if (!td_->messages_manager_->have_dialog(dialog_id)) { - 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")); - } - - auto it = dialog_suggested_actions_.find(dialog_id); - if (it == dialog_suggested_actions_.end() || !td::contains(it->second, action)) { - return promise.set_value(Unit()); - } - - auto action_str = action.get_suggested_action_str(); - if (action_str.empty()) { - return promise.set_value(Unit()); - } - - auto &queries = dismiss_suggested_action_queries_[dialog_id]; - queries.push_back(std::move(promise)); - if (queries.size() == 1) { - auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), action](Result &&result) { - send_closure(actor_id, &ContactsManager::on_dismiss_suggested_action, action, std::move(result)); - }); - td_->create_handler(std::move(query_promise))->send(std::move(action)); - } -} - -void ContactsManager::on_dismiss_suggested_action(SuggestedAction action, Result &&result) { - auto it = dismiss_suggested_action_queries_.find(action.dialog_id_); - CHECK(it != dismiss_suggested_action_queries_.end()); - auto promises = std::move(it->second); - dismiss_suggested_action_queries_.erase(it); - - if (result.is_error()) { - fail_promises(promises, result.move_as_error()); - return; - } - - remove_dialog_suggested_action(action); - - set_promises(promises); -} - void ContactsManager::on_import_contacts_finished(int64 random_id, vector imported_contact_user_ids, vector unimported_contact_invites) { LOG(INFO) << "Contacts import with random_id " << random_id @@ -9967,7 +9883,8 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from if (c->default_permissions != RestrictedRights(false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, ChannelType::Unknown)) { - remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); + td_->dialog_manager_->remove_dialog_suggested_action( + SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } c->is_default_permissions_changed = false; } @@ -11067,33 +10984,8 @@ void ContactsManager::on_get_chat_full(tl_object_ptr &&c } } - if (dismiss_suggested_action_queries_.count(DialogId(channel_id)) == 0) { - auto it = dialog_suggested_actions_.find(DialogId(channel_id)); - if (it != dialog_suggested_actions_.end() || !channel->pending_suggestions_.empty()) { - vector suggested_actions; - for (auto &action_str : channel->pending_suggestions_) { - SuggestedAction suggested_action(action_str, DialogId(channel_id)); - if (!suggested_action.is_empty()) { - if (suggested_action == SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)} && - (c->is_gigagroup || - c->default_permissions != RestrictedRights(false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, ChannelType::Unknown))) { - LOG(INFO) << "Skip ConvertToGigagroup suggested action"; - } else { - suggested_actions.push_back(suggested_action); - } - } - } - if (it == dialog_suggested_actions_.end()) { - it = dialog_suggested_actions_.emplace(DialogId(channel_id), vector()).first; - } - update_suggested_actions(it->second, std::move(suggested_actions)); - if (it->second.empty()) { - dialog_suggested_actions_.erase(it); - } - } - } + td_->dialog_manager_->set_dialog_pending_suggestions(DialogId(channel_id), + std::move(channel->pending_suggestions_)); } promise.set_value(Unit()); } @@ -13619,7 +13511,8 @@ void ContactsManager::on_channel_status_changed(Channel *c, ChannelId channel_id send_get_channel_full_query(nullptr, channel_id, Auto(), "update channel owner"); td_->dialog_participant_manager_->reload_dialog_administrators(DialogId(channel_id), {}, Auto()); - remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); + td_->dialog_manager_->remove_dialog_suggested_action( + SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } if (old_status.is_member() != new_status.is_member() || new_status.is_banned()) { @@ -15647,7 +15540,8 @@ void ContactsManager::on_get_channel(telegram_api::channel &channel, const char is_forum = false; } if (is_gigagroup) { - remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); + td_->dialog_manager_->remove_dialog_suggested_action( + SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); } DialogParticipantStatus status = [&] { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 98c9f6523..c6e0289c6 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -36,7 +36,6 @@ #include "td/telegram/SecretChatId.h" #include "td/telegram/StickerSetId.h" #include "td/telegram/StoryId.h" -#include "td/telegram/SuggestedAction.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" @@ -526,6 +525,8 @@ class ContactsManager final : public Actor { bool can_get_channel_story_statistics(ChannelId channel_id) const; + bool can_convert_channel_to_gigagroup(ChannelId channel_id) const; + void get_created_public_dialogs(PublicDialogType type, Promise> &&promise, bool from_binlog); @@ -537,8 +538,6 @@ class ContactsManager final : public Actor { vector get_inactive_channels(Promise &&promise); - void dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise); - bool is_user_contact(UserId user_id, bool is_mutual = false) const; bool is_user_premium(UserId user_id) const; @@ -1624,10 +1623,6 @@ class ContactsManager final : public Actor { void finish_get_chat_participant(ChatId chat_id, UserId user_id, Promise &&promise); - void remove_dialog_suggested_action(SuggestedAction action); - - void on_dismiss_suggested_action(SuggestedAction action, Result &&result); - bool need_poll_user_active_stories(const User *u, UserId user_id) const; static bool get_user_has_unread_stories(const User *u); @@ -1791,9 +1786,6 @@ class ContactsManager final : public Actor { QueryCombiner get_user_full_queries_{"GetUserFullCombiner", 2.0}; QueryCombiner get_chat_full_queries_{"GetChatFullCombiner", 2.0}; - FlatHashMap, DialogIdHash> dialog_suggested_actions_; - FlatHashMap>, DialogIdHash> dismiss_suggested_action_queries_; - class UploadProfilePhotoCallback; std::shared_ptr upload_profile_photo_callback_; diff --git a/td/telegram/DialogManager.cpp b/td/telegram/DialogManager.cpp index 053735120..b552685e6 100644 --- a/td/telegram/DialogManager.cpp +++ b/td/telegram/DialogManager.cpp @@ -134,6 +134,38 @@ class ResolveUsernameQuery final : public Td::ResultHandler { } }; +class DismissSuggestionQuery final : public Td::ResultHandler { + Promise promise_; + DialogId dialog_id_; + + public: + explicit DismissSuggestionQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(SuggestedAction action) { + dialog_id_ = action.dialog_id_; + 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::help_dismissSuggestion(std::move(input_peer), action.get_suggested_action_str()))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + td_->dialog_manager_->on_get_dialog_error(dialog_id_, status, "DismissSuggestionQuery"); + promise_.set_error(std::move(status)); + } +}; + class MigrateChatQuery final : public Td::ResultHandler { Promise promise_; @@ -2232,4 +2264,89 @@ void DialogManager::drop_username(const string &username) { } } +void DialogManager::set_dialog_pending_suggestions(DialogId dialog_id, vector &&pending_suggestions) { + if (dismiss_suggested_action_queries_.count(dialog_id) != 0) { + return; + } + auto it = dialog_suggested_actions_.find(dialog_id); + if (it == dialog_suggested_actions_.end() && !pending_suggestions.empty()) { + return; + } + vector suggested_actions; + for (auto &action_str : pending_suggestions) { + SuggestedAction suggested_action(action_str, dialog_id); + if (!suggested_action.is_empty()) { + if (suggested_action == SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, dialog_id} && + (dialog_id.get_type() != DialogType::Channel || + !td_->contacts_manager_->can_convert_channel_to_gigagroup(dialog_id.get_channel_id()))) { + LOG(INFO) << "Skip ConvertToGigagroup suggested action"; + } else { + suggested_actions.push_back(suggested_action); + } + } + } + if (it == dialog_suggested_actions_.end()) { + it = dialog_suggested_actions_.emplace(dialog_id, vector()).first; + } + update_suggested_actions(it->second, std::move(suggested_actions)); + if (it->second.empty()) { + dialog_suggested_actions_.erase(it); + } +} + +void DialogManager::remove_dialog_suggested_action(SuggestedAction action) { + auto it = dialog_suggested_actions_.find(action.dialog_id_); + if (it == dialog_suggested_actions_.end()) { + return; + } + remove_suggested_action(it->second, action); + if (it->second.empty()) { + dialog_suggested_actions_.erase(it); + } +} + +void DialogManager::dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise) { + auto dialog_id = action.dialog_id_; + if (!td_->messages_manager_->have_dialog(dialog_id)) { + 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")); + } + + auto it = dialog_suggested_actions_.find(dialog_id); + if (it == dialog_suggested_actions_.end() || !td::contains(it->second, action)) { + return promise.set_value(Unit()); + } + + auto action_str = action.get_suggested_action_str(); + if (action_str.empty()) { + return promise.set_value(Unit()); + } + + auto &queries = dismiss_suggested_action_queries_[dialog_id]; + queries.push_back(std::move(promise)); + if (queries.size() == 1) { + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), action](Result &&result) { + send_closure(actor_id, &DialogManager::on_dismiss_suggested_action, action, std::move(result)); + }); + td_->create_handler(std::move(query_promise))->send(std::move(action)); + } +} + +void DialogManager::on_dismiss_suggested_action(SuggestedAction action, Result &&result) { + auto it = dismiss_suggested_action_queries_.find(action.dialog_id_); + CHECK(it != dismiss_suggested_action_queries_.end()); + auto promises = std::move(it->second); + dismiss_suggested_action_queries_.erase(it); + + if (result.is_error()) { + return fail_promises(promises, result.move_as_error()); + } + + remove_dialog_suggested_action(action); + + set_promises(promises); +} + } // namespace td diff --git a/td/telegram/DialogManager.h b/td/telegram/DialogManager.h index 6d5b787d6..799d17984 100644 --- a/td/telegram/DialogManager.h +++ b/td/telegram/DialogManager.h @@ -20,6 +20,7 @@ #include "td/telegram/MessageId.h" #include "td/telegram/NotificationSettingsScope.h" #include "td/telegram/Photo.h" +#include "td/telegram/SuggestedAction.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" @@ -215,6 +216,12 @@ class DialogManager final : public Actor { void reload_voice_chat_on_search(const string &username); + void set_dialog_pending_suggestions(DialogId dialog_id, vector &&pending_suggestions); + + void dismiss_dialog_suggested_action(SuggestedAction action, Promise &&promise); + + void remove_dialog_suggested_action(SuggestedAction action); + private: static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title @@ -240,6 +247,8 @@ class DialogManager final : public Actor { void on_resolve_dialog(const string &username, ChannelId channel_id, Promise &&promise); + void on_dismiss_suggested_action(SuggestedAction action, Result &&result); + class UploadDialogPhotoCallback; std::shared_ptr upload_dialog_photo_callback_; @@ -275,6 +284,9 @@ class DialogManager final : public Actor { FlatHashMap>> resolve_dialog_username_queries_; + FlatHashMap, DialogIdHash> dialog_suggested_actions_; + FlatHashMap>, DialogIdHash> dismiss_suggested_action_queries_; + Td *td_; ActorShared<> parent_; }; diff --git a/td/telegram/SuggestedAction.cpp b/td/telegram/SuggestedAction.cpp index 196145e04..0a2e3915a 100644 --- a/td/telegram/SuggestedAction.cpp +++ b/td/telegram/SuggestedAction.cpp @@ -8,7 +8,7 @@ #include "td/telegram/ChannelId.h" #include "td/telegram/ConfigManager.h" -#include "td/telegram/ContactsManager.h" +#include "td/telegram/DialogManager.h" #include "td/telegram/Global.h" #include "td/telegram/Td.h" @@ -222,7 +222,7 @@ void dismiss_suggested_action(SuggestedAction action, Promise &&promise) { return send_closure_later(G()->config_manager(), &ConfigManager::dismiss_suggested_action, std::move(action), std::move(promise)); case SuggestedAction::Type::ConvertToGigagroup: - return send_closure_later(G()->contacts_manager(), &ContactsManager::dismiss_dialog_suggested_action, + return send_closure_later(G()->dialog_manager(), &DialogManager::dismiss_dialog_suggested_action, std::move(action), std::move(promise)); case SuggestedAction::Type::SetPassword: { if (action.otherwise_relogin_days_ < 0) {