diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index a17c7c2da..05a3ab1f0 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -1129,9 +1129,6 @@ void ConfigManager::do_set_archive_and_mute(bool archive_and_mute) { } void ConfigManager::dismiss_suggested_action(SuggestedAction suggested_action, Promise &&promise) { - if (suggested_action == SuggestedAction()) { - return promise.set_error(Status::Error(400, "Action must be non-empty")); - } auto action_str = suggested_action.get_suggested_action_str(); if (action_str.empty()) { return promise.set_value(Unit()); diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index c04a8f503..909317793 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -72,6 +72,38 @@ namespace td { +class DismissSuggestionQuery : 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->messages_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(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + promise_.set_value(Unit()); + } + + void on_error(uint64 id, Status status) override { + td->messages_manager_->on_get_dialog_error(dialog_id_, status, "DismissSuggestionQuery"); + promise_.set_error(std::move(status)); + } +}; + class SetAccountTtlQuery : public Td::ResultHandler { Promise promise_; @@ -6211,6 +6243,8 @@ void ContactsManager::convert_channel_to_gigagroup(ChannelId channel_id, Promise return promise.set_error(Status::Error(6, "Chat must be a supergroup")); } + remove_dialog_suggested_action(SuggestedAction{SuggestedAction::Type::ConvertToGigagroup, DialogId(channel_id)}); + td_->create_handler(std::move(promise))->send(channel_id); } @@ -7439,12 +7473,73 @@ void ContactsManager::remove_inactive_channel(ChannelId channel_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_suggested_action(SuggestedAction action, Promise &&promise) { - if (!action.dialog_id_.is_valid()) { + if (action == SuggestedAction()) { + return promise.set_error(Status::Error(400, "Action must be non-empty")); + } + auto dialog_id = action.dialog_id_; + if (!dialog_id.is_valid()) { send_closure_later(G()->config_manager(), &ConfigManager::dismiss_suggested_action, std::move(action), std::move(promise)); return; } + + if (!td_->messages_manager_->have_dialog(dialog_id)) { + return promise.set_error(Status::Error(400, "Chat not found")); + } + if (!td_->messages_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()) { + for (auto &promise : promises) { + promise.set_error(result.error().clone()); + } + return; + } + + remove_dialog_suggested_action(action); + + for (auto &promise : promises) { + promise.set_value(Unit()); + } } void ContactsManager::on_imported_contacts(int64 random_id, vector imported_contact_user_ids, diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index bdf258628..8f893a820 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -1435,6 +1435,10 @@ class ContactsManager : public Actor { void reload_dialog_administrators(DialogId dialog_id, int32 hash, Promise &&promise); + void remove_dialog_suggested_action(SuggestedAction action); + + void on_dismiss_suggested_action(SuggestedAction action, Result &&result); + static td_api::object_ptr get_update_unknown_user_object(UserId user_id); td_api::object_ptr get_user_status_object(UserId user_id, const User *u) const; @@ -1622,6 +1626,9 @@ class ContactsManager : public Actor { std::unordered_map, DialogIdHash> dialog_administrators_; + std::unordered_map, DialogIdHash> dialog_suggested_actions_; + std::unordered_map>, DialogIdHash> dismiss_suggested_action_queries_; + class UploadProfilePhotoCallback; std::shared_ptr upload_profile_photo_callback_; diff --git a/td/telegram/SuggestedAction.h b/td/telegram/SuggestedAction.h index 8b39a18c6..774e024b1 100644 --- a/td/telegram/SuggestedAction.h +++ b/td/telegram/SuggestedAction.h @@ -23,7 +23,7 @@ struct SuggestedAction { SuggestedAction() = default; - explicit SuggestedAction(Type type) : type_(type) { + explicit SuggestedAction(Type type, DialogId dialog_id = DialogId()) : type_(type), dialog_id_(dialog_id) { } explicit SuggestedAction(Slice action_str); @@ -38,6 +38,7 @@ struct SuggestedAction { }; inline bool operator==(const SuggestedAction &lhs, const SuggestedAction &rhs) { + CHECK(lhs.dialog_id_ == rhs.dialog_id_); return lhs.type_ == rhs.type_; } @@ -46,6 +47,7 @@ inline bool operator!=(const SuggestedAction &lhs, const SuggestedAction &rhs) { } inline bool operator<(const SuggestedAction &lhs, const SuggestedAction &rhs) { + CHECK(lhs.dialog_id_ == rhs.dialog_id_); return static_cast(lhs.type_) < static_cast(rhs.type_); }