From fc979564475b81e90f889ea0687c1e7a7c42abbf Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 18 Jul 2023 16:00:06 +0300 Subject: [PATCH] Add td_api::StoryPrivacySettings. --- td/generate/scheme/td_api.tl | 33 +++++++++---- td/telegram/StoryManager.cpp | 34 ++++++------- td/telegram/StoryManager.h | 6 +-- td/telegram/Td.cpp | 8 +-- td/telegram/Td.h | 2 +- td/telegram/UserPrivacySettingRule.cpp | 67 +++++++++++++++++++++++--- td/telegram/UserPrivacySettingRule.h | 7 +++ td/telegram/cli.cpp | 39 ++++++++++++--- 8 files changed, 146 insertions(+), 50 deletions(-) diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 0a0327a99..e135a275a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -4489,7 +4489,22 @@ jsonValueArray values:vector = JsonValue; jsonValueObject members:vector = JsonValue; -//@class UserPrivacySettingRule @description Represents a single rule for managing privacy settings +//@class StoryPrivacySettings @description Describes privacy settings of a story + +//@description The story can be viewed by everyone +storyPrivacySettingsEveryone = StoryPrivacySettings; + +//@description The story can be viewed by all contacts except chosen users @except_user_ids User identifiers of the contacts that can't see the story +storyPrivacySettingsContacts except_user_ids:vector = StoryPrivacySettings; + +//@description The story can be viewed by all close friends +storyPrivacySettingsCloseFriends = StoryPrivacySettings; + +//@description The story can be viewed by certain specified users @user_ids Identifiers of the users +storyPrivacySettingsSelectedContacts user_ids:vector = StoryPrivacySettings; + + +//@class UserPrivacySettingRule @description Represents a single rule for managing user privacy settings //@description A rule to allow all users to do something userPrivacySettingRuleAllowAll = UserPrivacySettingRule; @@ -4497,9 +4512,6 @@ userPrivacySettingRuleAllowAll = UserPrivacySettingRule; //@description A rule to allow all contacts of the user to do something userPrivacySettingRuleAllowContacts = UserPrivacySettingRule; -//@description A rule to allow all close friends of the user to do something -userPrivacySettingRuleAllowCloseFriends = UserPrivacySettingRule; - //@description A rule to allow certain specified users to do something @user_ids The user identifiers, total number of users in all rules must not exceed 1000 userPrivacySettingRuleAllowUsers user_ids:vector = UserPrivacySettingRule; @@ -4521,6 +4533,7 @@ userPrivacySettingRuleRestrictChatMembers chat_ids:vector = UserPrivacySe //@description A list of privacy rules. Rules are matched in the specified order. The first matched rule defines the privacy setting for a given user. If no rule matches, the action is not allowed @rules A list of rules userPrivacySettingRules rules:vector = UserPrivacySettingRules; + //@class UserPrivacySetting @description Describes available user privacy settings //@description A privacy setting for managing whether the user's online status is visible @@ -4955,10 +4968,10 @@ storyInteractionInfo view_count:int32 recent_viewer_user_ids:vector = Sto //@can_get_viewers True, if users viewed the story can be received through getStoryViewers //@has_expired_viewers True, if users viewed the story can't be received, because the story has expired more than getOption("story_viewers_expiration_delay") seconds ago //@interaction_info Information about interactions with the story; may be null if the story isn't owned or there were no interactions -//@privacy_rules Privacy rules affecting story visibility; may be null if the story isn't owned +//@privacy_settings Privacy rules affecting story visibility; may be null if the story isn't owned //@content Content of the story //@caption Caption of the story -story id:int32 sender_chat_id:int53 date:int32 is_being_edited:Bool is_edited:Bool is_pinned:Bool is_visible_only_for_self:Bool can_be_forwarded:Bool can_be_replied:Bool can_get_viewers:Bool has_expired_viewers:Bool interaction_info:storyInteractionInfo privacy_rules:userPrivacySettingRules content:StoryContent caption:formattedText = Story; +story id:int32 sender_chat_id:int53 date:int32 is_being_edited:Bool is_edited:Bool is_pinned:Bool is_visible_only_for_self:Bool can_be_forwarded:Bool can_be_replied:Bool can_get_viewers:Bool has_expired_viewers:Bool interaction_info:storyInteractionInfo privacy_settings:StoryPrivacySettings content:StoryContent caption:formattedText = Story; //@description Represents a list of stories @total_count Approximate total number of stories found @stories The list of stories stories total_count:int32 stories:vector = Stories; @@ -7293,11 +7306,11 @@ getStory story_sender_chat_id:int53 story_id:int32 only_local:Bool = Story; //@description Sends a new story. Returns a temporary story with identifier 0 //@content Content of the story //@caption Story caption; pass null to use an empty caption; 0-getOption("story_caption_length_max") characters -//@privacy_rules The privacy rules for the story +//@privacy_settings The privacy settings for the story //@active_period Period after which the story is moved to archive, in seconds; must be one of 6 * 3600, 12 * 3600, 86400, 2 * 86400, 3 * 86400, or 7 * 86400 for Telegram Premium users, and 86400 otherwise //@is_pinned Pass true to keep the story accessible after expiration //@protect_content Pass true if the content of the story must be protected from forwarding and screenshotting -sendStory content:InputStoryContent caption:formattedText privacy_rules:userPrivacySettingRules active_period:int32 is_pinned:Bool protect_content:Bool = Story; +sendStory content:InputStoryContent caption:formattedText privacy_settings:StoryPrivacySettings active_period:int32 is_pinned:Bool protect_content:Bool = Story; //@description Changes content and caption of a previously sent story //@story_id Identifier of the story to edit @@ -7305,8 +7318,8 @@ sendStory content:InputStoryContent caption:formattedText privacy_rules:userPriv //@caption New story caption; pass null to keep the current caption editStory story_id:int32 content:InputStoryContent caption:formattedText = Ok; -//@description Changes privacy rules of a previously sent story @story_id Identifier of the story @privacy_rules The new privacy rules for the story -setStoryPrivacyRules story_id:int32 privacy_rules:userPrivacySettingRules = Ok; +//@description Changes privacy settings of a previously sent story @story_id Identifier of the story @privacy_settings The new privacy settigs for the story +setStoryPrivacySettings story_id:int32 privacy_settings:StoryPrivacySettings = Ok; //@description Toggles whether a story is accessible after expiration @story_id Identifier of the story @is_pinned Pass true to make the story accessible after expiration; pass false to make it private toggleStoryIsPinned story_id:int32 is_pinned:Bool = Ok; diff --git a/td/telegram/StoryManager.cpp b/td/telegram/StoryManager.cpp index 8aa3dadd7..587775070 100644 --- a/td/telegram/StoryManager.cpp +++ b/td/telegram/StoryManager.cpp @@ -2273,16 +2273,13 @@ td_api::object_ptr StoryManager::get_story_object(StoryFullId sto return nullptr; } - td_api::object_ptr privacy_rules; - if (story->is_public_ || story->is_for_close_friends_) { - privacy_rules = td_api::make_object(); - if (story->is_public_) { - privacy_rules->rules_.push_back(td_api::make_object()); - } else { - privacy_rules->rules_.push_back(td_api::make_object()); - } + td_api::object_ptr privacy_settings; + if (story->is_public_) { + privacy_settings = td_api::make_object(); + } else if (story->is_for_close_friends_) { + privacy_settings = td_api::make_object(); } else if (is_owned) { - privacy_rules = story->privacy_rules_.get_user_privacy_setting_rules_object(td_); + privacy_settings = story->privacy_rules_.get_story_privacy_settings_object(td_); } bool is_being_edited = false; @@ -2307,9 +2304,8 @@ td_api::object_ptr StoryManager::get_story_object(StoryFullId sto auto changelog_dialog_id = get_changelog_story_dialog_id(); bool is_visible_only_for_self = !story_id.is_server() || dialog_id == changelog_dialog_id || (!story->is_pinned_ && !is_active_story(story)); - bool can_be_forwarded = !story->noforwards_ && story_id.is_server() && privacy_rules != nullptr && - privacy_rules->rules_.size() == 1u && - privacy_rules->rules_[0]->get_id() == td_api::userPrivacySettingRuleAllowAll::ID; + bool can_be_forwarded = !story->noforwards_ && story_id.is_server() && privacy_settings != nullptr && + privacy_settings->get_id() == td_api::storyPrivacySettingsEveryone::ID; bool can_be_replied = story_id.is_server() && dialog_id != changelog_dialog_id; bool can_get_viewers = can_get_story_viewers(story_full_id, story).is_ok(); bool has_expired_viewers = !can_get_viewers && is_story_owned(dialog_id) && story_id.is_server(); @@ -2320,7 +2316,7 @@ td_api::object_ptr StoryManager::get_story_object(StoryFullId sto story_id.get(), td_->messages_manager_->get_chat_id_object(dialog_id, "get_story_object"), story->date_, is_being_edited, is_edited, story->is_pinned_, is_visible_only_for_self, can_be_forwarded, can_be_replied, can_get_viewers, has_expired_viewers, story->interaction_info_.get_story_interaction_info_object(td_), - std::move(privacy_rules), get_story_content_object(td_, content), + std::move(privacy_settings), get_story_content_object(td_, content), get_formatted_text_object(*caption, true, get_story_content_duration(td_, content))); } @@ -3286,7 +3282,7 @@ void StoryManager::do_get_story(StoryFullId story_full_id, Result &&result void StoryManager::send_story(td_api::object_ptr &&input_story_content, td_api::object_ptr &&input_caption, - td_api::object_ptr &&rules, int32 active_period, + td_api::object_ptr &&settings, int32 active_period, bool is_pinned, bool protect_content, Promise> &&promise) { bool is_bot = td_->auth_manager_->is_bot(); @@ -3295,7 +3291,7 @@ void StoryManager::send_story(td_api::object_ptr &&in TRY_RESULT_PROMISE(promise, caption, get_formatted_text(td_, DialogId(), std::move(input_caption), is_bot, true, false, false)); TRY_RESULT_PROMISE(promise, privacy_rules, - UserPrivacySettingRules::get_user_privacy_setting_rules(td_, std::move(rules))); + UserPrivacySettingRules::get_user_privacy_setting_rules(td_, std::move(settings))); if (active_period != 86400 && !(G()->is_test_dc() && (active_period == 60 || active_period == 300))) { bool is_premium = td_->option_manager_->get_option_boolean("is_premium"); if (!is_premium || @@ -3659,16 +3655,16 @@ void StoryManager::delete_pending_story(FileId file_id, unique_ptr } } -void StoryManager::set_story_privacy_rules(StoryId story_id, - td_api::object_ptr &&rules, - Promise &&promise) { +void StoryManager::set_story_privacy_settings(StoryId story_id, + td_api::object_ptr &&settings, + Promise &&promise) { DialogId dialog_id(td_->contacts_manager_->get_my_id()); const Story *story = get_story({dialog_id, story_id}); if (story == nullptr || story->content_ == nullptr) { return promise.set_error(Status::Error(400, "Story not found")); } TRY_RESULT_PROMISE(promise, privacy_rules, - UserPrivacySettingRules::get_user_privacy_setting_rules(td_, std::move(rules))); + UserPrivacySettingRules::get_user_privacy_setting_rules(td_, std::move(settings))); td_->create_handler(std::move(promise))->send(dialog_id, story_id, std::move(privacy_rules)); } diff --git a/td/telegram/StoryManager.h b/td/telegram/StoryManager.h index cf3afac5b..6aff86696 100644 --- a/td/telegram/StoryManager.h +++ b/td/telegram/StoryManager.h @@ -195,7 +195,7 @@ class StoryManager final : public Actor { void send_story(td_api::object_ptr &&input_story_content, td_api::object_ptr &&input_caption, - td_api::object_ptr &&rules, int32 active_period, bool is_pinned, + td_api::object_ptr &&settings, int32 active_period, bool is_pinned, bool protect_content, Promise> &&promise); void on_send_story_file_parts_missing(unique_ptr &&pending_story, vector &&bad_parts); @@ -203,8 +203,8 @@ class StoryManager final : public Actor { void edit_story(StoryId story_id, td_api::object_ptr &&input_story_content, td_api::object_ptr &&input_caption, Promise &&promise); - void set_story_privacy_rules(StoryId story_id, td_api::object_ptr &&rules, - Promise &&promise); + void set_story_privacy_settings(StoryId story_id, td_api::object_ptr &&settings, + Promise &&promise); void toggle_story_is_pinned(StoryId story_id, bool is_pinned, Promise &&promise); diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index d40096f11..e5d40a3d1 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5635,7 +5635,7 @@ void Td::on_request(uint64 id, td_api::sendStory &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); story_manager_->send_story(std::move(request.content_), std::move(request.caption_), - std::move(request.privacy_rules_), request.active_period_, request.is_pinned_, + std::move(request.privacy_settings_), request.active_period_, request.is_pinned_, request.protect_content_, std::move(promise)); } @@ -5646,11 +5646,11 @@ void Td::on_request(uint64 id, td_api::editStory &request) { std::move(promise)); } -void Td::on_request(uint64 id, td_api::setStoryPrivacyRules &request) { +void Td::on_request(uint64 id, td_api::setStoryPrivacySettings &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - story_manager_->set_story_privacy_rules(StoryId(request.story_id_), std::move(request.privacy_rules_), - std::move(promise)); + story_manager_->set_story_privacy_settings(StoryId(request.story_id_), std::move(request.privacy_settings_), + std::move(promise)); } void Td::on_request(uint64 id, const td_api::toggleStoryIsPinned &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 9187f5a57..ec6bcac0a 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -792,7 +792,7 @@ class Td final : public Actor { void on_request(uint64 id, td_api::editStory &request); - void on_request(uint64 id, td_api::setStoryPrivacyRules &request); + void on_request(uint64 id, td_api::setStoryPrivacySettings &request); void on_request(uint64 id, const td_api::toggleStoryIsPinned &request); diff --git a/td/telegram/UserPrivacySettingRule.cpp b/td/telegram/UserPrivacySettingRule.cpp index 9ee15a5fa..b11efcdb4 100644 --- a/td/telegram/UserPrivacySettingRule.cpp +++ b/td/telegram/UserPrivacySettingRule.cpp @@ -53,9 +53,6 @@ UserPrivacySettingRule::UserPrivacySettingRule(Td *td, const td_api::UserPrivacy case td_api::userPrivacySettingRuleAllowContacts::ID: type_ = Type::AllowContacts; break; - case td_api::userPrivacySettingRuleAllowCloseFriends::ID: - type_ = Type::AllowCloseFriends; - break; case td_api::userPrivacySettingRuleAllowAll::ID: type_ = Type::AllowAll; break; @@ -160,7 +157,8 @@ td_api::object_ptr UserPrivacySettingRule::get_u case Type::AllowContacts: return make_tl_object(); case Type::AllowCloseFriends: - return make_tl_object(); + LOG(ERROR) << "Have AllowCloseFriends rule"; + return make_tl_object(); case Type::AllowAll: return make_tl_object(); case Type::AllowUsers: @@ -269,8 +267,7 @@ UserPrivacySettingRules UserPrivacySettingRules::get_user_privacy_setting_rules( for (auto &rule : rules) { result.rules_.push_back(UserPrivacySettingRule(td, std::move(rule))); } - if (!result.rules_.empty() && result.rules_.back().get_user_privacy_setting_rule_object(td)->get_id() == - td_api::userPrivacySettingRuleRestrictAll::ID) { + if (!result.rules_.empty() && result.rules_.back().type_ == UserPrivacySettingRule::Type::RestrictAll) { result.rules_.pop_back(); } return result; @@ -291,12 +288,70 @@ Result UserPrivacySettingRules::get_user_privacy_settin return result; } +Result UserPrivacySettingRules::get_user_privacy_setting_rules( + Td *td, td_api::object_ptr settings) { + if (settings == nullptr) { + return Status::Error(400, "StoryPrivacySettings must be non-empty"); + } + UserPrivacySettingRules result; + switch (settings->get_id()) { + case td_api::storyPrivacySettingsEveryone::ID: + result.rules_.emplace_back(td, td_api::userPrivacySettingRuleAllowAll()); + break; + case td_api::storyPrivacySettingsContacts::ID: { + auto user_ids = std::move(static_cast(*settings).except_user_ids_); + if (!user_ids.empty()) { + result.rules_.emplace_back(td, td_api::userPrivacySettingRuleRestrictUsers(std::move(user_ids))); + } + result.rules_.emplace_back(td, td_api::userPrivacySettingRuleAllowContacts()); + break; + } + case td_api::storyPrivacySettingsCloseFriends::ID: { + UserPrivacySettingRule rule; + rule.type_ = UserPrivacySettingRule::Type::AllowCloseFriends; + result.rules_.push_back(std::move(rule)); + break; + } + case td_api::storyPrivacySettingsSelectedContacts::ID: { + auto user_ids = std::move(static_cast(*settings).user_ids_); + result.rules_.emplace_back(td, td_api::userPrivacySettingRuleAllowUsers(std::move(user_ids))); + break; + } + default: + UNREACHABLE(); + } + return result; +} + td_api::object_ptr UserPrivacySettingRules::get_user_privacy_setting_rules_object( Td *td) const { return make_tl_object( transform(rules_, [td](const auto &rule) { return rule.get_user_privacy_setting_rule_object(td); })); } +td_api::object_ptr UserPrivacySettingRules::get_story_privacy_settings_object( + Td *td) const { + if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowAll) { + return td_api::make_object(); + } + if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowContacts) { + return td_api::make_object(); + } + if (rules_.size() == 2u && rules_[0].type_ == UserPrivacySettingRule::Type::RestrictUsers && + rules_[1].type_ == UserPrivacySettingRule::Type::AllowContacts) { + return td_api::make_object( + td->contacts_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsContacts")); + } + if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowCloseFriends) { + return td_api::make_object(); + } + if (rules_.size() == 1u && rules_[0].type_ == UserPrivacySettingRule::Type::AllowUsers) { + return td_api::make_object( + td->contacts_manager_->get_user_ids_object(rules_[0].user_ids_, "storyPrivacySettingsSelectedContacts")); + } + return td_api::make_object(); +} + vector> UserPrivacySettingRules::get_input_privacy_rules( Td *td) const { auto result = transform(rules_, [td](const auto &rule) { return rule.get_input_privacy_rule(td); }); diff --git a/td/telegram/UserPrivacySettingRule.h b/td/telegram/UserPrivacySettingRule.h index e0b79986e..e18b09b24 100644 --- a/td/telegram/UserPrivacySettingRule.h +++ b/td/telegram/UserPrivacySettingRule.h @@ -88,6 +88,8 @@ class UserPrivacySettingRule { RestrictChatParticipants } type_ = Type::RestrictAll; + friend class UserPrivacySettingRules; + vector user_ids_; vector dialog_ids_; @@ -113,8 +115,13 @@ class UserPrivacySettingRules { static Result get_user_privacy_setting_rules( Td *td, td_api::object_ptr rules); + static Result get_user_privacy_setting_rules( + Td *td, td_api::object_ptr settings); + td_api::object_ptr get_user_privacy_setting_rules_object(Td *td) const; + td_api::object_ptr get_story_privacy_settings_object(Td *td) const; + vector> get_input_privacy_rules(Td *td) const; bool operator==(const UserPrivacySettingRules &other) const { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 65e41caa5..7084d3213 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1127,8 +1127,6 @@ class CliClient final : public Actor { rules.push_back(td_api::make_object()); } else if (rules_str[i] == 'C') { rules.push_back(td_api::make_object()); - } else if (rules_str[i] == 'f') { - rules.push_back(td_api::make_object()); } else if (rules_str[i] == 'u') { rules.push_back(td_api::make_object(std::move(arg))); } else if (rules_str[i] == 'U') { @@ -1153,6 +1151,33 @@ class CliClient final : public Actor { } } + struct StoryPrivacySettings { + string settings; + + operator td_api::object_ptr() const { + if (settings == "a" || settings == "e") { + return td_api::make_object(); + } + if (settings == "f" || settings == "cf") { + return td_api::make_object(); + } + if (!settings.empty()) { + auto user_ids = to_integers(Slice(settings).substr(1)); + if (settings[0] == 'c') { + return td_api::make_object(std::move(user_ids)); + } + if (settings[0] == 'u') { + return td_api::make_object(std::move(user_ids)); + } + } + return td_api::make_object(); + } + }; + + void get_args(string &args, StoryPrivacySettings &arg) const { + arg.settings = trim(args); + } + template void get_args(string &args, FirstType &first_arg, SecondType &second_arg, Types &...other_args) const { string arg; @@ -3990,7 +4015,7 @@ class CliClient final : public Actor { } else if (op == "ssp" || op == "sspp") { string photo; string caption; - PrivacyRules rules; + StoryPrivacySettings rules; int32 active_period; string sticker_file_ids; bool protect_content; @@ -4002,7 +4027,7 @@ class CliClient final : public Actor { } else if (op == "ssv" || op == "ssvp") { string video; string caption; - PrivacyRules rules; + StoryPrivacySettings rules; int32 active_period; double duration; string sticker_file_ids; @@ -4040,11 +4065,11 @@ class CliClient final : public Actor { td_api::make_object(as_input_file(video), to_integers(sticker_file_ids), duration, false), as_caption(caption))); - } else if (op == "sspr") { + } else if (op == "ssps") { StoryId story_id; - PrivacyRules rules; + StoryPrivacySettings rules; get_args(args, story_id, rules); - send_request(td_api::make_object(story_id, rules)); + send_request(td_api::make_object(story_id, rules)); } else if (op == "tsip") { StoryId story_id; bool is_pinned;