From 665662a160960864a6abc51b68c4e4bc9dedd797 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 6 Aug 2023 23:28:00 +0300 Subject: [PATCH] Add td_api::setStoryReaction. --- td/generate/scheme/td_api.tl | 7 +++ td/telegram/StoryManager.cpp | 119 +++++++++++++++++++++++++++++++++++ td/telegram/StoryManager.h | 7 +++ td/telegram/Td.cpp | 8 +++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 8 +++ 6 files changed, 151 insertions(+) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 48e8d643a..1d9cd02d4 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -7460,6 +7460,13 @@ openStory story_sender_chat_id:int53 story_id:int32 = Ok; //@story_id The identifier of the story closeStory story_sender_chat_id:int53 story_id:int32 = Ok; +//@description Changes chosen reaction on a story +//@story_sender_chat_id The identifier of the sender of the story +//@story_id The identifier of the story +//@reaction_type Type of the reaction to set; pass null to remove the reaction. `reactionTypeCustomEmoji` reactions can be used only by Telegram Premium users +//@update_recent_reactions Pass true if the reaction needs to be added to recent reactions +setStoryReaction story_sender_chat_id:int53 story_id:int32 reaction_type:ReactionType update_recent_reactions:Bool = Ok; + //@description Returns viewers of a recent outgoing story. The method can be called if story.can_get_viewers == true. The views are returned in a reverse chronological order (i.e., in order of decreasing view_date) //-For optimal performance, the number of returned stories is chosen by TDLib //@story_id Story identifier diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 62b9c7687..8853b67ea 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -22,7 +22,9 @@ #include "td/telegram/NotificationId.h" #include "td/telegram/NotificationManager.h" #include "td/telegram/OptionManager.h" +#include "td/telegram/ReactionManager.h" #include "td/telegram/ReportReason.h" +#include "td/telegram/StickersManager.h" #include "td/telegram/StoryContent.h" #include "td/telegram/StoryContentType.h" #include "td/telegram/StoryInteractionInfo.hpp" @@ -243,6 +245,56 @@ class ReadStoriesQuery final : public Td::ResultHandler { } }; +class SendStoryReactionQuery final : public Td::ResultHandler { + Promise promise_; + DialogId dialog_id_; + + public: + explicit SendStoryReactionQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send(StoryFullId story_full_id, const ReactionType &reaction_type, bool add_to_recent) { + dialog_id_ = story_full_id.get_dialog_id(); + + CHECK(dialog_id_.get_type() == DialogType::User); + auto r_input_user = td_->contacts_manager_->get_input_user(dialog_id_.get_user_id()); + if (r_input_user.is_error()) { + return on_error(r_input_user.move_as_error()); + } + // auto input_peer = td_->stories_manager_->get_input_peer(dialog_id_, AccessRights::Read); + // CHECK(input_peer != nullptr); + + int32 flags = 0; + if (!reaction_type.is_empty() && add_to_recent) { + flags |= telegram_api::stories_sendReaction::ADD_TO_RECENT_MASK; + } + + send_query(G()->net_query_creator().create( + telegram_api::stories_sendReaction(flags, false /*ignored*/, r_input_user.move_as_ok(), + story_full_id.get_story_id().get(), reaction_type.get_input_reaction()), + {{story_full_id}})); + } + + 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()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for SendStoryReactionQuery: " << to_string(ptr); + td_->updates_manager_->on_get_updates(std::move(ptr), std::move(promise_)); + } + + void on_error(Status status) final { + if (status.message() == "STORY_NOT_MODIFIED") { + return promise_.set_value(Unit()); + } + td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "SendStoryReactionQuery"); + promise_.set_error(std::move(status)); + } +}; + class GetStoryViewsListQuery final : public Td::ResultHandler { Promise> promise_; @@ -2089,6 +2141,73 @@ void StoryManager::on_story_replied(StoryFullId story_full_id, UserId replier_us } } +bool StoryManager::can_use_story_reaction(const ReactionType &reaction_type) const { + if (reaction_type.is_empty()) { + return true; + } + if (reaction_type.is_custom_reaction()) { + return td_->option_manager_->get_option_boolean("is_premium"); + } + return td_->reaction_manager_->is_active_reaction(reaction_type); +} + +void StoryManager::set_story_reaction(StoryFullId story_full_id, ReactionType reaction_type, bool add_to_recent, + Promise &&promise) { + auto owner_dialog_id = story_full_id.get_dialog_id(); + if (!td_->messages_manager_->have_dialog_force(owner_dialog_id, "set_story_reaction")) { + return promise.set_error(Status::Error(400, "Story sender not found")); + } + if (!td_->messages_manager_->have_input_peer(owner_dialog_id, AccessRights::Read)) { + return promise.set_error(Status::Error(400, "Can't access the story sender")); + } + if (!story_full_id.get_story_id().is_valid()) { + return promise.set_error(Status::Error(400, "Invalid story identifier specified")); + } + + Story *story = get_story_force(story_full_id, "set_story_reaction"); + if (story == nullptr) { + return promise.set_error(Status::Error(400, "Story not found")); + } + + if (!can_use_story_reaction(reaction_type)) { + return promise.set_error(Status::Error(400, "The reaction isn't available for stories")); + } + + if (story->chosen_reaction_type_ == reaction_type) { + return promise.set_value(Unit()); + } + + if (add_to_recent) { + td_->reaction_manager_->add_recent_reaction(reaction_type); + } + + story->chosen_reaction_type_ = reaction_type; + on_story_changed(story_full_id, story, true, true); + + // TODO cancel previous queries, log event + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), story_full_id, + promise = std::move(promise)](Result &&result) mutable { + send_closure(actor_id, &StoryManager::on_set_story_reaction, story_full_id, std::move(result), std::move(promise)); + }); + + td_->create_handler(std::move(query_promise)) + ->send(story_full_id, reaction_type, add_to_recent); +} + +void StoryManager::on_set_story_reaction(StoryFullId story_full_id, Result &&result, Promise &&promise) { + TRY_STATUS_PROMISE(promise, G()->close_status()); + + if (!have_story_force(story_full_id)) { + return promise.set_value(Unit()); + } + + if (result.is_error()) { + reload_story(story_full_id, Promise(), "on_set_story_reaction"); + } + + promise.set_result(std::move(result)); +} + void StoryManager::schedule_interaction_info_update() { if (interaction_info_update_timeout_.has_timeout()) { return; diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index 5a1bfc098..6cc53fbde 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -246,6 +246,9 @@ class StoryManager final : public Actor { void on_story_replied(StoryFullId story_full_id, UserId replier_user_id); + void set_story_reaction(StoryFullId story_full_id, ReactionType reaction_type, bool add_to_recent, + Promise &&promise); + void get_story_viewers(StoryId story_id, const td_api::messageViewer *offset, int32 limit, Promise> &&promise); @@ -508,6 +511,8 @@ class StoryManager final : public Actor { void read_stories_on_server(DialogId owner_dialog_id, StoryId story_id, uint64 log_event_id); + bool can_use_story_reaction(const ReactionType &reaction_type) const; + void schedule_interaction_info_update(); static void update_interaction_info_static(void *story_manager); @@ -526,6 +531,8 @@ class StoryManager final : public Actor { Result> r_view_list, Promise> &&promise); + void on_set_story_reaction(StoryFullId story_full_id, Result &&result, Promise &&promise); + void load_expired_database_stories(); void on_load_expired_database_stories(vector stories); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 3ada73dfb..dffd350fb 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -6484,6 +6484,14 @@ void Td::on_request(uint64 id, const td_api::closeStory &request) { story_manager_->close_story(DialogId(request.story_sender_chat_id_), StoryId(request.story_id_), std::move(promise)); } +void Td::on_request(uint64 id, const td_api::setStoryReaction &request) { + CHECK_IS_USER(); + CREATE_OK_REQUEST_PROMISE(); + story_manager_->set_story_reaction({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)}, + ReactionType(request.reaction_type_), request.update_recent_reactions_, + std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::getStoryViewers &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 1a4682aca..e705d4d83 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -1021,6 +1021,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::closeStory &request); + void on_request(uint64 id, const td_api::setStoryReaction &request); + void on_request(uint64 id, const td_api::getStoryViewers &request); void on_request(uint64 id, td_api::reportStory &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index b13d85c1b..aeb5e8656 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -4140,6 +4140,14 @@ class CliClient final : public Actor { StoryId story_id; get_args(args, story_sender_chat_id, story_id); send_request(td_api::make_object(story_sender_chat_id, story_id)); + } else if (op == "ssr") { + ChatId story_sender_chat_id; + StoryId story_id; + string reaction; + bool update_recent_reactions; + get_args(args, story_sender_chat_id, story_id, reaction, update_recent_reactions); + send_request(td_api::make_object(story_sender_chat_id, story_id, + as_reaction_type(reaction), update_recent_reactions)); } else if (op == "gsv") { StoryId story_id; string limit;