diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 535f6dbc8..29089b923 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -7540,6 +7540,9 @@ readChatList chat_list:ChatList = Ok; //@only_local Pass true to get only locally available information without sending network requests getStory story_sender_chat_id:int53 story_id:int32 only_local:Bool = Story; +//@description Returns channel chats in which the current user has the right to post stories. The chats must be rechecked with canSendStory before actually trying to post a story there +getChatsToSendStories = Chats; + //@description Checks whether the current user can send a story on behalf of a chat; requires can_post_stories rights for channel chats @chat_id Chat identifier canSendStory chat_id:int53 = CanSendStoryResult; diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index 7d83d1cb0..5c6ec05a0 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -88,6 +88,8 @@ class ContactsManager final : public Actor { static ChannelId get_channel_id(const tl_object_ptr &chat); static DialogId get_dialog_id(const tl_object_ptr &chat); + vector get_channel_ids(vector> &&chats, const char *source); + Result> get_input_user(UserId user_id) const; tl_object_ptr get_input_user_force(UserId user_id) const; @@ -1833,8 +1835,6 @@ class ContactsManager final : public Actor { tl_object_ptr get_secret_chat_object_const(SecretChatId secret_chat_id, const SecretChat *secret_chat) const; - vector get_channel_ids(vector> &&chats, const char *source); - vector get_dialog_ids(vector> &&chats, const char *source); void on_create_inactive_channels(vector &&channel_ids, Promise &&promise); diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 3f0881e56..5d496effc 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -801,6 +801,50 @@ class GetBoostsStatusQuery final : public Td::ResultHandler { } }; +class GetChatsToSendStoriesQuery final : public Td::ResultHandler { + Promise promise_; + + public: + explicit GetChatsToSendStoriesQuery(Promise &&promise) : promise_(std::move(promise)) { + } + + void send() { + send_query(G()->net_query_creator().create(telegram_api::stories_getChatsToSend())); + } + + 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 chats_ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetChatsToSendStoriesQuery: " << to_string(chats_ptr); + int32 constructor_id = chats_ptr->get_id(); + switch (constructor_id) { + case telegram_api::messages_chats::ID: { + auto chats = move_tl_object_as(chats_ptr); + td_->story_manager_->on_get_dialogs_to_send_stories(std::move(chats->chats_)); + break; + } + case telegram_api::messages_chatsSlice::ID: { + auto chats = move_tl_object_as(chats_ptr); + LOG(ERROR) << "Receive chatsSlice in result of GetCreatedPublicChannelsQuery"; + td_->story_manager_->on_get_dialogs_to_send_stories(std::move(chats->chats_)); + break; + } + default: + UNREACHABLE(); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + class CanSendStoryQuery final : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; @@ -4226,6 +4270,63 @@ Result StoryManager::get_next_yet_unsent_story_id(DialogId dialog_id) { return StoryId(++story_id); } +void StoryManager::return_dialogs_to_send_stories(Promise> &&promise, + const vector &channel_ids) { + if (!promise) { + return; + } + + auto total_count = narrow_cast(channel_ids.size()); + promise.set_value(td_api::make_object( + total_count, transform(channel_ids, [](ChannelId channel_id) { return DialogId(channel_id).get(); }))); +} + +void StoryManager::get_dialogs_to_send_stories(Promise> &&promise) { + if (channels_to_send_stories_inited_) { + return_dialogs_to_send_stories(std::move(promise), channels_to_send_stories_); + promise = {}; + } + reload_dialogs_to_send_stories(std::move(promise)); +} + +void StoryManager::reload_dialogs_to_send_stories(Promise> &&promise) { + get_dialogs_to_send_stories_queries_.push_back(std::move(promise)); + if (get_dialogs_to_send_stories_queries_.size() == 1) { + auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this)](Result &&result) { + send_closure(actor_id, &StoryManager::finish_get_dialogs_to_send_stories, std::move(result)); + }); + td_->create_handler(std::move(query_promise))->send(); + } +} + +void StoryManager::finish_get_dialogs_to_send_stories(Result &&result) { + G()->ignore_result_if_closing(result); + + auto promises = std::move(get_dialogs_to_send_stories_queries_); + reset_to_empty(get_dialogs_to_send_stories_queries_); + if (result.is_error()) { + fail_promises(promises, result.move_as_error()); + return; + } + + CHECK(channels_to_send_stories_inited_); + for (auto &promise : promises) { + return_dialogs_to_send_stories(std::move(promise), channels_to_send_stories_); + } +} + +void StoryManager::on_get_dialogs_to_send_stories(vector> &&chats) { + auto channel_ids = td_->contacts_manager_->get_channel_ids(std::move(chats), "on_get_dialogs_to_send_stories"); + if (channels_to_send_stories_inited_ && channels_to_send_stories_ == channel_ids) { + return; + } + for (auto channel_id : channel_ids) { + td_->messages_manager_->force_create_dialog(DialogId(channel_id), "on_get_dialogs_to_send_stories"); + } + channels_to_send_stories_ = std::move(channel_ids); + channels_to_send_stories_inited_ = true; +} + void StoryManager::can_send_story(DialogId dialog_id, Promise> &&promise) { if (!can_post_stories(dialog_id)) { diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index f11c1d000..62582c480 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -6,6 +6,7 @@ // #pragma once +#include "td/telegram/ChannelId.h" #include "td/telegram/DialogDate.h" #include "td/telegram/DialogId.h" #include "td/telegram/files/FileId.h" @@ -198,6 +199,12 @@ class StoryManager final : public Actor { void get_story(DialogId owner_dialog_id, StoryId story_id, bool only_local, Promise> &&promise); + void get_dialogs_to_send_stories(Promise> &&promise); + + void reload_dialogs_to_send_stories(Promise> &&promise); + + void on_get_dialogs_to_send_stories(vector> &&chats); + void can_send_story(DialogId dialog_id, Promise> &&promise); void send_story(DialogId dialog_id, td_api::object_ptr &&input_story_content, @@ -434,6 +441,11 @@ class StoryManager final : public Actor { void on_delete_story(StoryFullId story_full_id); + void return_dialogs_to_send_stories(Promise> &&promise, + const vector &channel_ids); + + void finish_get_dialogs_to_send_stories(Result &&result); + void on_get_dialog_pinned_stories(DialogId owner_dialog_id, telegram_api::object_ptr &&stories, Promise> &&promise); @@ -632,6 +644,10 @@ class StoryManager final : public Actor { FlatHashMap> ready_to_send_stories_; + bool channels_to_send_stories_inited_ = false; + vector channels_to_send_stories_; + vector>> get_dialogs_to_send_stories_queries_; + StoryList story_lists_[2]; StoryStealthMode stealth_mode_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index b9dcd5a76..768d93fd2 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5679,6 +5679,12 @@ void Td::on_request(uint64 id, const td_api::getStory &request) { std::move(promise)); } +void Td::on_request(uint64 id, const td_api::getChatsToSendStories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + story_manager_->get_dialogs_to_send_stories(std::move(promise)); +} + void Td::on_request(uint64 id, const td_api::canSendStory &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index a4f8a6f1f..1de643ac3 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -796,6 +796,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::getStory &request); + void on_request(uint64 id, const td_api::getChatsToSendStories &request); + void on_request(uint64 id, const td_api::canSendStory &request); void on_request(uint64 id, td_api::sendStory &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index ec611c771..cf89cfe6a 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -4136,6 +4136,8 @@ 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, op == "gstl")); + } else if (op == "gctss") { + send_request(td_api::make_object()); } else if (op == "csst") { ChatId chat_id; get_args(args, chat_id);