Add td_api::getStoryPublicForwards.

This commit is contained in:
levlam 2023-11-30 17:21:56 +03:00
parent 7afab3e805
commit 9bf9bf767d
8 changed files with 239 additions and 8 deletions

View File

@ -1332,7 +1332,7 @@ message id:int53 sender_id:MessageSender chat_id:int53 sending_state:MessageSend
//@description Contains a list of messages @total_count Approximate total number of messages found @messages List of messages; messages may be null
messages total_count:int32 messages:vector<message> = Messages;
//@description Contains a list of messages found by a search @total_count Approximate total number of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, there are no more results
//@description Contains a list of messages found by a search @total_count Approximate total number of messages found; -1 if unknown @messages List of messages @next_offset The offset for the next request. If empty, then there are no more results
foundMessages total_count:int32 messages:vector<message> next_offset:string = FoundMessages;
//@description Contains a list of messages found by a search in a given chat @total_count Approximate total number of messages found; -1 if unknown @messages List of messages @next_from_message_id The offset for the next request. If 0, there are no more results
@ -1438,7 +1438,7 @@ downloadedFileCounts active_count:int32 paused_count:int32 completed_count:int32
//@description Contains a list of downloaded files, found by a search
//@total_counts Total number of suitable files, ignoring offset
//@files The list of files
//@next_offset The offset for the next request. If empty, there are no more results
//@next_offset The offset for the next request. If empty, then there are no more results
foundFileDownloads total_counts:downloadedFileCounts files:vector<fileDownload> next_offset:string = FoundFileDownloads;
@ -3386,7 +3386,7 @@ storyViewer user_id:int53 view_date:int32 block_list:BlockList chosen_reaction_t
//@total_count Approximate total number of story viewers found
//@total_reaction_count Approximate total number of reactions set by found story viewers
//@viewers List of story viewers
//@next_offset The offset for the next request. If empty, there are no more results
//@next_offset The offset for the next request. If empty, then there are no more results
storyViewers total_count:int32 total_reaction_count:int32 viewers:vector<storyViewer> next_offset:string = StoryViewers;
@ -3567,6 +3567,22 @@ storyInfo story_id:int32 date:int32 is_for_close_friends:Bool = StoryInfo;
chatActiveStories chat_id:int53 list:StoryList order:int53 max_read_story_id:int32 stories:vector<storyInfo> = ChatActiveStories;
//@class StoryPublicForward @description Describes a public forward or repost of a story
//@description Contains a public forward of a story as a message @message Information about the message with the story
storyPublicForwardMessage message:message = StoryPublicForward;
//@description Contains a public repost of a story as a story @story Information about the reposted story
storyPublicForwardStory story:story = StoryPublicForward;
//@description Represents a list of public forwards and reposts of a story
//@total_count Approximate total number of messages and stories found
//@forwards List of found public forwards and reposts
//@next_offset The offset for the next request. If empty, then there are no more results
storyPublicForwards total_count:int32 forwards:vector<StoryPublicForward> next_offset:string = StoryPublicForwards;
//@class ChatBoostSource @description Describes source of a chat boost
//@description The chat created a Telegram Premium gift code for a user
@ -3614,7 +3630,7 @@ chatBoostStatus boost_url:string applied_slot_ids:vector<int32> level:int32 gift
//@expiration_date Point in time (Unix timestamp) when the boost will expire
chatBoost id:string count:int32 source:ChatBoostSource start_date:int32 expiration_date:int32 = ChatBoost;
//@description Contains a list of boosts applied to a chat @total_count Total number of boosts applied to the chat @boosts List of boosts @next_offset The offset for the next request. If empty, there are no more results
//@description Contains a list of boosts applied to a chat @total_count Total number of boosts applied to the chat @boosts List of boosts @next_offset The offset for the next request. If empty, then there are no more results
foundChatBoosts total_count:int32 boosts:vector<chatBoost> next_offset:string = FoundChatBoosts;
//@description Describes a slot for chat boost
@ -3864,7 +3880,7 @@ phoneNumberAuthenticationSettings allow_flash_call:Bool allow_missed_call:Bool i
//@date Point in time (Unix timestamp) when the reaction was added
addedReaction type:ReactionType sender_id:MessageSender is_outgoing:Bool date:int32 = AddedReaction;
//@description Represents a list of reactions added to a message @total_count The total number of found reactions @reactions The list of added reactions @next_offset The offset for the next request. If empty, there are no more results
//@description Represents a list of reactions added to a message @total_count The total number of found reactions @reactions The list of added reactions @next_offset The offset for the next request. If empty, then there are no more results
addedReactions total_count:int32 reactions:vector<addedReaction> next_offset:string = AddedReactions;
//@description Represents an available reaction @type Type of the reaction @needs_premium True, if Telegram Premium is needed to send the reaction
@ -4215,7 +4231,7 @@ inlineQueryResultsButton text:string type:InlineQueryResultsButtonType = InlineQ
//@inline_query_id Unique identifier of the inline query
//@button Button to be shown above inline query results; may be null
//@results Results of the query
//@next_offset The offset for the next request. If empty, there are no more results
//@next_offset The offset for the next request. If empty, then there are no more results
inlineQueryResults inline_query_id:int64 button:inlineQueryResultsButton results:vector<InlineQueryResult> next_offset:string = InlineQueryResults;
@ -7811,7 +7827,7 @@ setChatPermissions chat_id:int53 permissions:chatPermissions = Ok;
setChatBackground chat_id:int53 background:InputBackground type:BackgroundType dark_theme_dimming:int32 only_for_self:Bool = Ok;
//@description Restores background in a specific chat after it was changed by the other user. Supported only in private and secret chats with non-deleted users.
//-Can be called only from messageChatSetBackground messages with the currently set background that was set for both sides by the other user if userFullInfo.set_chat_background
//-Can be called only from messageChatSetBackground messages with the currently set background that was set for both sides by the other user if userFullInfo.set_chat_background == true
//@chat_id Chat identifier
revertChatBackground chat_id:int53 = Ok;
@ -8102,6 +8118,14 @@ reportStory story_sender_chat_id:int53 story_id:int32 reason:ReportReason text:s
//-and for the next "story_stealth_mode_future_period" seconds; for Telegram Premium users only
activateStoryStealthMode = Ok;
//@description Returns forwards of a story as a message to public chats and reposts by public channels. Can be used only if story.can_get_statistics == true, or the story is posted on behalf of the current user.
//-For optimal performance, the number of returned messages and stories is chosen by TDLib
//@story_sender_chat_id The identifier of the sender of the story
//@story_id The identifier of the story
//@offset Offset of the first entry to return as received from the previous request; use empty string to get the first chunk of results
//@limit The maximum number of messages and stories to be returned; must be positive and can't be greater than 100. For optimal performance, the number of returned objects is chosen by TDLib and can be smaller than the specified limit
getStoryPublicForwards story_sender_chat_id:int53 story_id:int32 offset:string limit:int32 = StoryPublicForwards;
//@description Returns the list of available chat boost slots for the current user
getAvailableChatBoostSlots = ChatBoostSlots;

View File

@ -9767,7 +9767,7 @@ void MessagesManager::get_channel_differences_if_needed(MessagesInfo &&messages_
auto dialog_id = DialogId::get_message_dialog_id(message);
if (need_channel_difference_to_add_message(dialog_id, message)) {
run_after_channel_difference(dialog_id, MessageId::get_max_message_id(messages_info.messages), mpas.get_promise(),
run_after_channel_difference(dialog_id, MessageId::get_message_id(message, false), mpas.get_promise(),
"get_channel_differences_if_needed");
}
}
@ -9777,6 +9777,35 @@ void MessagesManager::get_channel_differences_if_needed(MessagesInfo &&messages_
lock.set_value(Unit());
}
void MessagesManager::get_channel_differences_if_needed(
telegram_api::object_ptr<telegram_api::stats_publicForwards> &&public_forwards,
Promise<telegram_api::object_ptr<telegram_api::stats_publicForwards>> &&promise) {
if (td_->auth_manager_->is_bot()) {
return promise.set_value(std::move(public_forwards));
}
MultiPromiseActorSafe mpas{"GetChannelDifferencesIfNeededMultiPromiseActor"};
mpas.add_promise(Promise<Unit>());
mpas.set_ignore_errors(true);
auto lock = mpas.get_promise();
for (const auto &forward : public_forwards->forwards_) {
CHECK(forward != nullptr);
if (forward->get_id() != telegram_api::publicForwardMessage::ID) {
continue;
}
const auto &message = static_cast<const telegram_api::publicForwardMessage *>(forward.get())->message_;
auto dialog_id = DialogId::get_message_dialog_id(message);
if (need_channel_difference_to_add_message(dialog_id, message)) {
run_after_channel_difference(dialog_id, MessageId::get_message_id(message, false), mpas.get_promise(),
"get_channel_differences_if_needed");
}
}
// must be added after forwarded messages are checked
mpas.add_promise(
PromiseCreator::lambda([public_forwards = std::move(public_forwards), promise = std::move(promise)](
Unit ignored) mutable { promise.set_value(std::move(public_forwards)); }));
lock.set_value(Unit());
}
void MessagesManager::on_get_messages(vector<tl_object_ptr<telegram_api::Message>> &&messages, bool is_channel_message,
bool is_scheduled, Promise<Unit> &&promise, const char *source) {
TRY_STATUS_PROMISE(promise, G()->close_status());

View File

@ -178,6 +178,10 @@ class MessagesManager final : public Actor {
void get_channel_differences_if_needed(MessagesInfo &&messages_info, Promise<MessagesInfo> &&promise);
void get_channel_differences_if_needed(
telegram_api::object_ptr<telegram_api::stats_publicForwards> &&public_forwards,
Promise<telegram_api::object_ptr<telegram_api::stats_publicForwards>> &&promise);
void on_get_messages(vector<tl_object_ptr<telegram_api::Message>> &&messages, bool is_channel_message,
bool is_scheduled, Promise<Unit> &&promise, const char *source);

View File

@ -443,6 +443,55 @@ class GetMessagePublicForwardsQuery final : public Td::ResultHandler {
}
};
class GetStoryPublicForwardsQuery final : public Td::ResultHandler {
Promise<td_api::object_ptr<td_api::storyPublicForwards>> promise_;
DialogId dialog_id_;
public:
explicit GetStoryPublicForwardsQuery(Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise)
: promise_(std::move(promise)) {
}
void send(DcId dc_id, StoryFullId story_full_id, const string &offset, int32 limit) {
dialog_id_ = story_full_id.get_dialog_id();
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Write);
if (input_peer == nullptr) {
return on_error(Status::Error(400, "Can't get story statistics"));
}
send_query(
G()->net_query_creator().create(telegram_api::stats_getStoryPublicForwards(
std::move(input_peer), story_full_id.get_story_id().get(), offset, limit),
{}, dc_id));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::stats_getStoryPublicForwards>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
td_->messages_manager_->get_channel_differences_if_needed(
result_ptr.move_as_ok(),
PromiseCreator::lambda(
[actor_id = td_->statistics_manager_actor_.get(), promise = std::move(promise_)](
Result<telegram_api::object_ptr<telegram_api::stats_publicForwards>> &&result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
send_closure(actor_id, &StatisticsManager::on_get_story_public_forwards, result.move_as_ok(),
std::move(promise));
}
}));
}
void on_error(Status status) final {
td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetStoryPublicForwardsQuery");
promise_.set_error(std::move(status));
}
};
StatisticsManager::StatisticsManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
@ -662,4 +711,103 @@ void StatisticsManager::on_get_message_public_forwards(
promise.set_value(td_api::make_object<td_api::foundMessages>(total_count, std::move(result), next_offset));
}
void StatisticsManager::get_story_public_forwards(StoryFullId story_full_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise) {
if (limit <= 0) {
return promise.set_error(Status::Error(400, "Parameter limit must be positive"));
}
auto dialog_id = story_full_id.get_dialog_id();
if (dialog_id.get_type() == DialogType::User) {
if (dialog_id != DialogId(td_->contacts_manager_->get_my_id())) {
return promise.set_error(Status::Error(400, "Have no access to story statistics"));
}
return send_get_story_public_forwards_query(DcId::main(), story_full_id, std::move(offset), limit,
std::move(promise));
}
auto dc_id_promise = PromiseCreator::lambda([actor_id = actor_id(this), story_full_id, offset = std::move(offset),
limit, promise = std::move(promise)](Result<DcId> r_dc_id) mutable {
if (r_dc_id.is_error()) {
return promise.set_error(r_dc_id.move_as_error());
}
send_closure(actor_id, &StatisticsManager::send_get_story_public_forwards_query, r_dc_id.move_as_ok(),
story_full_id, std::move(offset), limit, std::move(promise));
});
td_->contacts_manager_->get_channel_statistics_dc_id(dialog_id, false, std::move(dc_id_promise));
}
void StatisticsManager::send_get_story_public_forwards_query(
DcId dc_id, StoryFullId story_full_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise) {
if (!td_->story_manager_->have_story_force(story_full_id)) {
return promise.set_error(Status::Error(400, "Story not found"));
}
if (!td_->story_manager_->can_get_story_statistics(story_full_id) &&
story_full_id.get_dialog_id() != DialogId(td_->contacts_manager_->get_my_id())) {
return promise.set_error(Status::Error(400, "Story forwards are inaccessible"));
}
static constexpr int32 MAX_STORY_FORWARDS = 100; // server side limit
if (limit > MAX_STORY_FORWARDS) {
limit = MAX_STORY_FORWARDS;
}
td_->create_handler<GetStoryPublicForwardsQuery>(std::move(promise))->send(dc_id, story_full_id, offset, limit);
}
void StatisticsManager::on_get_story_public_forwards(
telegram_api::object_ptr<telegram_api::stats_publicForwards> &&public_forwards,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
td_->contacts_manager_->on_get_users(std::move(public_forwards->users_), "on_get_story_public_forwards");
td_->contacts_manager_->on_get_chats(std::move(public_forwards->chats_), "on_get_story_public_forwards");
auto total_count = public_forwards->count_;
LOG(INFO) << "Receive " << public_forwards->forwards_.size() << " forwarded stories out of "
<< public_forwards->count_;
vector<td_api::object_ptr<td_api::StoryPublicForward>> result;
for (auto &forward_ptr : public_forwards->forwards_) {
switch (forward_ptr->get_id()) {
case telegram_api::publicForwardMessage::ID: {
auto forward = telegram_api::move_object_as<telegram_api::publicForwardMessage>(forward_ptr);
auto dialog_id = DialogId::get_message_dialog_id(forward->message_);
auto message_full_id = td_->messages_manager_->on_get_message(std::move(forward->message_), false,
dialog_id.get_type() == DialogType::Channel,
false, "on_get_story_public_forwards");
if (message_full_id != MessageFullId()) {
CHECK(dialog_id == message_full_id.get_dialog_id());
result.push_back(td_api::make_object<td_api::storyPublicForwardMessage>(
td_->messages_manager_->get_message_object(message_full_id, "on_get_story_public_forwards")));
CHECK(result.back() != nullptr);
} else {
total_count--;
}
break;
}
case telegram_api::publicForwardStory::ID: {
auto forward = telegram_api::move_object_as<telegram_api::publicForwardStory>(forward_ptr);
auto dialog_id = DialogId(forward->peer_);
auto story_id = td_->story_manager_->on_get_story(dialog_id, std::move(forward->story_));
if (story_id.is_valid() && td_->story_manager_->have_story({dialog_id, story_id})) {
result.push_back(td_api::make_object<td_api::storyPublicForwardStory>(
td_->story_manager_->get_story_object({dialog_id, story_id})));
CHECK(result.back() != nullptr);
} else {
total_count--;
}
break;
}
default:
UNREACHABLE();
}
}
if (total_count < static_cast<int32>(result.size())) {
LOG(ERROR) << "Receive " << result.size() << " valid story sorwards out of " << total_count;
total_count = static_cast<int32>(result.size());
}
promise.set_value(
td_api::make_object<td_api::storyPublicForwards>(total_count, std::move(result), public_forwards->next_offset_));
}
} // namespace td

View File

@ -46,6 +46,12 @@ class StatisticsManager final : public Actor {
vector<telegram_api::object_ptr<telegram_api::Message>> &&messages,
int32 next_rate, Promise<td_api::object_ptr<td_api::foundMessages>> &&promise);
void get_story_public_forwards(StoryFullId story_full_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise);
void on_get_story_public_forwards(telegram_api::object_ptr<telegram_api::stats_publicForwards> &&public_forwards,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise);
private:
void tear_down() final;
@ -64,6 +70,9 @@ class StatisticsManager final : public Actor {
void send_get_message_public_forwards_query(DcId dc_id, MessageFullId message_full_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::foundMessages>> &&promise);
void send_get_story_public_forwards_query(DcId dc_id, StoryFullId story_full_id, string offset, int32 limit,
Promise<td_api::object_ptr<td_api::storyPublicForwards>> &&promise);
Td *td_;
ActorShared<> parent_;
};

View File

@ -5514,6 +5514,14 @@ void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) {
std::move(request.offset_), request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, td_api::getStoryPublicForwards &request) {
CHECK_IS_USER();
CLEAN_INPUT_STRING(request.offset_);
CREATE_REQUEST_PROMISE();
statistics_manager_->get_story_public_forwards({DialogId(request.story_sender_chat_id_), StoryId(request.story_id_)},
std::move(request.offset_), request.limit_, std::move(promise));
}
void Td::on_request(uint64 id, const td_api::removeNotification &request) {
CHECK_IS_USER();
CREATE_OK_REQUEST_PROMISE();

View File

@ -753,6 +753,8 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::getMessagePublicForwards &request);
void on_request(uint64 id, td_api::getStoryPublicForwards &request);
void on_request(uint64 id, const td_api::removeNotification &request);
void on_request(uint64 id, const td_api::removeNotificationGroup &request);

View File

@ -2793,6 +2793,13 @@ class CliClient final : public Actor {
string limit;
get_args(args, chat_id, message_id, offset, limit);
send_request(td_api::make_object<td_api::getMessagePublicForwards>(chat_id, message_id, offset, as_limit(limit)));
} else if (op == "gspf") {
ChatId chat_id;
StoryId story_id;
string offset;
string limit;
get_args(args, chat_id, story_id, offset, limit);
send_request(td_api::make_object<td_api::getStoryPublicForwards>(chat_id, story_id, offset, as_limit(limit)));
} else if (op == "ghf") {
get_history_chat_id_ = as_chat_id(args);
send_request(td_api::make_object<td_api::getChatHistory>(get_history_chat_id_, std::numeric_limits<int64>::max(),