From fc77b0a51ca673e9447da42efdf2d178c50f9502 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 17 Mar 2017 20:19:46 +0300 Subject: [PATCH] Save privacy in ApiWrap. Handle privacy updates. --- Telegram/SourceFiles/apiwrap.cpp | 134 ++++++++++++++++++ Telegram/SourceFiles/apiwrap.h | 12 ++ Telegram/SourceFiles/app.cpp | 30 ++-- Telegram/SourceFiles/app.h | 1 + .../SourceFiles/boxes/edit_privacy_box.cpp | 6 +- Telegram/SourceFiles/boxes/edit_privacy_box.h | 1 - Telegram/SourceFiles/mainwidget.cpp | 1 + .../settings/settings_privacy_controllers.cpp | 10 -- .../settings/settings_privacy_controllers.h | 2 - 9 files changed, 168 insertions(+), 29 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 1cac67d68..a627cb3c2 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -923,6 +923,140 @@ bool ApiWrap::hasUnsavedDrafts() const { return !_draftsSaveRequestIds.isEmpty(); } +void ApiWrap::savePrivacy(const MTPInputPrivacyKey &key, QVector &&rules) { + auto keyTypeId = key.type(); + auto it = _privacySaveRequests.find(keyTypeId); + if (it != _privacySaveRequests.cend()) { + MTP::cancel(it.value()); + _privacySaveRequests.erase(it); + } + auto requestId = MTP::send(MTPaccount_SetPrivacy(key, MTP_vector(std::move(rules))), rpcDone(&ApiWrap::savePrivacyDone, keyTypeId), rpcFail(&ApiWrap::savePrivacyFail, keyTypeId)); + _privacySaveRequests.insert(keyTypeId, requestId); +} + +void ApiWrap::savePrivacyDone(mtpTypeId keyTypeId, const MTPaccount_PrivacyRules &result) { + Expects(result.type() == mtpc_account_privacyRules); + auto &rules = result.c_account_privacyRules(); + App::feedUsers(rules.vusers); + _privacySaveRequests.remove(keyTypeId); + handlePrivacyChange(keyTypeId, rules.vrules); +} + +bool ApiWrap::savePrivacyFail(mtpTypeId keyTypeId, const RPCError &error) { + if (MTP::isDefaultHandledError(error)) { + return false; + } + _privacySaveRequests.remove(keyTypeId); + return true; +} + +void ApiWrap::handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &rules) { + if (keyTypeId == mtpc_privacyKeyStatusTimestamp) { + enum class Rule { + Unknown, + Allow, + Disallow, + }; + auto userRules = QMap(); + auto contactsRule = Rule::Unknown; + auto everyoneRule = Rule::Unknown; + for (auto &rule : rules.v) { + auto type = rule.type(); + if (type != mtpc_privacyValueAllowAll && type != mtpc_privacyValueDisallowAll && contactsRule != Rule::Unknown) { + // This is simplified: we ignore per-user rules that come after a contacts rule. + // But none of the official apps provide such complicated rule sets, so its fine. + continue; + } + + switch (type) { + case mtpc_privacyValueAllowAll: everyoneRule = Rule::Allow; break; + case mtpc_privacyValueDisallowAll: everyoneRule = Rule::Disallow; break; + case mtpc_privacyValueAllowContacts: contactsRule = Rule::Allow; break; + case mtpc_privacyValueDisallowContacts: contactsRule = Rule::Disallow; break; + case mtpc_privacyValueAllowUsers: { + for_const (auto &userId, rule.c_privacyValueAllowUsers().vusers.v) { + if (!userRules.contains(userId.v)) { + userRules.insert(userId.v, Rule::Allow); + } + } + } break; + case mtpc_privacyValueDisallowUsers: { + for_const (auto &userId, rule.c_privacyValueDisallowUsers().vusers.v) { + if (!userRules.contains(userId.v)) { + userRules.insert(userId.v, Rule::Disallow); + } + } + } break; + } + if (everyoneRule != Rule::Unknown) { + break; + } + } + + auto now = unixtime(); + App::enumerateUsers([&userRules, contactsRule, everyoneRule, now](UserData *user) { + if (user->isSelf() || user->loadedStatus != PeerData::FullLoaded) { + return; + } + if (user->onlineTill <= 0) { + return; + } + + if (user->onlineTill + 3 * 86400 >= now) { + user->onlineTill = -2; // recently + } else if (user->onlineTill + 7 * 86400 >= now) { + user->onlineTill = -3; // last week + } else if (user->onlineTill + 30 * 86400 >= now) { + user->onlineTill = -4; // last month + } else { + user->onlineTill = 0; + } + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); + }); + + if (_contactsStatusesRequestId) { + MTP::cancel(_contactsStatusesRequestId); + } + _contactsStatusesRequestId = MTP::send(MTPcontacts_GetStatuses(), rpcDone(&ApiWrap::contactsStatusesDone), rpcFail(&ApiWrap::contactsStatusesFail)); + } +} + +int ApiWrap::onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill) { + switch (status.type()) { + case mtpc_userStatusEmpty: return 0; + case mtpc_userStatusRecently: return (currentOnlineTill > -10) ? -2 : currentOnlineTill; // don't modify pseudo-online + case mtpc_userStatusLastWeek: return -3; + case mtpc_userStatusLastMonth: return -4; + case mtpc_userStatusOffline: return status.c_userStatusOffline().vwas_online.v; + case mtpc_userStatusOnline: return status.c_userStatusOnline().vexpires.v; + } + Unexpected("Bad UserStatus type."); +} + +void ApiWrap::contactsStatusesDone(const MTPVector &result) { + _contactsStatusesRequestId = 0; + for_const (auto &item, result.v) { + t_assert(item.type() == mtpc_contactStatus); + auto &data = item.c_contactStatus(); + if (auto user = App::userLoaded(data.vuser_id.v)) { + auto oldOnlineTill = user->onlineTill; + auto newOnlineTill = onlineTillFromStatus(data.vstatus, oldOnlineTill); + if (oldOnlineTill != newOnlineTill) { + user->onlineTill = newOnlineTill; + Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserOnlineChanged); + } + } + } +} + +bool ApiWrap::contactsStatusesFail(const RPCError &error) { + if (MTP::isDefaultHandledError(error)) { + return false; + } + _contactsStatusesRequestId = 0; + return true; +} + void ApiWrap::saveDraftsToCloud() { for (auto i = _draftsSaveRequestIds.begin(), e = _draftsSaveRequestIds.end(); i != e; ++i) { if (i.value()) continue; // sent already diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index d0a6ce88f..cf1c6280f 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -76,6 +76,10 @@ public: void saveDraftToCloudDelayed(History *history); bool hasUnsavedDrafts() const; + void savePrivacy(const MTPInputPrivacyKey &key, QVector &&rules); + void handlePrivacyChange(mtpTypeId keyTypeId, const MTPVector &rules); + int onlineTillFromStatus(const MTPUserStatus &status, int currentOnlineTill); + ~ApiWrap(); signals: @@ -179,4 +183,12 @@ private: void stickersClearRecentDone(const MTPBool &result); bool stickersClearRecentFail(const RPCError &result); + QMap _privacySaveRequests; + void savePrivacyDone(mtpTypeId keyTypeId, const MTPaccount_PrivacyRules &result); + bool savePrivacyFail(mtpTypeId keyTypeId, const RPCError &error); + + mtpRequestId _contactsStatusesRequestId = 0; + void contactsStatusesDone(const MTPVector &result); + bool contactsStatusesFail(const RPCError &error); + }; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 482455138..dc1a1a8e8 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -535,21 +535,13 @@ namespace { data->loadedStatus = PeerData::FullLoaded; } - auto oldOnlineTill = data->onlineTill; - if (status && !minimal) switch (status->type()) { - case mtpc_userStatusEmpty: data->onlineTill = 0; break; - case mtpc_userStatusRecently: - if (data->onlineTill > -10) { // don't modify pseudo-online - data->onlineTill = -2; - } - break; - case mtpc_userStatusLastWeek: data->onlineTill = -3; break; - case mtpc_userStatusLastMonth: data->onlineTill = -4; break; - case mtpc_userStatusOffline: data->onlineTill = status->c_userStatusOffline().vwas_online.v; break; - case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break; - } - if (oldOnlineTill != data->onlineTill) { - update.flags |= UpdateFlag::UserOnlineChanged; + if (status && !minimal) { + auto oldOnlineTill = data->onlineTill; + auto newOnlineTill = App::api()->onlineTillFromStatus(*status, oldOnlineTill); + if (oldOnlineTill != newOnlineTill) { + data->onlineTill = newOnlineTill; + update.flags |= UpdateFlag::UserOnlineChanged; + } } if (data->contact < 0 && !data->phone().isEmpty() && data->id != AuthSession::CurrentUserPeerId()) { @@ -1560,6 +1552,14 @@ namespace { return i.value(); } + void enumerateUsers(base::lambda action) { + for_const (auto peer, peersData) { + if (auto user = peer->asUser()) { + action(user); + } + } + } + UserData *self() { return ::self; } diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 09109dc3c..96150950c 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -146,6 +146,7 @@ namespace App { inline ChannelData *channelLoaded(ChannelId channelId) { return channel(channelId, PeerData::FullLoaded); } + void enumerateUsers(base::lambda action); UserData *self(); PeerData *peerByName(const QString &username); diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 6b4a8506e..2afdfc41f 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "ui/widgets/buttons.h" #include "ui/effects/widget_slide_wrap.h" #include "boxes/peer_list_box.h" +#include "apiwrap.h" #include "lang.h" namespace { @@ -330,7 +331,10 @@ void EditPrivacyBox::createWidgets() { _exceptionsDescription.create(this, _controller->exceptionsDescription(), Ui::FlatLabel::InitType::Simple, st::editPrivacyLabel); clearButtons(); - addButton(lang(lng_settings_save), [this] { _controller->save(collectResult()); }); + addButton(lang(lng_settings_save), [this] { + App::api()->savePrivacy(_controller->key(), collectResult()); + closeBox(); + }); addButton(lang(lng_cancel), [this] { closeBox(); }); showChildren(); diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.h b/Telegram/SourceFiles/boxes/edit_privacy_box.h index decded381..550231796 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.h +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.h @@ -44,7 +44,6 @@ public: class Controller { public: virtual MTPInputPrivacyKey key() = 0; - virtual void save(QVector &&result) = 0; virtual QString title() = 0; virtual QString optionDescription(Option option) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index fceba67b0..df08e3aba 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -5060,6 +5060,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updatePrivacy: { auto &d = update.c_updatePrivacy(); + App::api()->handlePrivacyChange(d.vkey.type(), d.vrules); } break; case mtpc_updatePinnedDialogs: { diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp index b46410e8e..f42109cd8 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.cpp @@ -223,11 +223,6 @@ MTPInputPrivacyKey LastSeenPrivacyController::key() { return MTP_inputPrivacyKeyStatusTimestamp(); } -void LastSeenPrivacyController::save(QVector &&result) { - MTP::send(MTPaccount_SetPrivacy(MTP_inputPrivacyKeyStatusTimestamp(), MTP_vector(result))); - view()->closeBox(); -} - QString LastSeenPrivacyController::title() { return lang(lng_edit_privacy_lastseen_title); } @@ -269,11 +264,6 @@ MTPInputPrivacyKey GroupsInvitePrivacyController::key() { return MTP_inputPrivacyKeyChatInvite(); } -void GroupsInvitePrivacyController::save(QVector &&result) { - MTP::send(MTPaccount_SetPrivacy(MTP_inputPrivacyKeyChatInvite(), MTP_vector(result))); - view()->closeBox(); -} - QString GroupsInvitePrivacyController::title() { return lang(lng_edit_privacy_groups_title); } diff --git a/Telegram/SourceFiles/settings/settings_privacy_controllers.h b/Telegram/SourceFiles/settings/settings_privacy_controllers.h index c1ac68581..7c02867f3 100644 --- a/Telegram/SourceFiles/settings/settings_privacy_controllers.h +++ b/Telegram/SourceFiles/settings/settings_privacy_controllers.h @@ -53,7 +53,6 @@ public: using Exception = EditPrivacyBox::Exception; MTPInputPrivacyKey key() override; - void save(QVector &&result) override; QString title() override; QString optionDescription(Option option) override; @@ -70,7 +69,6 @@ public: using Exception = EditPrivacyBox::Exception; MTPInputPrivacyKey key() override; - void save(QVector &&result) override; QString title() override; QString optionDescription(Option option) override;