mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-31 06:35:14 +00:00
Moved user privacy from ApiWrap to Api::UserPrivacy.
This commit is contained in:
@@ -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: {
|
||||
|
303
Telegram/SourceFiles/api/api_user_privacy.cpp
Normal file
303
Telegram/SourceFiles/api/api_user_privacy.cpp
Normal file
@@ -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<MTPInputPrivacyRule>;
|
||||
using TLRules = MTPVector<MTPPrivacyRule>;
|
||||
|
||||
TLInputRules RulesToTL(const UserPrivacy::Rule &rule) {
|
||||
const auto collectInputUsers = [](const auto &peers) {
|
||||
auto result = QVector<MTPInputUser>();
|
||||
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<MTPint>(); // #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<MTPInputPrivacyRule>();
|
||||
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<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueAllowChatParticipants(
|
||||
MTP_vector<MTPint>(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<MTPInputUser>(users)));
|
||||
}
|
||||
if (!chats.empty()) {
|
||||
result.push_back(
|
||||
MTP_inputPrivacyValueDisallowChatParticipants(
|
||||
MTP_vector<MTPint>(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<MTPInputPrivacyRule>(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<PeerData*>(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<PeerData*>(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<UserPrivacy::Key> 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<ApiWrap*> 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<UserPrivacy::Rule> {
|
||||
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
|
73
Telegram/SourceFiles/api/api_user_privacy.h
Normal file
73
Telegram/SourceFiles/api/api_user_privacy.h
Normal file
@@ -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<not_null<PeerData*>> always;
|
||||
std::vector<not_null<PeerData*>> never;
|
||||
bool ignoreAlways = false;
|
||||
bool ignoreNever = false;
|
||||
};
|
||||
|
||||
explicit UserPrivacy(not_null<ApiWrap*> api);
|
||||
|
||||
void save(
|
||||
Key key,
|
||||
const UserPrivacy::Rule &rule);
|
||||
void apply(
|
||||
mtpTypeId type,
|
||||
const MTPVector<MTPPrivacyRule> &rules,
|
||||
bool allLoaded);
|
||||
|
||||
void reload(Key key);
|
||||
rpl::producer<Rule> value(Key key);
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
void pushPrivacy(Key key, const MTPVector<MTPPrivacyRule> &rules);
|
||||
|
||||
base::flat_map<mtpTypeId, mtpRequestId> _privacySaveRequests;
|
||||
|
||||
base::flat_map<Key, mtpRequestId> _privacyRequestIds;
|
||||
base::flat_map<Key, Rule> _privacyValues;
|
||||
std::map<Key, rpl::event_stream<Rule>> _privacyChanges;
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
Reference in New Issue
Block a user