From 5bd73bab9b4e989114025cca3d643a06672cfb0c Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 31 Jul 2021 17:11:53 +0300 Subject: [PATCH] Moved user privacy from ApiWrap to Api::UserPrivacy. --- Telegram/CMakeLists.txt | 2 + Telegram/SourceFiles/api/api_updates.cpp | 12 +- Telegram/SourceFiles/api/api_user_privacy.cpp | 303 ++++++++++++++++++ Telegram/SourceFiles/api/api_user_privacy.h | 73 +++++ Telegram/SourceFiles/apiwrap.cpp | 208 +----------- Telegram/SourceFiles/apiwrap.h | 50 +-- .../SourceFiles/boxes/edit_privacy_box.cpp | 66 +--- Telegram/SourceFiles/boxes/edit_privacy_box.h | 12 +- Telegram/SourceFiles/main/main_session.cpp | 11 +- .../settings/settings_privacy_controllers.cpp | 67 ++-- .../settings/settings_privacy_controllers.h | 7 - .../settings/settings_privacy_security.cpp | 14 +- .../settings/settings_privacy_security.h | 4 +- 13 files changed, 439 insertions(+), 390 deletions(-) create mode 100644 Telegram/SourceFiles/api/api_user_privacy.cpp create mode 100644 Telegram/SourceFiles/api/api_user_privacy.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 3091dbe684..9542f86aa9 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -124,6 +124,8 @@ PRIVATE api/api_toggling_media.h api/api_updates.cpp api/api_updates.h + api/api_user_privacy.cpp + api/api_user_privacy.h boxes/filters/edit_filter_box.cpp boxes/filters/edit_filter_box.h boxes/filters/edit_filter_chats_list.cpp diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp index 8ac2261ac7..edd4ab362a 100644 --- a/Telegram/SourceFiles/api/api_updates.cpp +++ b/Telegram/SourceFiles/api/api_updates.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_authorizations.h" #include "api/api_text_entities.h" +#include "api/api_user_privacy.h" #include "main/main_session.h" #include "main/main_account.h" #include "mtproto/mtp_instance.h" @@ -1954,13 +1955,10 @@ void Updates::feedUpdate(const MTPUpdate &update) { } return true; }; - if (const auto key = ApiWrap::Privacy::KeyFromMTP(d.vkey().type())) { - if (allLoaded()) { - session().api().handlePrivacyChange(*key, d.vrules()); - } else { - session().api().reloadPrivacy(*key); - } - } + session().api().userPrivacy().apply( + d.vkey().type(), + d.vrules(), + allLoaded()); } break; case mtpc_updatePinnedDialogs: { diff --git a/Telegram/SourceFiles/api/api_user_privacy.cpp b/Telegram/SourceFiles/api/api_user_privacy.cpp new file mode 100644 index 0000000000..da5f9d1909 --- /dev/null +++ b/Telegram/SourceFiles/api/api_user_privacy.cpp @@ -0,0 +1,303 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "api/api_user_privacy.h" + +#include "apiwrap.h" +#include "data/data_chat.h" +#include "data/data_channel.h" +#include "data/data_peer.h" +#include "data/data_peer_id.h" +#include "data/data_session.h" +#include "data/data_user.h" +#include "main/main_session.h" + +namespace Api { +namespace { + +constexpr auto kMaxRules = 3; // Allow users, disallow users, Option. + +using TLInputRules = MTPVector; +using TLRules = MTPVector; + +TLInputRules RulesToTL(const UserPrivacy::Rule &rule) { + const auto collectInputUsers = [](const auto &peers) { + auto result = QVector(); + result.reserve(peers.size()); + for (const auto peer : peers) { + if (const auto user = peer->asUser()) { + result.push_back(user->inputUser); + } + } + return result; + }; + const auto collectInputChats = [](const auto &peers) { + auto result = QVector(); // #TODO ids + result.reserve(peers.size()); + for (const auto peer : peers) { + if (!peer->isUser()) { + result.push_back(peerToBareMTPInt(peer->id)); + } + } + return result; + }; + + auto result = QVector(); + result.reserve(kMaxRules); + if (!rule.ignoreAlways) { + const auto users = collectInputUsers(rule.always); + const auto chats = collectInputChats(rule.always); + if (!users.empty()) { + result.push_back( + MTP_inputPrivacyValueAllowUsers( + MTP_vector(users))); + } + if (!chats.empty()) { + result.push_back( + MTP_inputPrivacyValueAllowChatParticipants( + MTP_vector(chats))); + } + } + if (!rule.ignoreNever) { + const auto users = collectInputUsers(rule.never); + const auto chats = collectInputChats(rule.never); + if (!users.empty()) { + result.push_back( + MTP_inputPrivacyValueDisallowUsers( + MTP_vector(users))); + } + if (!chats.empty()) { + result.push_back( + MTP_inputPrivacyValueDisallowChatParticipants( + MTP_vector(chats))); + } + } + result.push_back([&] { + using Option = UserPrivacy::Option; + switch (rule.option) { + case Option::Everyone: return MTP_inputPrivacyValueAllowAll(); + case Option::Contacts: return MTP_inputPrivacyValueAllowContacts(); + case Option::Nobody: return MTP_inputPrivacyValueDisallowAll(); + } + Unexpected("Option value in Api::UserPrivacy::RulesToTL."); + }()); + + + return MTP_vector(std::move(result)); +} + +UserPrivacy::Rule TLToRules(const TLRules &rules, Data::Session &owner) { + // This is simplified version of privacy rules interpretation. + // But it should be fine for all the apps + // that use the same subset of features. + using Option = UserPrivacy::Option; + auto result = UserPrivacy::Rule(); + auto optionSet = false; + const auto setOption = [&](Option option) { + if (optionSet) return; + optionSet = true; + result.option = option; + }; + auto &always = result.always; + auto &never = result.never; + const auto feed = [&](const MTPPrivacyRule &rule) { + rule.match([&](const MTPDprivacyValueAllowAll &) { + setOption(Option::Everyone); + }, [&](const MTPDprivacyValueAllowContacts &) { + setOption(Option::Contacts); + }, [&](const MTPDprivacyValueAllowUsers &data) { + const auto &users = data.vusers().v; + always.reserve(always.size() + users.size()); + for (const auto userId : users) { + const auto user = owner.user(UserId(userId.v)); + if (!base::contains(never, user) + && !base::contains(always, user)) { + always.emplace_back(user); + } + } + }, [&](const MTPDprivacyValueAllowChatParticipants &data) { + const auto &chats = data.vchats().v; + always.reserve(always.size() + chats.size()); + for (const auto &chatId : chats) { + const auto chat = owner.chatLoaded(chatId); + const auto peer = chat + ? static_cast(chat) + : owner.channelLoaded(chatId); + if (peer + && !base::contains(never, peer) + && !base::contains(always, peer)) { + always.emplace_back(peer); + } + } + }, [&](const MTPDprivacyValueDisallowContacts &) { + // Not supported + }, [&](const MTPDprivacyValueDisallowAll &) { + setOption(Option::Nobody); + }, [&](const MTPDprivacyValueDisallowUsers &data) { + const auto &users = data.vusers().v; + never.reserve(never.size() + users.size()); + for (const auto userId : users) { + const auto user = owner.user(UserId(userId.v)); + if (!base::contains(always, user) + && !base::contains(never, user)) { + never.emplace_back(user); + } + } + }, [&](const MTPDprivacyValueDisallowChatParticipants &data) { + const auto &chats = data.vchats().v; + never.reserve(never.size() + chats.size()); + for (const auto &chatId : chats) { + const auto chat = owner.chatLoaded(chatId); + const auto peer = chat + ? static_cast(chat) + : owner.channelLoaded(chatId); + if (peer + && !base::contains(always, peer) + && !base::contains(never, peer)) { + never.emplace_back(peer); + } + } + }); + }; + for (const auto &rule : rules.v) { + feed(rule); + } + feed(MTP_privacyValueDisallowAll()); // Disallow by default. + return result; +} + +MTPInputPrivacyKey KeyToTL(UserPrivacy::Key key) { + using Key = UserPrivacy::Key; + switch (key) { + case Key::Calls: return MTP_inputPrivacyKeyPhoneCall(); + case Key::Invites: return MTP_inputPrivacyKeyChatInvite(); + case Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber(); + case Key::AddedByPhone: + return MTP_inputPrivacyKeyAddedByPhone(); + case Key::LastSeen: + return MTP_inputPrivacyKeyStatusTimestamp(); + case Key::CallsPeer2Peer: + return MTP_inputPrivacyKeyPhoneP2P(); + case Key::Forwards: + return MTP_inputPrivacyKeyForwards(); + case Key::ProfilePhoto: + return MTP_inputPrivacyKeyProfilePhoto(); + } + Unexpected("Key in Api::UserPrivacy::KetToTL."); +} + +std::optional TLToKey(mtpTypeId type) { + using Key = UserPrivacy::Key; + switch (type) { + case mtpc_privacyKeyPhoneNumber: + case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber; + case mtpc_privacyKeyAddedByPhone: + case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone; + case mtpc_privacyKeyStatusTimestamp: + case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen; + case mtpc_privacyKeyChatInvite: + case mtpc_inputPrivacyKeyChatInvite: return Key::Invites; + case mtpc_privacyKeyPhoneCall: + case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls; + case mtpc_privacyKeyPhoneP2P: + case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer; + case mtpc_privacyKeyForwards: + case mtpc_inputPrivacyKeyForwards: return Key::Forwards; + case mtpc_privacyKeyProfilePhoto: + case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto; + } + return std::nullopt; +} + +} // namespace + +UserPrivacy::UserPrivacy(not_null api) +: _session(&api->session()) +, _api(&api->instance()) { +} + +void UserPrivacy::save( + Key key, + const UserPrivacy::Rule &rule) { + const auto tlKey = KeyToTL(key); + const auto keyTypeId = tlKey.type(); + const auto it = _privacySaveRequests.find(keyTypeId); + if (it != _privacySaveRequests.cend()) { + _api.request(it->second).cancel(); + _privacySaveRequests.erase(it); + } + + const auto requestId = _api.request(MTPaccount_SetPrivacy( + tlKey, + RulesToTL(rule) + )).done([=](const MTPaccount_PrivacyRules &result) { + result.match([&](const MTPDaccount_privacyRules &data) { + _session->data().processUsers(data.vusers()); + _session->data().processChats(data.vchats()); + _privacySaveRequests.remove(keyTypeId); + apply(keyTypeId, data.vrules(), true); + }); + }).fail([=](const MTP::Error &error) { + _privacySaveRequests.remove(keyTypeId); + }).send(); + + _privacySaveRequests.emplace(keyTypeId, requestId); +} + +void UserPrivacy::apply( + mtpTypeId type, + const TLRules &rules, + bool allLoaded) { + if (const auto key = TLToKey(type)) { + if (!allLoaded) { + reload(*key); + return; + } + pushPrivacy(*key, rules); + if ((*key) == Key::LastSeen) { + _session->api().updatePrivacyLastSeens(); + } + } +} + +void UserPrivacy::reload(Key key) { + if (_privacyRequestIds.contains(key)) { + return; + } + const auto requestId = _api.request(MTPaccount_GetPrivacy( + KeyToTL(key) + )).done([=](const MTPaccount_PrivacyRules &result) { + _privacyRequestIds.erase(key); + result.match([&](const MTPDaccount_privacyRules &data) { + _session->data().processUsers(data.vusers()); + _session->data().processChats(data.vchats()); + pushPrivacy(key, data.vrules()); + }); + }).fail([=](const MTP::Error &error) { + _privacyRequestIds.erase(key); + }).send(); + _privacyRequestIds.emplace(key, requestId); +} + +void UserPrivacy::pushPrivacy(Key key, const TLRules &rules) { + const auto &saved = (_privacyValues[key] = + TLToRules(rules, _session->data())); + const auto i = _privacyChanges.find(key); + if (i != end(_privacyChanges)) { + i->second.fire_copy(saved); + } +} + +auto UserPrivacy::value(Key key) -> rpl::producer { + if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) { + return _privacyChanges[key].events_starting_with_copy(i->second); + } else { + return _privacyChanges[key].events(); + } +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_user_privacy.h b/Telegram/SourceFiles/api/api_user_privacy.h new file mode 100644 index 0000000000..a706cea020 --- /dev/null +++ b/Telegram/SourceFiles/api/api_user_privacy.h @@ -0,0 +1,73 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +#include "mtproto/sender.h" + +class ApiWrap; + +namespace Main { +class Session; +} // namespace Main + +namespace Api { + +class UserPrivacy final { +public: + enum class Key { + PhoneNumber, + AddedByPhone, + LastSeen, + Calls, + Invites, + CallsPeer2Peer, + Forwards, + ProfilePhoto, + }; + enum class Option { + Everyone, + Contacts, + Nobody, + }; + struct Rule { + Option option = Option::Everyone; + std::vector> always; + std::vector> never; + bool ignoreAlways = false; + bool ignoreNever = false; + }; + + explicit UserPrivacy(not_null api); + + void save( + Key key, + const UserPrivacy::Rule &rule); + void apply( + mtpTypeId type, + const MTPVector &rules, + bool allLoaded); + + void reload(Key key); + rpl::producer value(Key key); + +private: + const not_null _session; + + void pushPrivacy(Key key, const MTPVector &rules); + + base::flat_map _privacySaveRequests; + + base::flat_map _privacyRequestIds; + base::flat_map _privacyValues; + std::map> _privacyChanges; + + MTP::Sender _api; + +}; + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 14b57e4ad9..09dcd2ddbb 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "api/api_sensitive_content.h" #include "api/api_global_privacy.h" #include "api/api_updates.h" +#include "api/api_user_privacy.h" #include "data/stickers/data_stickers.h" #include "data/data_drafts.h" #include "data/data_changes.h" @@ -120,49 +121,6 @@ using UpdatedFileReferences = Data::UpdatedFileReferences; } // namespace -MTPInputPrivacyKey ApiWrap::Privacy::Input(Key key) { - switch (key) { - case Privacy::Key::Calls: return MTP_inputPrivacyKeyPhoneCall(); - case Privacy::Key::Invites: return MTP_inputPrivacyKeyChatInvite(); - case Privacy::Key::PhoneNumber: return MTP_inputPrivacyKeyPhoneNumber(); - case Privacy::Key::AddedByPhone: - return MTP_inputPrivacyKeyAddedByPhone(); - case Privacy::Key::LastSeen: - return MTP_inputPrivacyKeyStatusTimestamp(); - case Privacy::Key::CallsPeer2Peer: - return MTP_inputPrivacyKeyPhoneP2P(); - case Privacy::Key::Forwards: - return MTP_inputPrivacyKeyForwards(); - case Privacy::Key::ProfilePhoto: - return MTP_inputPrivacyKeyProfilePhoto(); - } - Unexpected("Key in ApiWrap::Privacy::Input."); -} - -std::optional ApiWrap::Privacy::KeyFromMTP( - mtpTypeId type) { - using Key = Privacy::Key; - switch (type) { - case mtpc_privacyKeyPhoneNumber: - case mtpc_inputPrivacyKeyPhoneNumber: return Key::PhoneNumber; - case mtpc_privacyKeyAddedByPhone: - case mtpc_inputPrivacyKeyAddedByPhone: return Key::AddedByPhone; - case mtpc_privacyKeyStatusTimestamp: - case mtpc_inputPrivacyKeyStatusTimestamp: return Key::LastSeen; - case mtpc_privacyKeyChatInvite: - case mtpc_inputPrivacyKeyChatInvite: return Key::Invites; - case mtpc_privacyKeyPhoneCall: - case mtpc_inputPrivacyKeyPhoneCall: return Key::Calls; - case mtpc_privacyKeyPhoneP2P: - case mtpc_inputPrivacyKeyPhoneP2P: return Key::CallsPeer2Peer; - case mtpc_privacyKeyForwards: - case mtpc_inputPrivacyKeyForwards: return Key::Forwards; - case mtpc_privacyKeyProfilePhoto: - case mtpc_inputPrivacyKeyProfilePhoto: return Key::ProfilePhoto; - } - return std::nullopt; -} - bool ApiWrap::BlockedPeersSlice::Item::operator==(const Item &other) const { return (peer == other.peer) && (date == other.date); } @@ -195,6 +153,7 @@ ApiWrap::ApiWrap(not_null session) , _selfDestruct(std::make_unique(this)) , _sensitiveContent(std::make_unique(this)) , _globalPrivacy(std::make_unique(this)) +, _userPrivacy(std::make_unique(this)) , _inviteLinks(std::make_unique(this)) { crl::on_main(session, [=] { // You can't use _session->lifetime() in the constructor, @@ -2309,45 +2268,7 @@ void ApiWrap::saveDraftToCloudDelayed(not_null history) { } } -void ApiWrap::savePrivacy( - const MTPInputPrivacyKey &key, - QVector &&rules) { - const auto keyTypeId = key.type(); - const auto it = _privacySaveRequests.find(keyTypeId); - if (it != _privacySaveRequests.cend()) { - request(it->second).cancel(); - _privacySaveRequests.erase(it); - } - - const auto requestId = request(MTPaccount_SetPrivacy( - key, - MTP_vector(std::move(rules)) - )).done([=](const MTPaccount_PrivacyRules &result) { - result.match([&](const MTPDaccount_privacyRules &data) { - _session->data().processUsers(data.vusers()); - _session->data().processChats(data.vchats()); - _privacySaveRequests.remove(keyTypeId); - if (const auto key = Privacy::KeyFromMTP(keyTypeId)) { - handlePrivacyChange(*key, data.vrules()); - } - }); - }).fail([=](const MTP::Error &error) { - _privacySaveRequests.remove(keyTypeId); - }).send(); - - _privacySaveRequests.emplace(keyTypeId, requestId); -} - -void ApiWrap::handlePrivacyChange( - Privacy::Key key, - const MTPVector &rules) { - pushPrivacy(key, rules.v); - if (key == Privacy::Key::LastSeen) { - updatePrivacyLastSeens(rules.v); - } -} - -void ApiWrap::updatePrivacyLastSeens(const QVector &rules) { +void ApiWrap::updatePrivacyLastSeens() { const auto now = base::unixtime::now(); _session->data().enumerateUsers([&](UserData *user) { if (user->isSelf() || !user->isFullLoaded()) { @@ -4878,125 +4799,6 @@ void ApiWrap::saveSelfBio(const QString &text, FnMut done) { }).send(); } -void ApiWrap::reloadPrivacy(Privacy::Key key) { - if (_privacyRequestIds.contains(key)) { - return; - } - const auto requestId = request(MTPaccount_GetPrivacy( - Privacy::Input(key) - )).done([=](const MTPaccount_PrivacyRules &result) { - _privacyRequestIds.erase(key); - result.match([&](const MTPDaccount_privacyRules &data) { - _session->data().processUsers(data.vusers()); - _session->data().processChats(data.vchats()); - pushPrivacy(key, data.vrules().v); - }); - }).fail([=](const MTP::Error &error) { - _privacyRequestIds.erase(key); - }).send(); - _privacyRequestIds.emplace(key, requestId); -} - -auto ApiWrap::parsePrivacy(const QVector &rules) --> Privacy { - using Option = Privacy::Option; - - // This is simplified version of privacy rules interpretation. - // But it should be fine for all the apps - // that use the same subset of features. - auto result = Privacy(); - auto optionSet = false; - const auto SetOption = [&](Option option) { - if (optionSet) return; - optionSet = true; - result.option = option; - }; - auto &always = result.always; - auto &never = result.never; - const auto Feed = [&](const MTPPrivacyRule &rule) { - rule.match([&](const MTPDprivacyValueAllowAll &) { - SetOption(Option::Everyone); - }, [&](const MTPDprivacyValueAllowContacts &) { - SetOption(Option::Contacts); - }, [&](const MTPDprivacyValueAllowUsers &data) { - const auto &users = data.vusers().v; - always.reserve(always.size() + users.size()); - for (const auto userId : users) { - const auto user = _session->data().user(UserId(userId.v)); - if (!base::contains(never, user) - && !base::contains(always, user)) { - always.emplace_back(user); - } - } - }, [&](const MTPDprivacyValueAllowChatParticipants &data) { - const auto &chats = data.vchats().v; - always.reserve(always.size() + chats.size()); - for (const auto &chatId : chats) { - const auto chat = _session->data().chatLoaded(chatId); - const auto peer = chat - ? static_cast(chat) - : _session->data().channelLoaded(chatId); - if (peer - && !base::contains(never, peer) - && !base::contains(always, peer)) { - always.emplace_back(peer); - } - } - }, [&](const MTPDprivacyValueDisallowContacts &) { - // not supported - }, [&](const MTPDprivacyValueDisallowAll &) { - SetOption(Option::Nobody); - }, [&](const MTPDprivacyValueDisallowUsers &data) { - const auto &users = data.vusers().v; - never.reserve(never.size() + users.size()); - for (const auto userId : users) { - const auto user = _session->data().user(UserId(userId.v)); - if (!base::contains(always, user) - && !base::contains(never, user)) { - never.emplace_back(user); - } - } - }, [&](const MTPDprivacyValueDisallowChatParticipants &data) { - const auto &chats = data.vchats().v; - never.reserve(never.size() + chats.size()); - for (const auto &chatId : chats) { - const auto chat = _session->data().chatLoaded(chatId); - const auto peer = chat - ? static_cast(chat) - : _session->data().channelLoaded(chatId); - if (peer - && !base::contains(always, peer) - && !base::contains(never, peer)) { - never.emplace_back(peer); - } - } - }); - }; - for (const auto &rule : rules) { - Feed(rule); - } - Feed(MTP_privacyValueDisallowAll()); // disallow by default. - return result; -} - -void ApiWrap::pushPrivacy( - Privacy::Key key, - const QVector &rules) { - const auto &saved = (_privacyValues[key] = parsePrivacy(rules)); - const auto i = _privacyChanges.find(key); - if (i != end(_privacyChanges)) { - i->second.fire_copy(saved); - } -} - -auto ApiWrap::privacyValue(Privacy::Key key) -> rpl::producer { - if (const auto i = _privacyValues.find(key); i != end(_privacyValues)) { - return _privacyChanges[key].events_starting_with_copy(i->second); - } else { - return _privacyChanges[key].events(); - } -} - void ApiWrap::reloadBlockedPeers() { if (_blockedPeersRequestId) { return; @@ -5068,6 +4870,10 @@ Api::GlobalPrivacy &ApiWrap::globalPrivacy() { return *_globalPrivacy; } +Api::UserPrivacy &ApiWrap::userPrivacy() { + return *_userPrivacy; +} + Api::InviteLinks &ApiWrap::inviteLinks() { return *_inviteLinks; } diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index bdc5ad7406..fe9fb4a79f 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -61,6 +61,7 @@ class AttachedStickers; class SelfDestruct; class SensitiveContent; class GlobalPrivacy; +class UserPrivacy; class InviteLinks; namespace details { @@ -113,30 +114,6 @@ public: using SendAction = Api::SendAction; using MessageToSend = Api::MessageToSend; - struct Privacy { - enum class Key { - PhoneNumber, - AddedByPhone, - LastSeen, - Calls, - Invites, - CallsPeer2Peer, - Forwards, - ProfilePhoto, - }; - enum class Option { - Everyone, - Contacts, - Nobody, - }; - Option option = Option::Everyone; - std::vector> always; - std::vector> never; - - static MTPInputPrivacyKey Input(Key key); - static std::optional KeyFromMTP(mtpTypeId type); - }; - struct BlockedPeersSlice { struct Item { PeerData *peer = nullptr; @@ -302,12 +279,6 @@ public: void updateNotifySettingsDelayed(not_null peer); void saveDraftToCloudDelayed(not_null history); - void savePrivacy( - const MTPInputPrivacyKey &key, - QVector &&rules); - void handlePrivacyChange( - Privacy::Key key, - const MTPVector &rules); static int OnlineTillFromStatus( const MTPUserStatus &status, int currentOnlineTill); @@ -446,9 +417,6 @@ public: void saveSelfBio(const QString &text, FnMut done); - void reloadPrivacy(Privacy::Key key); - rpl::producer privacyValue(Privacy::Key key); - void reloadBlockedPeers(); rpl::producer blockedPeersSlice(); @@ -457,6 +425,7 @@ public: [[nodiscard]] Api::SelfDestruct &selfDestruct(); [[nodiscard]] Api::SensitiveContent &sensitiveContent(); [[nodiscard]] Api::GlobalPrivacy &globalPrivacy(); + [[nodiscard]] Api::UserPrivacy &userPrivacy(); [[nodiscard]] Api::InviteLinks &inviteLinks(); void createPoll( @@ -470,6 +439,8 @@ public: void closePoll(not_null item); void reloadPollResults(not_null item); + void updatePrivacyLastSeens(); + private: struct MessageDataRequest { using Callbacks = QList; @@ -626,12 +597,6 @@ private: void photoUploadReady(const FullMsgId &msgId, const MTPInputFile &file); - Privacy parsePrivacy(const QVector &rules); - void pushPrivacy( - Privacy::Key key, - const QVector &rules); - void updatePrivacyLastSeens(const QVector &rules); - void migrateDone( not_null peer, not_null channel); @@ -701,8 +666,6 @@ private: base::flat_map, StickersByEmoji> _stickersByEmoji; - base::flat_map _privacySaveRequests; - mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0; @@ -773,10 +736,6 @@ private: FnMut _saveBioDone; QString _saveBioText; - base::flat_map _privacyRequestIds; - base::flat_map _privacyValues; - std::map> _privacyChanges; - mtpRequestId _blockedPeersRequestId = 0; std::optional _blockedPeersSlice; rpl::event_stream _blockedPeersChanges; @@ -786,6 +745,7 @@ private: const std::unique_ptr _selfDestruct; const std::unique_ptr _sensitiveContent; const std::unique_ptr _globalPrivacy; + const std::unique_ptr _userPrivacy; const std::unique_ptr _inviteLinks; base::flat_map _pollVotesRequestIds; diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 1102f5fa16..c223e51c55 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -170,63 +170,6 @@ void EditPrivacyBox::editExceptions( Ui::LayerOption::KeepOther); } -QVector EditPrivacyBox::collectResult() { - const auto collectInputUsers = [](const auto &peers) { - auto result = QVector(); - result.reserve(peers.size()); - for (const auto peer : peers) { - if (const auto user = peer->asUser()) { - result.push_back(user->inputUser); - } - } - return result; - }; - const auto collectInputChats = [](const auto &peers) { - auto result = QVector(); // #TODO ids - result.reserve(peers.size()); - for (const auto peer : peers) { - if (!peer->isUser()) { - result.push_back(peerToBareMTPInt(peer->id)); - } - } - return result; - }; - - constexpr auto kMaxRules = 3; // allow users, disallow users, option - auto result = QVector(); - result.reserve(kMaxRules); - if (showExceptionLink(Exception::Always)) { - const auto users = collectInputUsers(_value.always); - const auto chats = collectInputChats(_value.always); - if (!users.empty()) { - result.push_back(MTP_inputPrivacyValueAllowUsers(MTP_vector(users))); - } - if (!chats.empty()) { - result.push_back(MTP_inputPrivacyValueAllowChatParticipants(MTP_vector(chats))); - } - } - if (showExceptionLink(Exception::Never)) { - const auto users = collectInputUsers(_value.never); - const auto chats = collectInputChats(_value.never); - if (!users.empty()) { - result.push_back(MTP_inputPrivacyValueDisallowUsers(MTP_vector(users))); - } - if (!chats.empty()) { - result.push_back(MTP_inputPrivacyValueDisallowChatParticipants(MTP_vector(chats))); - } - } - result.push_back([&] { - switch (_value.option) { - case Option::Everyone: return MTP_inputPrivacyValueAllowAll(); - case Option::Contacts: return MTP_inputPrivacyValueAllowContacts(); - case Option::Nobody: return MTP_inputPrivacyValueDisallowAll(); - } - Unexpected("Option value in EditPrivacyBox::collectResult."); - }()); - - return result; -} - std::vector> &EditPrivacyBox::exceptions(Exception exception) { switch (exception) { case Exception::Always: return _value.always; @@ -379,10 +322,13 @@ void EditPrivacyBox::setupContent() { const auto someAreDisallowed = (_value.option != Option::Everyone) || !_value.never.empty(); _controller->confirmSave(someAreDisallowed, crl::guard(this, [=] { + _value.ignoreAlways = !showExceptionLink(Exception::Always); + _value.ignoreNever = !showExceptionLink(Exception::Never); + _controller->saveAdditional(); - _window->session().api().savePrivacy( - _controller->apiKey(), - collectResult()); + _window->session().api().userPrivacy().save( + _controller->key(), + _value); closeBox(); })); }); diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index 4310d1b516..d414c93187 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/abstract_box.h" #include "mtproto/sender.h" -#include "apiwrap.h" +#include "api/api_user_privacy.h" namespace Ui { class VerticalLayout; @@ -31,15 +31,14 @@ class EditPrivacyBox; class EditPrivacyController { public: - using Key = ApiWrap::Privacy::Key; - using Option = ApiWrap::Privacy::Option; + using Key = Api::UserPrivacy::Key; + using Option = Api::UserPrivacy::Option; enum class Exception { Always, Never, }; [[nodiscard]] virtual Key key() = 0; - [[nodiscard]] virtual MTPInputPrivacyKey apiKey() = 0; [[nodiscard]] virtual rpl::producer title() = 0; [[nodiscard]] virtual bool hasOption(Option option) { @@ -102,8 +101,8 @@ private: class EditPrivacyBox : public Ui::BoxContent { public: - using Value = ApiWrap::Privacy; - using Option = Value::Option; + using Value = Api::UserPrivacy::Rule; + using Option = Api::UserPrivacy::Option; using Exception = EditPrivacyController::Exception; EditPrivacyBox( @@ -124,7 +123,6 @@ protected: private: bool showExceptionLink(Exception exception) const; void setupContent(); - QVector collectResult(); Ui::FlatLabel *addLabel( not_null container, diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 1ebeba5756..99e02e2aa4 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_updates.h" #include "api/api_send_progress.h" +#include "api/api_user_privacy.h" #include "main/main_account.h" #include "main/main_domain.h" #include "main/main_session_settings.h" @@ -120,11 +121,11 @@ Session::Session( }, _lifetime); if (_settings->hadLegacyCallsPeerToPeerNobody()) { - api().savePrivacy( - MTP_inputPrivacyKeyPhoneP2P(), - QVector( - 1, - MTP_inputPrivacyValueDisallowAll())); + api().userPrivacy().save( + Api::UserPrivacy::Key::CallsPeer2Peer, + Api::UserPrivacy::Rule{ + .option = Api::UserPrivacy::Option::Nobody + }); saveSettingsDelayed(); } diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index 13bd63cac9..4df730c03a 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -45,6 +45,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Settings { namespace { +using UserPrivacy = Api::UserPrivacy; +using PrivacyRule = Api::UserPrivacy::Rule; + constexpr auto kBlockedPerPage = 40; class BlockPeerBoxController final : public ChatsListBoxController { @@ -339,14 +342,10 @@ std::unique_ptr BlockedBoxController::createRow( return row; } -ApiWrap::Privacy::Key PhoneNumberPrivacyController::key() { +UserPrivacy::Key PhoneNumberPrivacyController::key() { return Key::PhoneNumber; } -MTPInputPrivacyKey PhoneNumberPrivacyController::apiKey() { - return MTP_inputPrivacyKeyPhoneNumber(); -} - rpl::producer PhoneNumberPrivacyController::title() { return tr::lng_edit_privacy_phone_number_title(); } @@ -396,8 +395,8 @@ object_ptr PhoneNumberPrivacyController::setupMiddleWidget( not_null controller, not_null parent, rpl::producer