Support various types of story interactions.

This commit is contained in:
levlam 2023-12-25 22:07:02 +03:00
parent be785dd673
commit 53cf01e7bf
6 changed files with 137 additions and 49 deletions

View File

@ -3406,22 +3406,6 @@ emojiCategoryTypeEmojiStatus = EmojiCategoryType;
emojiCategoryTypeChatPhoto = EmojiCategoryType;
//@description Represents a view of a story
//@user_id User identifier of the viewer
//@view_date Approximate point in time (Unix timestamp) when the story was viewed
//@block_list Block list to which the user is added; may be null if none
//@chosen_reaction_type Type of the reaction that was chosen by the user; may be null if none
storyInteraction user_id:int53 view_date:int32 block_list:BlockList chosen_reaction_type:ReactionType = StoryInteraction;
//@description Represents a list of interactions with a story
//@total_count Approximate total number of interactions found
//@total_forward_count Approximate total number of found forwards and reposts
//@total_reaction_count Approximate total number of found reactions
//@interactions List of story interactions
//@next_offset The offset for the next request. If empty, then there are no more results
storyInteractions total_count:int32 total_forward_count:int32 total_reaction_count:int32 interactions:vector<storyInteraction> next_offset:string = StoryInteractions;
//@description Describes position of a clickable rectangle area on a story media
//@x_percentage The abscissa of the rectangle's center, as a percentage of the media width
//@y_percentage The ordinate of the rectangle's center, as a percentage of the media height
@ -3608,6 +3592,34 @@ 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 StoryInteractionType @description Describes type of interaction with a story
//@description A view of the story @chosen_reaction_type Type of the reaction that was chosen by the viewer; may be null if none
storyInteractionTypeView chosen_reaction_type:ReactionType = StoryInteractionType;
//@description A forward of the story as a message @message The message with story forward
storyInteractionTypeForward message:message = StoryInteractionType;
//@description A repost of the story as a story @story The reposted story
storyInteractionTypeRepost story:story = StoryInteractionType;
//@description Represents interaction with a story
//@actor_id Identifier of the user or chat that made the interaction
//@interaction_date Approximate point in time (Unix timestamp) when the interaction happenned
//@block_list Block list to which the actor is added; may be null if none
//@type Type of the interaction
storyInteraction actor_id:MessageSender interaction_date:int32 block_list:BlockList type:StoryInteractionType = StoryInteraction;
//@description Represents a list of interactions with a story
//@total_count Approximate total number of interactions found
//@total_forward_count Approximate total number of found forwards and reposts
//@total_reaction_count Approximate total number of found reactions
//@interactions List of story interactions
//@next_offset The offset for the next request. If empty, then there are no more results
storyInteractions total_count:int32 total_forward_count:int32 total_reaction_count:int32 interactions:vector<storyInteraction> next_offset:string = StoryInteractions;
//@class PublicForward @description Describes a public forward or repost of a story
//@description Contains a public forward as a message @message Information about the message

View File

@ -230,7 +230,6 @@ class MessagesManager final : public Actor {
vector<tl_object_ptr<telegram_api::Message>> &&messages,
Promise<td_api::object_ptr<td_api::messages>> &&promise);
// if message is from_update, flags have_previous and have_next are ignored and must be both true
MessageFullId on_get_message(tl_object_ptr<telegram_api::Message> message_ptr, bool from_update,
bool is_channel_message, bool is_scheduled, const char *source);

View File

@ -2869,7 +2869,7 @@ void StoryManager::on_get_story_interactions(
}
td_->contacts_manager_->on_view_dialog_active_stories(story_viewers.get_actor_dialog_ids());
promise.set_value(story_viewers.get_story_interactions_object(td_->contacts_manager_.get()));
promise.set_value(story_viewers.get_story_interactions_object(td_));
}
void StoryManager::report_story(StoryFullId story_full_id, ReportReason &&reason, Promise<Unit> &&promise) {
@ -2895,6 +2895,11 @@ bool StoryManager::have_story_force(StoryFullId story_full_id) {
return get_story_force(story_full_id, "have_story_force") != nullptr;
}
int32 StoryManager::get_story_date(StoryFullId story_full_id) {
const auto *story = get_story_force(story_full_id, "get_story_date");
return story != nullptr ? story->date_ : 0;
}
bool StoryManager::is_inaccessible_story(StoryFullId story_full_id) const {
return inaccessible_story_full_ids_.count(story_full_id) > 0;
}

View File

@ -306,6 +306,8 @@ class StoryManager final : public Actor {
bool have_story_force(StoryFullId story_full_id);
int32 get_story_date(StoryFullId story_full_id);
bool can_get_story_statistics(StoryFullId story_full_id);
bool is_inaccessible_story(StoryFullId story_full_id) const;

View File

@ -8,7 +8,9 @@
#include "td/telegram/BlockListId.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/MessageSender.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/StoryManager.h"
#include "td/telegram/Td.h"
#include "td/utils/algorithm.h"
@ -18,37 +20,101 @@ namespace td {
StoryViewer::StoryViewer(Td *td, telegram_api::object_ptr<telegram_api::StoryView> &&story_view_ptr) {
CHECK(story_view_ptr != nullptr);
if (story_view_ptr->get_id() != telegram_api::storyView::ID) {
return;
switch (story_view_ptr->get_id()) {
case telegram_api::storyView::ID: {
auto story_view = telegram_api::move_object_as<telegram_api::storyView>(story_view_ptr);
UserId user_id(story_view->user_id_);
if (!user_id.is_valid()) {
break;
}
type_ = Type::View;
actor_dialog_id_ = DialogId(user_id);
date_ = td::max(story_view->date_, static_cast<int32>(0));
is_blocked_ = story_view->blocked_;
is_blocked_for_stories_ = story_view->blocked_my_stories_from_;
reaction_type_ = ReactionType(story_view->reaction_);
break;
}
case telegram_api::storyViewPublicForward::ID: {
auto story_view = telegram_api::move_object_as<telegram_api::storyViewPublicForward>(story_view_ptr);
auto date = MessagesManager::get_message_date(story_view->message_);
auto message_full_id = td->messages_manager_->on_get_message(std::move(story_view->message_), false, true, false,
"storyViewPublicForward");
if (!message_full_id.get_message_id().is_valid() || date <= 0) {
break;
}
type_ = Type::Forward;
actor_dialog_id_ = td->messages_manager_->get_dialog_message_sender(message_full_id);
date_ = date;
is_blocked_ = story_view->blocked_;
is_blocked_for_stories_ = story_view->blocked_my_stories_from_;
message_full_id_ = message_full_id;
break;
}
case telegram_api::storyViewPublicRepost::ID: {
auto story_view = telegram_api::move_object_as<telegram_api::storyViewPublicRepost>(story_view_ptr);
auto owner_dialog_id = DialogId(story_view->peer_id_);
if (!owner_dialog_id.is_valid()) {
break;
}
auto story_id = td->story_manager_->on_get_story(owner_dialog_id, std::move(story_view->story_));
auto date = td->story_manager_->get_story_date({owner_dialog_id, story_id});
if (date <= 0) {
break;
}
type_ = Type::Repost;
actor_dialog_id_ = owner_dialog_id;
date_ = date;
is_blocked_ = story_view->blocked_;
is_blocked_for_stories_ = story_view->blocked_my_stories_from_;
story_id_ = story_id;
break;
}
default:
UNREACHABLE();
break;
}
auto story_view = telegram_api::move_object_as<telegram_api::storyView>(story_view_ptr);
UserId user_id(story_view->user_id_);
if (!user_id.is_valid()) {
return;
}
user_id_ = user_id;
date_ = td::max(story_view->date_, static_cast<int32>(0));
is_blocked_ = story_view->blocked_;
is_blocked_for_stories_ = story_view->blocked_my_stories_from_;
reaction_type_ = ReactionType(story_view->reaction_);
td->messages_manager_->on_update_dialog_is_blocked(DialogId(user_id), is_blocked_, is_blocked_for_stories_);
if (is_valid()) {
td->messages_manager_->on_update_dialog_is_blocked(actor_dialog_id_, is_blocked_, is_blocked_for_stories_);
}
}
td_api::object_ptr<td_api::storyInteraction> StoryViewer::get_story_interaction_object(
ContactsManager *contacts_manager) const {
td_api::object_ptr<td_api::storyInteraction> StoryViewer::get_story_interaction_object(Td *td) const {
CHECK(is_valid());
auto type = [&]() -> td_api::object_ptr<td_api::StoryInteractionType> {
switch (type_) {
case Type::View:
return td_api::make_object<td_api::storyInteractionTypeView>(reaction_type_.get_reaction_type_object());
case Type::Forward: {
auto message_object =
td->messages_manager_->get_message_object(message_full_id_, "storyInteractionTypeForward");
CHECK(message_object != nullptr);
return td_api::make_object<td_api::storyInteractionTypeForward>(std::move(message_object));
}
case Type::Repost: {
auto story_object = td->story_manager_->get_story_object({actor_dialog_id_, story_id_});
CHECK(story_object != nullptr);
return td_api::make_object<td_api::storyInteractionTypeRepost>(std::move(story_object));
}
default:
UNREACHABLE();
return nullptr;
}
}();
auto block_list_id = BlockListId(is_blocked_, is_blocked_for_stories_);
return td_api::make_object<td_api::storyInteraction>(
contacts_manager->get_user_id_object(user_id_, "get_story_interaction_object"), date_,
block_list_id.get_block_list_object(), reaction_type_.get_reaction_type_object());
get_message_sender_object_const(td, actor_dialog_id_, "storyInteraction"), date_,
block_list_id.get_block_list_object(), std::move(type));
}
bool StoryViewer::is_valid() const {
return user_id_.is_valid() && date_ > 0;
return type_ != Type::None && actor_dialog_id_.is_valid() && date_ > 0;
}
StringBuilder &operator<<(StringBuilder &string_builder, const StoryViewer &viewer) {
return string_builder << '[' << viewer.user_id_ << " with " << viewer.reaction_type_ << " at " << viewer.date_ << ']';
return string_builder << '[' << viewer.actor_dialog_id_ << " with " << viewer.reaction_type_ << " at " << viewer.date_
<< ']';
}
StoryViewers::StoryViewers(Td *td, int32 total_count, int32 total_forward_count, int32 total_reaction_count,
@ -83,14 +149,11 @@ vector<DialogId> StoryViewers::get_actor_dialog_ids() const {
return transform(story_viewers_, [](auto &viewer) { return viewer.get_actor_dialog_id(); });
}
td_api::object_ptr<td_api::storyInteractions> StoryViewers::get_story_interactions_object(
ContactsManager *contacts_manager) const {
td_api::object_ptr<td_api::storyInteractions> StoryViewers::get_story_interactions_object(Td *td) const {
return td_api::make_object<td_api::storyInteractions>(
total_count_, total_forward_count_, total_reaction_count_,
transform(story_viewers_,
[contacts_manager](const StoryViewer &story_viewer) {
return story_viewer.get_story_interaction_object(contacts_manager);
}),
[td](const StoryViewer &story_viewer) { return story_viewer.get_story_interaction_object(td); }),
next_offset_);
}

View File

@ -7,7 +7,9 @@
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageFullId.h"
#include "td/telegram/ReactionType.h"
#include "td/telegram/StoryId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
@ -17,15 +19,20 @@
namespace td {
class ContactsManager;
class Td;
class StoryViewer {
UserId user_id_;
enum class Type : int32 { None, View, Forward, Repost };
Type type_ = Type::None;
DialogId actor_dialog_id_;
int32 date_ = 0;
bool is_blocked_ = false;
bool is_blocked_for_stories_ = false;
ReactionType reaction_type_;
ReactionType reaction_type_; // for View
MessageFullId message_full_id_; // for Forward
StoryId story_id_; // for Repost
friend StringBuilder &operator<<(StringBuilder &string_builder, const StoryViewer &viewer);
@ -33,16 +40,16 @@ class StoryViewer {
StoryViewer(Td *td, telegram_api::object_ptr<telegram_api::StoryView> &&story_view_ptr);
UserId get_viewer_user_id() const {
return user_id_;
return type_ == Type::View ? actor_dialog_id_.get_user_id() : UserId();
}
DialogId get_actor_dialog_id() const {
return DialogId(user_id_);
return actor_dialog_id_;
}
bool is_valid() const;
td_api::object_ptr<td_api::storyInteraction> get_story_interaction_object(ContactsManager *contacts_manager) const;
td_api::object_ptr<td_api::storyInteraction> get_story_interaction_object(Td *td) const;
};
StringBuilder &operator<<(StringBuilder &string_builder, const StoryViewer &viewer);
@ -64,7 +71,7 @@ class StoryViewers {
vector<DialogId> get_actor_dialog_ids() const;
td_api::object_ptr<td_api::storyInteractions> get_story_interactions_object(ContactsManager *contacts_manager) const;
td_api::object_ptr<td_api::storyInteractions> get_story_interactions_object(Td *td) const;
};
StringBuilder &operator<<(StringBuilder &string_builder, const StoryViewers &viewers);