766 lines
30 KiB
C++
766 lines
30 KiB
C++
//
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
#include "td/telegram/NotificationSettingsManager.h"
|
|
|
|
#include "td/telegram/AccessRights.h"
|
|
#include "td/telegram/AuthManager.h"
|
|
#include "td/telegram/ContactsManager.h"
|
|
#include "td/telegram/Global.h"
|
|
#include "td/telegram/logevent/LogEvent.h"
|
|
#include "td/telegram/logevent/LogEventHelper.h"
|
|
#include "td/telegram/MessagesManager.h"
|
|
#include "td/telegram/NotificationManager.h"
|
|
#include "td/telegram/NotificationSettings.hpp"
|
|
#include "td/telegram/NotificationSound.h"
|
|
#include "td/telegram/Td.h"
|
|
#include "td/telegram/TdDb.h"
|
|
#include "td/telegram/telegram_api.h"
|
|
#include "td/telegram/UpdatesManager.h"
|
|
|
|
#include "td/db/binlog/BinlogEvent.h"
|
|
#include "td/db/binlog/BinlogHelper.h"
|
|
|
|
#include "td/utils/algorithm.h"
|
|
#include "td/utils/buffer.h"
|
|
#include "td/utils/logging.h"
|
|
#include "td/utils/tl_helpers.h"
|
|
|
|
namespace td {
|
|
|
|
class GetDialogNotifySettingsQuery final : public Td::ResultHandler {
|
|
DialogId dialog_id_;
|
|
|
|
public:
|
|
void send(DialogId dialog_id) {
|
|
dialog_id_ = dialog_id;
|
|
auto input_notify_peer = td_->notification_settings_manager_->get_input_notify_peer(dialog_id);
|
|
CHECK(input_notify_peer != nullptr);
|
|
send_query(G()->net_query_creator().create(telegram_api::account_getNotifySettings(std::move(input_notify_peer))));
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_getNotifySettings>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
auto ptr = result_ptr.move_as_ok();
|
|
td_->messages_manager_->on_update_dialog_notify_settings(dialog_id_, std::move(ptr),
|
|
"GetDialogNotifySettingsQuery");
|
|
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_, Status::OK());
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "GetDialogNotifySettingsQuery");
|
|
td_->notification_settings_manager_->on_get_dialog_notification_settings_query_finished(dialog_id_,
|
|
std::move(status));
|
|
}
|
|
};
|
|
|
|
class GetNotifySettingsExceptionsQuery final : public Td::ResultHandler {
|
|
Promise<Unit> promise_;
|
|
|
|
public:
|
|
explicit GetNotifySettingsExceptionsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
}
|
|
|
|
void send(NotificationSettingsScope scope, bool filter_scope, bool compare_sound) {
|
|
int32 flags = 0;
|
|
tl_object_ptr<telegram_api::InputNotifyPeer> input_notify_peer;
|
|
if (filter_scope) {
|
|
flags |= telegram_api::account_getNotifyExceptions::PEER_MASK;
|
|
input_notify_peer = get_input_notify_peer(scope);
|
|
}
|
|
if (compare_sound) {
|
|
flags |= telegram_api::account_getNotifyExceptions::COMPARE_SOUND_MASK;
|
|
}
|
|
send_query(G()->net_query_creator().create(
|
|
telegram_api::account_getNotifyExceptions(flags, false /* ignored */, std::move(input_notify_peer))));
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_getNotifyExceptions>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
auto updates_ptr = result_ptr.move_as_ok();
|
|
auto dialog_ids = UpdatesManager::get_update_notify_settings_dialog_ids(updates_ptr.get());
|
|
vector<tl_object_ptr<telegram_api::User>> users;
|
|
vector<tl_object_ptr<telegram_api::Chat>> chats;
|
|
switch (updates_ptr->get_id()) {
|
|
case telegram_api::updatesCombined::ID: {
|
|
auto updates = static_cast<telegram_api::updatesCombined *>(updates_ptr.get());
|
|
users = std::move(updates->users_);
|
|
chats = std::move(updates->chats_);
|
|
reset_to_empty(updates->users_);
|
|
reset_to_empty(updates->chats_);
|
|
break;
|
|
}
|
|
case telegram_api::updates::ID: {
|
|
auto updates = static_cast<telegram_api::updates *>(updates_ptr.get());
|
|
users = std::move(updates->users_);
|
|
chats = std::move(updates->chats_);
|
|
reset_to_empty(updates->users_);
|
|
reset_to_empty(updates->chats_);
|
|
break;
|
|
}
|
|
}
|
|
td_->contacts_manager_->on_get_users(std::move(users), "GetNotifySettingsExceptionsQuery");
|
|
td_->contacts_manager_->on_get_chats(std::move(chats), "GetNotifySettingsExceptionsQuery");
|
|
for (auto &dialog_id : dialog_ids) {
|
|
td_->messages_manager_->force_create_dialog(dialog_id, "GetNotifySettingsExceptionsQuery");
|
|
}
|
|
td_->updates_manager_->on_get_updates(std::move(updates_ptr), std::move(promise_));
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
promise_.set_error(std::move(status));
|
|
}
|
|
};
|
|
|
|
class GetScopeNotifySettingsQuery final : public Td::ResultHandler {
|
|
Promise<Unit> promise_;
|
|
NotificationSettingsScope scope_;
|
|
|
|
public:
|
|
explicit GetScopeNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
}
|
|
|
|
void send(NotificationSettingsScope scope) {
|
|
scope_ = scope;
|
|
auto input_notify_peer = get_input_notify_peer(scope);
|
|
CHECK(input_notify_peer != nullptr);
|
|
send_query(G()->net_query_creator().create(telegram_api::account_getNotifySettings(std::move(input_notify_peer))));
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_getNotifySettings>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
auto ptr = result_ptr.move_as_ok();
|
|
td_->notification_settings_manager_->on_update_scope_notify_settings(scope_, std::move(ptr));
|
|
|
|
promise_.set_value(Unit());
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
promise_.set_error(std::move(status));
|
|
}
|
|
};
|
|
|
|
class UpdateDialogNotifySettingsQuery final : public Td::ResultHandler {
|
|
Promise<Unit> promise_;
|
|
DialogId dialog_id_;
|
|
|
|
public:
|
|
explicit UpdateDialogNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
}
|
|
|
|
void send(DialogId dialog_id, const DialogNotificationSettings &new_settings) {
|
|
dialog_id_ = dialog_id;
|
|
|
|
auto input_notify_peer = td_->notification_settings_manager_->get_input_notify_peer(dialog_id);
|
|
if (input_notify_peer == nullptr) {
|
|
return on_error(Status::Error(500, "Can't update chat notification settings"));
|
|
}
|
|
|
|
int32 flags = 0;
|
|
if (!new_settings.use_default_mute_until) {
|
|
flags |= telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK;
|
|
}
|
|
if (new_settings.sound != nullptr) {
|
|
flags |= telegram_api::inputPeerNotifySettings::SOUND_MASK;
|
|
}
|
|
if (!new_settings.use_default_show_preview) {
|
|
flags |= telegram_api::inputPeerNotifySettings::SHOW_PREVIEWS_MASK;
|
|
}
|
|
if (new_settings.silent_send_message) {
|
|
flags |= telegram_api::inputPeerNotifySettings::SILENT_MASK;
|
|
}
|
|
send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings(
|
|
std::move(input_notify_peer), make_tl_object<telegram_api::inputPeerNotifySettings>(
|
|
flags, new_settings.show_preview, new_settings.silent_send_message,
|
|
new_settings.mute_until, get_input_notification_sound(new_settings.sound)))));
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_updateNotifySettings>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
bool result = result_ptr.ok();
|
|
if (!result) {
|
|
return on_error(Status::Error(400, "Receive false as result"));
|
|
}
|
|
|
|
promise_.set_value(Unit());
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
if (!td_->messages_manager_->on_get_dialog_error(dialog_id_, status, "UpdateDialogNotifySettingsQuery")) {
|
|
LOG(INFO) << "Receive error for set chat notification settings: " << status;
|
|
}
|
|
|
|
if (!td_->auth_manager_->is_bot() &&
|
|
td_->notification_settings_manager_->get_input_notify_peer(dialog_id_) != nullptr) {
|
|
// trying to repair notification settings for this dialog
|
|
td_->notification_settings_manager_->send_get_dialog_notification_settings_query(dialog_id_, Promise<>());
|
|
}
|
|
|
|
promise_.set_error(std::move(status));
|
|
}
|
|
};
|
|
|
|
class UpdateScopeNotifySettingsQuery final : public Td::ResultHandler {
|
|
Promise<Unit> promise_;
|
|
NotificationSettingsScope scope_;
|
|
|
|
public:
|
|
explicit UpdateScopeNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
}
|
|
|
|
void send(NotificationSettingsScope scope, const ScopeNotificationSettings &new_settings) {
|
|
auto input_notify_peer = get_input_notify_peer(scope);
|
|
CHECK(input_notify_peer != nullptr);
|
|
int32 flags = telegram_api::inputPeerNotifySettings::MUTE_UNTIL_MASK |
|
|
telegram_api::inputPeerNotifySettings::SHOW_PREVIEWS_MASK;
|
|
if (new_settings.sound != nullptr) {
|
|
flags |= telegram_api::inputPeerNotifySettings::SOUND_MASK;
|
|
}
|
|
send_query(G()->net_query_creator().create(telegram_api::account_updateNotifySettings(
|
|
std::move(input_notify_peer), make_tl_object<telegram_api::inputPeerNotifySettings>(
|
|
flags, new_settings.show_preview, false, new_settings.mute_until,
|
|
get_input_notification_sound(new_settings.sound)))));
|
|
scope_ = scope;
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_updateNotifySettings>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
bool result = result_ptr.ok();
|
|
if (!result) {
|
|
return on_error(Status::Error(400, "Receive false as result"));
|
|
}
|
|
|
|
promise_.set_value(Unit());
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
LOG(INFO) << "Receive error for set notification settings: " << status;
|
|
|
|
if (!td_->auth_manager_->is_bot()) {
|
|
// trying to repair notification settings for this scope
|
|
td_->notification_settings_manager_->send_get_scope_notification_settings_query(scope_, Promise<>());
|
|
}
|
|
|
|
promise_.set_error(std::move(status));
|
|
}
|
|
};
|
|
|
|
class ResetNotifySettingsQuery final : public Td::ResultHandler {
|
|
Promise<Unit> promise_;
|
|
|
|
public:
|
|
explicit ResetNotifySettingsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
|
|
}
|
|
|
|
void send() {
|
|
send_query(G()->net_query_creator().create(telegram_api::account_resetNotifySettings()));
|
|
}
|
|
|
|
void on_result(BufferSlice packet) final {
|
|
auto result_ptr = fetch_result<telegram_api::account_resetNotifySettings>(packet);
|
|
if (result_ptr.is_error()) {
|
|
return on_error(result_ptr.move_as_error());
|
|
}
|
|
|
|
bool result = result_ptr.ok();
|
|
if (!result) {
|
|
return on_error(Status::Error(400, "Receive false as result"));
|
|
}
|
|
|
|
promise_.set_value(Unit());
|
|
}
|
|
|
|
void on_error(Status status) final {
|
|
if (!G()->is_expected_error(status)) {
|
|
LOG(ERROR) << "Receive error for reset notification settings: " << status;
|
|
}
|
|
promise_.set_error(std::move(status));
|
|
}
|
|
};
|
|
|
|
NotificationSettingsManager::NotificationSettingsManager(Td *td, ActorShared<> parent)
|
|
: td_(td), parent_(std::move(parent)) {
|
|
scope_unmute_timeout_.set_callback(on_scope_unmute_timeout_callback);
|
|
scope_unmute_timeout_.set_callback_data(static_cast<void *>(this));
|
|
}
|
|
|
|
NotificationSettingsManager::~NotificationSettingsManager() = default;
|
|
|
|
void NotificationSettingsManager::tear_down() {
|
|
parent_.reset();
|
|
}
|
|
|
|
void NotificationSettingsManager::start_up() {
|
|
init();
|
|
}
|
|
|
|
void NotificationSettingsManager::init() {
|
|
if (is_inited_) {
|
|
return;
|
|
}
|
|
is_inited_ = true;
|
|
|
|
bool is_authorized = td_->auth_manager_->is_authorized();
|
|
bool was_authorized_user = td_->auth_manager_->was_authorized() && !td_->auth_manager_->is_bot();
|
|
if (was_authorized_user) {
|
|
for (auto scope :
|
|
{NotificationSettingsScope::Private, NotificationSettingsScope::Group, NotificationSettingsScope::Channel}) {
|
|
auto notification_settings_string =
|
|
G()->td_db()->get_binlog_pmc()->get(get_notification_settings_scope_database_key(scope));
|
|
if (!notification_settings_string.empty()) {
|
|
auto current_settings = get_scope_notification_settings(scope);
|
|
CHECK(current_settings != nullptr);
|
|
log_event_parse(*current_settings, notification_settings_string).ensure();
|
|
|
|
VLOG(notifications) << "Loaded notification settings in " << scope << ": " << *current_settings;
|
|
|
|
schedule_scope_unmute(scope, current_settings->mute_until);
|
|
|
|
send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
|
|
}
|
|
}
|
|
if (!channels_notification_settings_.is_synchronized && is_authorized) {
|
|
channels_notification_settings_ = ScopeNotificationSettings(
|
|
chats_notification_settings_.mute_until, dup_notification_sound(chats_notification_settings_.sound),
|
|
chats_notification_settings_.show_preview, false, false);
|
|
channels_notification_settings_.is_synchronized = false;
|
|
send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>());
|
|
}
|
|
}
|
|
G()->td_db()->get_binlog_pmc()->erase("nsfac");
|
|
}
|
|
|
|
void NotificationSettingsManager::on_scope_unmute_timeout_callback(void *notification_settings_manager_ptr,
|
|
int64 scope_int) {
|
|
if (G()->close_flag()) {
|
|
return;
|
|
}
|
|
|
|
CHECK(1 <= scope_int && scope_int <= 3);
|
|
auto notification_settings_manager = static_cast<NotificationSettingsManager *>(notification_settings_manager_ptr);
|
|
send_closure_later(notification_settings_manager->actor_id(notification_settings_manager),
|
|
&NotificationSettingsManager::on_scope_unmute,
|
|
static_cast<NotificationSettingsScope>(scope_int - 1));
|
|
}
|
|
|
|
int32 NotificationSettingsManager::get_scope_mute_until(NotificationSettingsScope scope) const {
|
|
return get_scope_notification_settings(scope)->mute_until;
|
|
}
|
|
|
|
bool NotificationSettingsManager::get_scope_disable_pinned_message_notifications(
|
|
NotificationSettingsScope scope) const {
|
|
return get_scope_notification_settings(scope)->disable_pinned_message_notifications;
|
|
}
|
|
|
|
bool NotificationSettingsManager::get_scope_disable_mention_notifications(NotificationSettingsScope scope) const {
|
|
return get_scope_notification_settings(scope)->disable_mention_notifications;
|
|
}
|
|
|
|
tl_object_ptr<telegram_api::InputNotifyPeer> NotificationSettingsManager::get_input_notify_peer(
|
|
DialogId dialog_id) const {
|
|
if (!td_->messages_manager_->have_dialog(dialog_id)) {
|
|
return nullptr;
|
|
}
|
|
auto input_peer = td_->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
|
|
if (input_peer == nullptr) {
|
|
return nullptr;
|
|
}
|
|
return make_tl_object<telegram_api::inputNotifyPeer>(std::move(input_peer));
|
|
}
|
|
|
|
ScopeNotificationSettings *NotificationSettingsManager::get_scope_notification_settings(
|
|
NotificationSettingsScope scope) {
|
|
switch (scope) {
|
|
case NotificationSettingsScope::Private:
|
|
return &users_notification_settings_;
|
|
case NotificationSettingsScope::Group:
|
|
return &chats_notification_settings_;
|
|
case NotificationSettingsScope::Channel:
|
|
return &channels_notification_settings_;
|
|
default:
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
const ScopeNotificationSettings *NotificationSettingsManager::get_scope_notification_settings(
|
|
NotificationSettingsScope scope) const {
|
|
switch (scope) {
|
|
case NotificationSettingsScope::Private:
|
|
return &users_notification_settings_;
|
|
case NotificationSettingsScope::Group:
|
|
return &chats_notification_settings_;
|
|
case NotificationSettingsScope::Channel:
|
|
return &channels_notification_settings_;
|
|
default:
|
|
UNREACHABLE();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
td_api::object_ptr<td_api::updateScopeNotificationSettings>
|
|
NotificationSettingsManager::get_update_scope_notification_settings_object(NotificationSettingsScope scope) const {
|
|
auto notification_settings = get_scope_notification_settings(scope);
|
|
CHECK(notification_settings != nullptr);
|
|
return td_api::make_object<td_api::updateScopeNotificationSettings>(
|
|
get_notification_settings_scope_object(scope), get_scope_notification_settings_object(notification_settings));
|
|
}
|
|
|
|
void NotificationSettingsManager::on_scope_unmute(NotificationSettingsScope scope) {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
// just in case
|
|
return;
|
|
}
|
|
|
|
auto notification_settings = get_scope_notification_settings(scope);
|
|
CHECK(notification_settings != nullptr);
|
|
|
|
if (notification_settings->mute_until == 0) {
|
|
return;
|
|
}
|
|
|
|
auto now = G()->unix_time();
|
|
if (notification_settings->mute_until > now) {
|
|
LOG(ERROR) << "Failed to unmute " << scope << " in " << now << ", will be unmuted in "
|
|
<< notification_settings->mute_until;
|
|
schedule_scope_unmute(scope, notification_settings->mute_until);
|
|
return;
|
|
}
|
|
|
|
LOG(INFO) << "Unmute " << scope;
|
|
update_scope_unmute_timeout(scope, notification_settings->mute_until, 0);
|
|
send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
|
|
save_scope_notification_settings(scope, *notification_settings);
|
|
}
|
|
|
|
string NotificationSettingsManager::get_notification_settings_scope_database_key(NotificationSettingsScope scope) {
|
|
switch (scope) {
|
|
case NotificationSettingsScope::Private:
|
|
return "nsfpc";
|
|
case NotificationSettingsScope::Group:
|
|
return "nsfgc";
|
|
case NotificationSettingsScope::Channel:
|
|
return "nsfcc";
|
|
default:
|
|
UNREACHABLE();
|
|
return "";
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::save_scope_notification_settings(NotificationSettingsScope scope,
|
|
const ScopeNotificationSettings &new_settings) {
|
|
string key = get_notification_settings_scope_database_key(scope);
|
|
G()->td_db()->get_binlog_pmc()->set(key, log_event_store(new_settings).as_slice().str());
|
|
}
|
|
|
|
void NotificationSettingsManager::on_update_scope_notify_settings(
|
|
NotificationSettingsScope scope, tl_object_ptr<telegram_api::peerNotifySettings> &&peer_notify_settings) {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
return;
|
|
}
|
|
|
|
auto old_notification_settings = get_scope_notification_settings(scope);
|
|
CHECK(old_notification_settings != nullptr);
|
|
|
|
ScopeNotificationSettings notification_settings = ::td::get_scope_notification_settings(
|
|
std::move(peer_notify_settings), old_notification_settings->disable_pinned_message_notifications,
|
|
old_notification_settings->disable_mention_notifications);
|
|
if (!notification_settings.is_synchronized) {
|
|
return;
|
|
}
|
|
|
|
update_scope_notification_settings(scope, old_notification_settings, std::move(notification_settings));
|
|
}
|
|
|
|
bool NotificationSettingsManager::update_scope_notification_settings(NotificationSettingsScope scope,
|
|
ScopeNotificationSettings *current_settings,
|
|
ScopeNotificationSettings &&new_settings) {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
// just in case
|
|
return false;
|
|
}
|
|
|
|
bool need_update_server = current_settings->mute_until != new_settings.mute_until ||
|
|
!are_equivalent_notification_sounds(current_settings->sound, new_settings.sound) ||
|
|
current_settings->show_preview != new_settings.show_preview;
|
|
bool need_update_local =
|
|
current_settings->disable_pinned_message_notifications != new_settings.disable_pinned_message_notifications ||
|
|
current_settings->disable_mention_notifications != new_settings.disable_mention_notifications;
|
|
bool was_inited = current_settings->is_synchronized;
|
|
bool is_inited = new_settings.is_synchronized;
|
|
if (was_inited && !is_inited) {
|
|
return false; // just in case
|
|
}
|
|
bool is_changed = need_update_server || need_update_local || was_inited != is_inited ||
|
|
are_different_equivalent_notification_sounds(current_settings->sound, new_settings.sound);
|
|
if (is_changed) {
|
|
save_scope_notification_settings(scope, new_settings);
|
|
|
|
VLOG(notifications) << "Update notification settings in " << scope << " from " << *current_settings << " to "
|
|
<< new_settings;
|
|
|
|
update_scope_unmute_timeout(scope, current_settings->mute_until, new_settings.mute_until);
|
|
|
|
if (!current_settings->disable_pinned_message_notifications && new_settings.disable_pinned_message_notifications) {
|
|
td_->messages_manager_->remove_scope_pinned_message_notifications(scope);
|
|
}
|
|
if (current_settings->disable_mention_notifications != new_settings.disable_mention_notifications) {
|
|
td_->messages_manager_->on_update_scope_mention_notifications(scope, new_settings.disable_mention_notifications);
|
|
}
|
|
|
|
*current_settings = std::move(new_settings);
|
|
|
|
send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope));
|
|
}
|
|
return need_update_server;
|
|
}
|
|
|
|
void NotificationSettingsManager::schedule_scope_unmute(NotificationSettingsScope scope, int32 mute_until) {
|
|
auto now = G()->unix_time_cached();
|
|
if (mute_until >= now && mute_until < now + 366 * 86400) {
|
|
scope_unmute_timeout_.set_timeout_in(static_cast<int64>(scope) + 1, mute_until - now + 1);
|
|
} else {
|
|
scope_unmute_timeout_.cancel_timeout(static_cast<int64>(scope) + 1);
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::update_scope_unmute_timeout(NotificationSettingsScope scope, int32 &old_mute_until,
|
|
int32 new_mute_until) {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
// just in case
|
|
return;
|
|
}
|
|
|
|
LOG(INFO) << "Update " << scope << " unmute timeout from " << old_mute_until << " to " << new_mute_until;
|
|
if (old_mute_until == new_mute_until) {
|
|
return;
|
|
}
|
|
CHECK(old_mute_until >= 0);
|
|
|
|
schedule_scope_unmute(scope, new_mute_until);
|
|
|
|
auto was_muted = old_mute_until != 0;
|
|
auto is_muted = new_mute_until != 0;
|
|
|
|
old_mute_until = new_mute_until;
|
|
|
|
if (was_muted != is_muted) {
|
|
td_->messages_manager_->on_update_notification_scope_is_muted(scope, is_muted);
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::reset_scope_notification_settings() {
|
|
CHECK(!td_->auth_manager_->is_bot());
|
|
|
|
for (auto scope :
|
|
{NotificationSettingsScope::Private, NotificationSettingsScope::Group, NotificationSettingsScope::Channel}) {
|
|
auto current_settings = get_scope_notification_settings(scope);
|
|
CHECK(current_settings != nullptr);
|
|
ScopeNotificationSettings new_scope_settings;
|
|
new_scope_settings.is_synchronized = true;
|
|
update_scope_notification_settings(scope, current_settings, std::move(new_scope_settings));
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::send_get_dialog_notification_settings_query(DialogId dialog_id,
|
|
Promise<Unit> &&promise) {
|
|
if (td_->auth_manager_->is_bot() || dialog_id.get_type() == DialogType::SecretChat) {
|
|
LOG(WARNING) << "Can't get notification settings for " << dialog_id;
|
|
return promise.set_error(Status::Error(500, "Wrong getDialogNotificationSettings query"));
|
|
}
|
|
if (!td_->messages_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
|
|
LOG(WARNING) << "Have no access to " << dialog_id << " to get notification settings";
|
|
return promise.set_error(Status::Error(400, "Can't access the chat"));
|
|
}
|
|
|
|
auto &promises = get_dialog_notification_settings_queries_[dialog_id];
|
|
promises.push_back(std::move(promise));
|
|
if (promises.size() != 1) {
|
|
// query has already been sent, just wait for the result
|
|
return;
|
|
}
|
|
|
|
td_->create_handler<GetDialogNotifySettingsQuery>()->send(dialog_id);
|
|
}
|
|
|
|
const ScopeNotificationSettings *NotificationSettingsManager::get_scope_notification_settings(
|
|
NotificationSettingsScope scope, Promise<Unit> &&promise) {
|
|
const ScopeNotificationSettings *notification_settings = get_scope_notification_settings(scope);
|
|
CHECK(notification_settings != nullptr);
|
|
if (!notification_settings->is_synchronized && !td_->auth_manager_->is_bot()) {
|
|
send_get_scope_notification_settings_query(scope, std::move(promise));
|
|
return nullptr;
|
|
}
|
|
|
|
promise.set_value(Unit());
|
|
return notification_settings;
|
|
}
|
|
|
|
void NotificationSettingsManager::send_get_scope_notification_settings_query(NotificationSettingsScope scope,
|
|
Promise<Unit> &&promise) {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
LOG(ERROR) << "Can't get notification settings for " << scope;
|
|
return promise.set_error(Status::Error(500, "Wrong getScopeNotificationSettings query"));
|
|
}
|
|
|
|
td_->create_handler<GetScopeNotifySettingsQuery>(std::move(promise))->send(scope);
|
|
}
|
|
|
|
void NotificationSettingsManager::on_get_dialog_notification_settings_query_finished(DialogId dialog_id,
|
|
Status &&status) {
|
|
CHECK(!td_->auth_manager_->is_bot());
|
|
auto it = get_dialog_notification_settings_queries_.find(dialog_id);
|
|
CHECK(it != get_dialog_notification_settings_queries_.end());
|
|
CHECK(!it->second.empty());
|
|
auto promises = std::move(it->second);
|
|
get_dialog_notification_settings_queries_.erase(it);
|
|
|
|
for (auto &promise : promises) {
|
|
if (status.is_ok()) {
|
|
promise.set_value(Unit());
|
|
} else {
|
|
promise.set_error(status.clone());
|
|
}
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::update_dialog_notify_settings(DialogId dialog_id,
|
|
const DialogNotificationSettings &new_settings,
|
|
Promise<Unit> &&promise) {
|
|
td_->create_handler<UpdateDialogNotifySettingsQuery>(std::move(promise))->send(dialog_id, new_settings);
|
|
}
|
|
|
|
Status NotificationSettingsManager::set_scope_notification_settings(
|
|
NotificationSettingsScope scope, td_api::object_ptr<td_api::scopeNotificationSettings> &¬ification_settings) {
|
|
CHECK(!td_->auth_manager_->is_bot());
|
|
auto *current_settings = get_scope_notification_settings(scope);
|
|
CHECK(current_settings != nullptr);
|
|
TRY_RESULT(new_settings, ::td::get_scope_notification_settings(std::move(notification_settings)));
|
|
if (is_notification_sound_default(current_settings->sound) && is_notification_sound_default(new_settings.sound)) {
|
|
new_settings.sound = dup_notification_sound(current_settings->sound);
|
|
}
|
|
if (update_scope_notification_settings(scope, current_settings, std::move(new_settings))) {
|
|
update_scope_notification_settings_on_server(scope, 0);
|
|
}
|
|
return Status::OK();
|
|
}
|
|
|
|
class NotificationSettingsManager::UpdateScopeNotificationSettingsOnServerLogEvent {
|
|
public:
|
|
NotificationSettingsScope scope_;
|
|
|
|
template <class StorerT>
|
|
void store(StorerT &storer) const {
|
|
td::store(scope_, storer);
|
|
}
|
|
|
|
template <class ParserT>
|
|
void parse(ParserT &parser) {
|
|
td::parse(scope_, parser);
|
|
}
|
|
};
|
|
|
|
uint64 NotificationSettingsManager::save_update_scope_notification_settings_on_server_log_event(
|
|
NotificationSettingsScope scope) {
|
|
UpdateScopeNotificationSettingsOnServerLogEvent log_event{scope};
|
|
return binlog_add(G()->td_db()->get_binlog(), LogEvent::HandlerType::UpdateScopeNotificationSettingsOnServer,
|
|
get_log_event_storer(log_event));
|
|
}
|
|
|
|
void NotificationSettingsManager::update_scope_notification_settings_on_server(NotificationSettingsScope scope,
|
|
uint64 log_event_id) {
|
|
CHECK(!td_->auth_manager_->is_bot());
|
|
if (log_event_id == 0) {
|
|
log_event_id = save_update_scope_notification_settings_on_server_log_event(scope);
|
|
}
|
|
|
|
LOG(INFO) << "Update " << scope << " notification settings on server with log_event " << log_event_id;
|
|
td_->create_handler<UpdateScopeNotifySettingsQuery>(get_erase_log_event_promise(log_event_id))
|
|
->send(scope, *get_scope_notification_settings(scope));
|
|
}
|
|
|
|
void NotificationSettingsManager::reset_notify_settings(Promise<Unit> &&promise) {
|
|
td_->create_handler<ResetNotifySettingsQuery>(std::move(promise))->send();
|
|
}
|
|
|
|
void NotificationSettingsManager::get_notify_settings_exceptions(NotificationSettingsScope scope, bool filter_scope,
|
|
bool compare_sound, Promise<Unit> &&promise) {
|
|
td_->create_handler<GetNotifySettingsExceptionsQuery>(std::move(promise))->send(scope, filter_scope, compare_sound);
|
|
}
|
|
|
|
void NotificationSettingsManager::after_get_difference() {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
return;
|
|
}
|
|
|
|
if (!users_notification_settings_.is_synchronized) {
|
|
send_get_scope_notification_settings_query(NotificationSettingsScope::Private, Promise<>());
|
|
}
|
|
if (!chats_notification_settings_.is_synchronized) {
|
|
send_get_scope_notification_settings_query(NotificationSettingsScope::Group, Promise<>());
|
|
}
|
|
if (!channels_notification_settings_.is_synchronized) {
|
|
send_get_scope_notification_settings_query(NotificationSettingsScope::Channel, Promise<>());
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::on_binlog_events(vector<BinlogEvent> &&events) {
|
|
if (G()->close_flag()) {
|
|
return;
|
|
}
|
|
for (auto &event : events) {
|
|
CHECK(event.id_ != 0);
|
|
switch (event.type_) {
|
|
case LogEvent::HandlerType::UpdateScopeNotificationSettingsOnServer: {
|
|
UpdateScopeNotificationSettingsOnServerLogEvent log_event;
|
|
log_event_parse(log_event, event.data_).ensure();
|
|
|
|
update_scope_notification_settings_on_server(log_event.scope_, event.id_);
|
|
break;
|
|
}
|
|
default:
|
|
LOG(FATAL) << "Unsupported log event type " << event.type_;
|
|
}
|
|
}
|
|
}
|
|
|
|
void NotificationSettingsManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
|
|
if (td_->auth_manager_->is_bot()) {
|
|
return;
|
|
}
|
|
|
|
for (auto scope :
|
|
{NotificationSettingsScope::Private, NotificationSettingsScope::Group, NotificationSettingsScope::Channel}) {
|
|
auto current_settings = get_scope_notification_settings(scope);
|
|
CHECK(current_settings != nullptr);
|
|
if (current_settings->is_synchronized) {
|
|
updates.push_back(get_update_scope_notification_settings_object(scope));
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace td
|