mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 04:58:49 +03:00
Evaluate push rules locally
This commit is contained in:
parent
a1dd02d763
commit
37009906bb
10 changed files with 180 additions and 234 deletions
126
src/Cache.cpp
126
src/Cache.cpp
|
@ -1518,10 +1518,6 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
|
||||||
|
|
||||||
// Append the new ones.
|
// Append the new ones.
|
||||||
for (const auto &[read_by, timestamp] : event_receipts) {
|
for (const auto &[read_by, timestamp] : event_receipts) {
|
||||||
if (read_by == user_id) {
|
|
||||||
emit removeNotification(QString::fromStdString(room_id),
|
|
||||||
QString::fromStdString(event_id));
|
|
||||||
}
|
|
||||||
saved_receipts.emplace(read_by, timestamp);
|
saved_receipts.emplace(read_by, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1818,12 +1814,6 @@ Cache::saveState(const mtx::responses::Sync &res)
|
||||||
updatedInfo.tags.push_back(tag.first);
|
updatedInfo.tags.push_back(tag.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto fr = std::get_if<
|
|
||||||
mtx::events::AccountDataEvent<mtx::events::account_data::FullyRead>>(&evt)) {
|
|
||||||
nhlog::db()->debug("Fully read: {}", fr->content.event_id);
|
|
||||||
emit removeNotification(QString::fromStdString(room.first),
|
|
||||||
QString::fromStdString(fr->content.event_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2134,27 +2124,6 @@ Cache::roomIds()
|
||||||
return rooms;
|
return rooms;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
|
||||||
Cache::getTimelineMentions()
|
|
||||||
{
|
|
||||||
// TODO: Should be read-only, but getMentionsDb will attempt to create a DB
|
|
||||||
// if it doesn't exist, throwing an error.
|
|
||||||
auto txn = lmdb::txn::begin(env_, nullptr);
|
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications> notifs;
|
|
||||||
|
|
||||||
auto room_ids = getRoomIds(txn);
|
|
||||||
|
|
||||||
for (const auto &room_id : room_ids) {
|
|
||||||
auto roomNotifs = getTimelineMentionsForRoom(txn, room_id);
|
|
||||||
notifs[QString::fromStdString(room_id)] = roomNotifs;
|
|
||||||
}
|
|
||||||
|
|
||||||
txn.commit();
|
|
||||||
|
|
||||||
return notifs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
Cache::previousBatchToken(const std::string &room_id)
|
Cache::previousBatchToken(const std::string &room_id)
|
||||||
{
|
{
|
||||||
|
@ -3587,88 +3556,6 @@ Cache::clearTimeline(const std::string &room_id)
|
||||||
txn.commit();
|
txn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx::responses::Notifications
|
|
||||||
Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
auto db = getMentionsDb(txn, room_id);
|
|
||||||
|
|
||||||
if (db.size(txn) == 0) {
|
|
||||||
return mtx::responses::Notifications{};
|
|
||||||
}
|
|
||||||
|
|
||||||
mtx::responses::Notifications notif;
|
|
||||||
std::string_view event_id, msg;
|
|
||||||
|
|
||||||
auto cursor = lmdb::cursor::open(txn, db);
|
|
||||||
|
|
||||||
while (cursor.get(event_id, msg, MDB_NEXT)) {
|
|
||||||
auto obj = nlohmann::json::parse(msg);
|
|
||||||
|
|
||||||
if (obj.count("event") == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
mtx::responses::Notification notification;
|
|
||||||
from_json(obj, notification);
|
|
||||||
|
|
||||||
notif.notifications.push_back(notification);
|
|
||||||
}
|
|
||||||
cursor.close();
|
|
||||||
|
|
||||||
std::reverse(notif.notifications.begin(), notif.notifications.end());
|
|
||||||
|
|
||||||
return notif;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Add all notifications containing a user mention to the db.
|
|
||||||
void
|
|
||||||
Cache::saveTimelineMentions(const mtx::responses::Notifications &res)
|
|
||||||
{
|
|
||||||
QMap<std::string, QList<mtx::responses::Notification>> notifsByRoom;
|
|
||||||
|
|
||||||
// Sort into room-specific 'buckets'
|
|
||||||
for (const auto ¬if : res.notifications) {
|
|
||||||
nlohmann::json val = notif;
|
|
||||||
notifsByRoom[notif.room_id].push_back(notif);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto txn = lmdb::txn::begin(env_);
|
|
||||||
// Insert the entire set of mentions for each room at a time.
|
|
||||||
QMap<std::string, QList<mtx::responses::Notification>>::const_iterator it =
|
|
||||||
notifsByRoom.constBegin();
|
|
||||||
auto end = notifsByRoom.constEnd();
|
|
||||||
while (it != end) {
|
|
||||||
nhlog::db()->debug("Storing notifications for " + it.key());
|
|
||||||
saveTimelineMentions(txn, it.key(), std::move(it.value()));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
txn.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Cache::saveTimelineMentions(lmdb::txn &txn,
|
|
||||||
const std::string &room_id,
|
|
||||||
const QList<mtx::responses::Notification> &res)
|
|
||||||
{
|
|
||||||
auto db = getMentionsDb(txn, room_id);
|
|
||||||
|
|
||||||
using namespace mtx::events;
|
|
||||||
using namespace mtx::events::state;
|
|
||||||
|
|
||||||
for (const auto ¬if : res) {
|
|
||||||
const auto event_id = mtx::accessors::event_id(notif.event);
|
|
||||||
|
|
||||||
// double check that we have the correct room_id...
|
|
||||||
if (room_id.compare(notif.room_id) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json obj = notif;
|
|
||||||
|
|
||||||
db.put(txn, event_id, obj.dump());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::markSentNotification(const std::string &event_id)
|
Cache::markSentNotification(const std::string &event_id)
|
||||||
{
|
{
|
||||||
|
@ -5299,12 +5186,6 @@ roomIds()
|
||||||
return instance_->roomIds();
|
return instance_->roomIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
|
||||||
getTimelineMentions()
|
|
||||||
{
|
|
||||||
return instance_->getTimelineMentions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
roomMembers(const std::string &room_id)
|
roomMembers(const std::string &room_id)
|
||||||
|
@ -5405,13 +5286,6 @@ isNotificationSent(const std::string &event_id)
|
||||||
return instance_->isNotificationSent(event_id);
|
return instance_->isNotificationSent(event_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Add all notifications containing a user mention to the db.
|
|
||||||
void
|
|
||||||
saveTimelineMentions(const mtx::responses::Notifications &res)
|
|
||||||
{
|
|
||||||
instance_->saveTimelineMentions(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Remove old unused data.
|
//! Remove old unused data.
|
||||||
void
|
void
|
||||||
deleteOldMessages()
|
deleteOldMessages()
|
||||||
|
|
|
@ -118,9 +118,6 @@ setCurrentFormat();
|
||||||
bool
|
bool
|
||||||
runMigrations();
|
runMigrations();
|
||||||
|
|
||||||
QMap<QString, mtx::responses::Notifications>
|
|
||||||
getTimelineMentions();
|
|
||||||
|
|
||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
roomMembers(const std::string &room_id);
|
roomMembers(const std::string &room_id);
|
||||||
|
@ -178,10 +175,6 @@ removeReadNotification(const std::string &event_id);
|
||||||
bool
|
bool
|
||||||
isNotificationSent(const std::string &event_id);
|
isNotificationSent(const std::string &event_id);
|
||||||
|
|
||||||
//! Add all notifications containing a user mention to the db.
|
|
||||||
void
|
|
||||||
saveTimelineMentions(const mtx::responses::Notifications &res);
|
|
||||||
|
|
||||||
//! Remove old unused data.
|
//! Remove old unused data.
|
||||||
void
|
void
|
||||||
deleteOldMessages();
|
deleteOldMessages();
|
||||||
|
|
|
@ -138,7 +138,6 @@ public:
|
||||||
bool runMigrations();
|
bool runMigrations();
|
||||||
|
|
||||||
std::vector<QString> roomIds();
|
std::vector<QString> roomIds();
|
||||||
QMap<QString, mtx::responses::Notifications> getTimelineMentions();
|
|
||||||
|
|
||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
std::vector<std::string> roomMembers(const std::string &room_id);
|
std::vector<std::string> roomMembers(const std::string &room_id);
|
||||||
|
@ -179,9 +178,6 @@ public:
|
||||||
//! Check if we have sent a desktop notification for the given event id.
|
//! Check if we have sent a desktop notification for the given event id.
|
||||||
bool isNotificationSent(const std::string &event_id);
|
bool isNotificationSent(const std::string &event_id);
|
||||||
|
|
||||||
//! Add all notifications containing a user mention to the db.
|
|
||||||
void saveTimelineMentions(const mtx::responses::Notifications &res);
|
|
||||||
|
|
||||||
//! retrieve events in timeline and related functions
|
//! retrieve events in timeline and related functions
|
||||||
struct Messages
|
struct Messages
|
||||||
{
|
{
|
||||||
|
@ -318,7 +314,6 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||||
void roomReadStatus(const std::map<QString, bool> &status);
|
void roomReadStatus(const std::map<QString, bool> &status);
|
||||||
void removeNotification(const QString &room_id, const QString &event_id);
|
|
||||||
void userKeysUpdate(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
void userKeysUpdate(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||||
void userKeysUpdateFinalize(const std::string &user_id);
|
void userKeysUpdateFinalize(const std::string &user_id);
|
||||||
void verificationStatusChanged(const std::string &userid);
|
void verificationStatusChanged(const std::string &userid);
|
||||||
|
@ -335,15 +330,6 @@ private:
|
||||||
lmdb::dbi &membersdb,
|
lmdb::dbi &membersdb,
|
||||||
const mtx::responses::InvitedRoom &room);
|
const mtx::responses::InvitedRoom &room);
|
||||||
|
|
||||||
//! Add a notification containing a user mention to the db.
|
|
||||||
void saveTimelineMentions(lmdb::txn &txn,
|
|
||||||
const std::string &room_id,
|
|
||||||
const QList<mtx::responses::Notification> &res);
|
|
||||||
|
|
||||||
//! Get timeline items that a user was mentions in for a given room
|
|
||||||
mtx::responses::Notifications
|
|
||||||
getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id);
|
|
||||||
|
|
||||||
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
QString getInviteRoomName(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||||
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
QString getInviteRoomTopic(lmdb::txn &txn, lmdb::dbi &statesdb);
|
||||||
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
QString getInviteRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
||||||
|
@ -642,11 +628,6 @@ private:
|
||||||
return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);
|
return lmdb::dbi::open(txn, std::string(room_id + "/members").c_str(), MDB_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
lmdb::dbi getMentionsDb(lmdb::txn &txn, const std::string &room_id)
|
|
||||||
{
|
|
||||||
return lmdb::dbi::open(txn, std::string(room_id + "/mentions").c_str(), MDB_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
lmdb::dbi getUserKeysDb(lmdb::txn &txn) { return lmdb::dbi::open(txn, "user_key", MDB_CREATE); }
|
lmdb::dbi getUserKeysDb(lmdb::txn &txn) { return lmdb::dbi::open(txn, "user_key", MDB_CREATE); }
|
||||||
|
|
||||||
lmdb::dbi getVerificationDb(lmdb::txn &txn)
|
lmdb::dbi getVerificationDb(lmdb::txn &txn)
|
||||||
|
|
200
src/ChatPage.cpp
200
src/ChatPage.cpp
|
@ -136,18 +136,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
|
connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
|
||||||
connect(this, &ChatPage::changeToRoom, this, &ChatPage::changeRoom, Qt::QueuedConnection);
|
connect(this, &ChatPage::changeToRoom, this, &ChatPage::changeRoom, Qt::QueuedConnection);
|
||||||
connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendNotifications);
|
|
||||||
connect(this,
|
|
||||||
&ChatPage::highlightedNotifsRetrieved,
|
|
||||||
this,
|
|
||||||
[](const mtx::responses::Notifications ¬if) {
|
|
||||||
try {
|
|
||||||
cache::saveTimelineMentions(notif);
|
|
||||||
} catch (const lmdb::error &e) {
|
|
||||||
nhlog::db()->error("failed to save mentions: {}", e.what());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(notificationsManager,
|
connect(notificationsManager,
|
||||||
&NotificationsManager::notificationClicked,
|
&NotificationsManager::notificationClicked,
|
||||||
this,
|
this,
|
||||||
|
@ -208,18 +196,140 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QObject *parent)
|
||||||
// No need to check amounts for this section, as this function internally checks for
|
// No need to check amounts for this section, as this function internally checks for
|
||||||
// duplicates.
|
// duplicates.
|
||||||
if (notificationCount && userSettings_->hasNotifications())
|
if (notificationCount && userSettings_->hasNotifications())
|
||||||
http::client()->notifications(
|
for (const auto &e : sync.account_data.events) {
|
||||||
5,
|
if (auto newRules =
|
||||||
"",
|
std::get_if<mtx::events::AccountDataEvent<mtx::pushrules::GlobalRuleset>>(&e))
|
||||||
"",
|
pushrules =
|
||||||
[this](const mtx::responses::Notifications &res, mtx::http::RequestErr err) {
|
std::make_unique<mtx::pushrules::PushRuleEvaluator>(newRules->content.global);
|
||||||
if (err) {
|
}
|
||||||
nhlog::net()->warn("failed to retrieve notifications: {}", err);
|
if (!pushrules) {
|
||||||
return;
|
auto eventInDb = cache::client()->getAccountData(mtx::events::EventType::PushRules);
|
||||||
|
if (eventInDb) {
|
||||||
|
if (auto newRules =
|
||||||
|
std::get_if<mtx::events::AccountDataEvent<mtx::pushrules::GlobalRuleset>>(
|
||||||
|
&*eventInDb))
|
||||||
|
pushrules =
|
||||||
|
std::make_unique<mtx::pushrules::PushRuleEvaluator>(newRules->content.global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pushrules) {
|
||||||
|
const auto local_user = utils::localUser().toStdString();
|
||||||
|
|
||||||
|
for (const auto &[room_id, room] : sync.rooms.join) {
|
||||||
|
// clear old notifications
|
||||||
|
for (const auto &e : room.ephemeral.events) {
|
||||||
|
if (auto receiptsEv =
|
||||||
|
std::get_if<mtx::events::EphemeralEvent<mtx::events::ephemeral::Receipt>>(
|
||||||
|
&e)) {
|
||||||
|
std::vector<QString> receipts;
|
||||||
|
|
||||||
|
for (const auto &[event_id, userReceipts] : receiptsEv->content.receipts) {
|
||||||
|
if (auto r = userReceipts.find(mtx::events::ephemeral::Receipt::Read);
|
||||||
|
r != userReceipts.end()) {
|
||||||
|
for (const auto &[user_id, receipt] : r->second.users) {
|
||||||
|
(void)receipt;
|
||||||
|
|
||||||
|
if (user_id == local_user) {
|
||||||
|
receipts.push_back(QString::fromStdString(event_id));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (auto r =
|
||||||
|
userReceipts.find(mtx::events::ephemeral::Receipt::ReadPrivate);
|
||||||
|
r != userReceipts.end()) {
|
||||||
|
for (const auto &[user_id, receipt] : r->second.users) {
|
||||||
|
(void)receipt;
|
||||||
|
|
||||||
|
if (user_id == local_user) {
|
||||||
|
receipts.push_back(QString::fromStdString(event_id));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!receipts.empty())
|
||||||
|
notificationsManager->removeNotifications(
|
||||||
|
QString::fromStdString(room_id), receipts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit notificationsRetrieved(std::move(res));
|
// calculate new notifications
|
||||||
|
if (!room.timeline.events.empty() &&
|
||||||
|
(room.unread_notifications.notification_count ||
|
||||||
|
room.unread_notifications.highlight_count)) {
|
||||||
|
auto roomModel =
|
||||||
|
view_manager_->rooms()->getRoomById(QString::fromStdString(room_id));
|
||||||
|
|
||||||
|
if (!roomModel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto currentReadMarker =
|
||||||
|
cache::getEventIndex(room_id, cache::client()->getFullyReadEventId(room_id));
|
||||||
|
|
||||||
|
auto ctx = roomModel->pushrulesRoomContext();
|
||||||
|
for (const auto &event : room.timeline.events) {
|
||||||
|
mtx::events::collections::TimelineEvent te{event};
|
||||||
|
std::visit([room_id = room_id](auto &event_) { event_.room_id = room_id; },
|
||||||
|
te.data);
|
||||||
|
|
||||||
|
if (auto encryptedEvent =
|
||||||
|
std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(
|
||||||
|
&event)) {
|
||||||
|
MegolmSessionIndex index(room_id, encryptedEvent->content);
|
||||||
|
|
||||||
|
auto result = olm::decryptEvent(index, *encryptedEvent);
|
||||||
|
if (result.event)
|
||||||
|
te.data = result.event.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto actions = pushrules->evaluate(te, ctx);
|
||||||
|
if (std::find(actions.begin(),
|
||||||
|
actions.end(),
|
||||||
|
mtx::pushrules::actions::Action{
|
||||||
|
mtx::pushrules::actions::notify{}}) != actions.end()) {
|
||||||
|
auto event_id = mtx::accessors::event_id(event);
|
||||||
|
|
||||||
|
// skip already read events
|
||||||
|
if (currentReadMarker &&
|
||||||
|
currentReadMarker > cache::getEventIndex(room_id, event_id))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!cache::isNotificationSent(event_id)) {
|
||||||
|
// We should only send one notification per event.
|
||||||
|
cache::markSentNotification(event_id);
|
||||||
|
|
||||||
|
// Don't send a notification when the current room is opened.
|
||||||
|
if (isRoomActive(roomModel->roomId()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (userSettings_->hasDesktopNotifications()) {
|
||||||
|
auto info = cache::singleRoomInfo(room_id);
|
||||||
|
|
||||||
|
AvatarProvider::resolve(
|
||||||
|
roomModel->roomAvatarUrl(),
|
||||||
|
96,
|
||||||
|
this,
|
||||||
|
[this, te, room_id = room_id, actions](QPixmap image) {
|
||||||
|
notificationsManager->postNotification(
|
||||||
|
mtx::responses::Notification{
|
||||||
|
.actions = actions,
|
||||||
|
.event = te.data,
|
||||||
|
.read = false,
|
||||||
|
.profile_tag = "",
|
||||||
|
.room_id = room_id,
|
||||||
|
.ts = 0,
|
||||||
|
},
|
||||||
|
image.toImage());
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
|
@ -394,12 +504,6 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
|
||||||
&Cache::newReadReceipts,
|
&Cache::newReadReceipts,
|
||||||
view_manager_,
|
view_manager_,
|
||||||
&TimelineViewManager::updateReadReceipts);
|
&TimelineViewManager::updateReadReceipts);
|
||||||
|
|
||||||
connect(cache::client(),
|
|
||||||
&Cache::removeNotification,
|
|
||||||
notificationsManager,
|
|
||||||
&NotificationsManager::removeNotification);
|
|
||||||
|
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
nhlog::db()->critical("failure during boot: {}", e.what());
|
nhlog::db()->critical("failure during boot: {}", e.what());
|
||||||
emit dropToLoginPageCb(tr("Failed to open database, logging out!"));
|
emit dropToLoginPageCb(tr("Failed to open database, logging out!"));
|
||||||
|
@ -415,7 +519,6 @@ ChatPage::loadStateFromCache()
|
||||||
olm::client()->load(cache::restoreOlmAccount(), cache::client()->pickleSecret());
|
olm::client()->load(cache::restoreOlmAccount(), cache::client()->pickleSecret());
|
||||||
|
|
||||||
emit initializeEmptyViews();
|
emit initializeEmptyViews();
|
||||||
emit initializeMentions(cache::getTimelineMentions());
|
|
||||||
|
|
||||||
cache::calculateRoomReadStatus();
|
cache::calculateRoomReadStatus();
|
||||||
|
|
||||||
|
@ -464,46 +567,6 @@ ChatPage::removeRoom(const QString &room_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ChatPage::sendNotifications(const mtx::responses::Notifications &res)
|
|
||||||
{
|
|
||||||
for (const auto &item : res.notifications) {
|
|
||||||
const auto event_id = mtx::accessors::event_id(item.event);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (item.read) {
|
|
||||||
cache::removeReadNotification(event_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cache::isNotificationSent(event_id)) {
|
|
||||||
const auto room_id = QString::fromStdString(item.room_id);
|
|
||||||
|
|
||||||
// We should only send one notification per event.
|
|
||||||
cache::markSentNotification(event_id);
|
|
||||||
|
|
||||||
// Don't send a notification when the current room is opened.
|
|
||||||
if (isRoomActive(room_id))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (userSettings_->hasDesktopNotifications()) {
|
|
||||||
auto info = cache::singleRoomInfo(item.room_id);
|
|
||||||
|
|
||||||
AvatarProvider::resolve(QString::fromStdString(info.avatar_url),
|
|
||||||
96,
|
|
||||||
this,
|
|
||||||
[this, item](QPixmap image) {
|
|
||||||
notificationsManager->postNotification(
|
|
||||||
item, image.toImage());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const lmdb::error &e) {
|
|
||||||
nhlog::db()->warn("error while sending notification: {}", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::tryInitialSync()
|
ChatPage::tryInitialSync()
|
||||||
{
|
{
|
||||||
|
@ -596,7 +659,6 @@ ChatPage::startInitialSync()
|
||||||
olm::handle_to_device_messages(res.to_device.events);
|
olm::handle_to_device_messages(res.to_device.events);
|
||||||
|
|
||||||
emit initializeViews(std::move(res));
|
emit initializeViews(std::move(res));
|
||||||
emit initializeMentions(cache::getTimelineMentions());
|
|
||||||
|
|
||||||
cache::calculateRoomReadStatus();
|
cache::calculateRoomReadStatus();
|
||||||
} catch (const lmdb::error &e) {
|
} catch (const lmdb::error &e) {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <mtx/events.hpp>
|
#include <mtx/events.hpp>
|
||||||
#include <mtx/events/encrypted.hpp>
|
#include <mtx/events/encrypted.hpp>
|
||||||
#include <mtx/events/member.hpp>
|
#include <mtx/events/member.hpp>
|
||||||
|
#include <mtx/events/policy_rules.hpp>
|
||||||
#include <mtx/events/presence.hpp>
|
#include <mtx/events/presence.hpp>
|
||||||
#include <mtx/secret_storage.hpp>
|
#include <mtx/secret_storage.hpp>
|
||||||
|
|
||||||
|
@ -108,9 +109,6 @@ signals:
|
||||||
void connectionLost();
|
void connectionLost();
|
||||||
void connectionRestored();
|
void connectionRestored();
|
||||||
|
|
||||||
void notificationsRetrieved(const mtx::responses::Notifications &);
|
|
||||||
void highlightedNotifsRetrieved(const mtx::responses::Notifications &, const QPoint widgetPos);
|
|
||||||
|
|
||||||
void contentLoaded();
|
void contentLoaded();
|
||||||
void closing();
|
void closing();
|
||||||
void changeWindowTitle(const int);
|
void changeWindowTitle(const int);
|
||||||
|
@ -135,7 +133,6 @@ signals:
|
||||||
|
|
||||||
void initializeViews(const mtx::responses::Sync &rooms);
|
void initializeViews(const mtx::responses::Sync &rooms);
|
||||||
void initializeEmptyViews();
|
void initializeEmptyViews();
|
||||||
void initializeMentions(const QMap<QString, mtx::responses::Notifications> ¬ifs);
|
|
||||||
void syncUI(const mtx::responses::Sync &sync);
|
void syncUI(const mtx::responses::Sync &sync);
|
||||||
void dropToLoginPageCb(const QString &msg);
|
void dropToLoginPageCb(const QString &msg);
|
||||||
|
|
||||||
|
@ -206,9 +203,6 @@ private:
|
||||||
template<class Collection>
|
template<class Collection>
|
||||||
Memberships getMemberships(const std::vector<Collection> &events) const;
|
Memberships getMemberships(const std::vector<Collection> &events) const;
|
||||||
|
|
||||||
//! Send desktop notification for the received messages.
|
|
||||||
void sendNotifications(const mtx::responses::Notifications &);
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void connectCallMessage();
|
void connectCallMessage();
|
||||||
|
|
||||||
|
@ -222,6 +216,8 @@ private:
|
||||||
|
|
||||||
NotificationsManager *notificationsManager;
|
NotificationsManager *notificationsManager;
|
||||||
CallManager *callManager_;
|
CallManager *callManager_;
|
||||||
|
|
||||||
|
std::unique_ptr<mtx::pushrules::PushRuleEvaluator> pushrules;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Collection>
|
template<class Collection>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "EventAccessors.h"
|
#include "EventAccessors.h"
|
||||||
|
#include "Logging.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
QString
|
QString
|
||||||
|
@ -33,3 +34,24 @@ NotificationsManager::getMessageTemplate(const mtx::responses::Notification ¬
|
||||||
return QStringLiteral("%1: %2").arg(sender);
|
return QStringLiteral("%1: %2").arg(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NotificationsManager::removeNotifications(const QString &roomId,
|
||||||
|
const std::vector<QString> &eventIds)
|
||||||
|
{
|
||||||
|
std::string room_id = roomId.toStdString();
|
||||||
|
|
||||||
|
std::uint64_t markerPos = 0;
|
||||||
|
for (const auto &e : eventIds) {
|
||||||
|
markerPos = std::max(markerPos, cache::getEventIndex(room_id, e.toStdString()).value_or(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[roomId, eventId] : this->notificationIds) {
|
||||||
|
if (roomId != roomId)
|
||||||
|
continue;
|
||||||
|
auto idx = cache::getEventIndex(room_id, eventId.toStdString());
|
||||||
|
if (!idx || markerPos >= idx) {
|
||||||
|
removeNotification(roomId, eventId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ public:
|
||||||
|
|
||||||
void postNotification(const mtx::responses::Notification ¬ification, const QImage &icon);
|
void postNotification(const mtx::responses::Notification ¬ification, const QImage &icon);
|
||||||
|
|
||||||
|
void removeNotification(const QString &roomId, const QString &eventId);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void notificationClicked(const QString roomId, const QString eventId);
|
void notificationClicked(const QString roomId, const QString eventId);
|
||||||
void sendNotificationReply(const QString roomId, const QString eventId, const QString body);
|
void sendNotificationReply(const QString roomId, const QString eventId, const QString body);
|
||||||
|
@ -46,7 +48,7 @@ signals:
|
||||||
const QImage &icon);
|
const QImage &icon);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void removeNotification(const QString &roomId, const QString &eventId);
|
void removeNotifications(const QString &roomId, const std::vector<QString> &eventId);
|
||||||
|
|
||||||
#if defined(NHEKO_DBUS_SYS)
|
#if defined(NHEKO_DBUS_SYS)
|
||||||
public:
|
public:
|
||||||
|
@ -62,9 +64,6 @@ private:
|
||||||
const QImage &icon);
|
const QImage &icon);
|
||||||
void closeNotification(uint id);
|
void closeNotification(uint id);
|
||||||
|
|
||||||
// notification ID to (room ID, event ID)
|
|
||||||
QMap<uint, roomEventId> notificationIds;
|
|
||||||
|
|
||||||
const bool hasMarkup_;
|
const bool hasMarkup_;
|
||||||
const bool hasImages_;
|
const bool hasImages_;
|
||||||
#endif
|
#endif
|
||||||
|
@ -96,6 +95,10 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getMessageTemplate(const mtx::responses::Notification ¬ification);
|
QString getMessageTemplate(const mtx::responses::Notification ¬ification);
|
||||||
|
|
||||||
|
// notification ID to (room ID, event ID)
|
||||||
|
// Only populated on Linux atm
|
||||||
|
QMap<uint, roomEventId> notificationIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(NHEKO_DBUS_SYS)
|
#if defined(NHEKO_DBUS_SYS)
|
||||||
|
|
|
@ -34,6 +34,8 @@ public:
|
||||||
|
|
||||||
void invalidate();
|
void invalidate();
|
||||||
|
|
||||||
|
const mtx::events::state::PowerLevels &powerlevelEvent() const { return pl; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString roomId_;
|
QString roomId_;
|
||||||
mtx::events::state::PowerLevels pl;
|
mtx::events::state::PowerLevels pl;
|
||||||
|
|
|
@ -2921,6 +2921,17 @@ TimelineModel::directChatOtherUserId() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtx::pushrules::PushRuleEvaluator::RoomContext
|
||||||
|
TimelineModel::pushrulesRoomContext() const
|
||||||
|
{
|
||||||
|
return mtx::pushrules::PushRuleEvaluator::RoomContext{
|
||||||
|
.user_display_name =
|
||||||
|
cache::displayName(room_id_.toStdString(), http::client()->user_id().to_string()),
|
||||||
|
.member_count = cache::client()->memberCount(room_id_.toStdString()),
|
||||||
|
.power_levels = permissions_.powerlevelEvent(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
RoomSummary *
|
RoomSummary *
|
||||||
TimelineModel::parentSpace()
|
TimelineModel::parentSpace()
|
||||||
{
|
{
|
||||||
|
|
|
@ -336,6 +336,8 @@ public:
|
||||||
bool isDirect() const { return roomMemberCount() <= 2; }
|
bool isDirect() const { return roomMemberCount() <= 2; }
|
||||||
QString directChatOtherUserId() const;
|
QString directChatOtherUserId() const;
|
||||||
|
|
||||||
|
mtx::pushrules::PushRuleEvaluator::RoomContext pushrulesRoomContext() const;
|
||||||
|
|
||||||
std::optional<mtx::events::collections::TimelineEvents> eventById(const QString &id)
|
std::optional<mtx::events::collections::TimelineEvents> eventById(const QString &id)
|
||||||
{
|
{
|
||||||
auto e = events.get(id.toStdString(), "");
|
auto e = events.get(id.toStdString(), "");
|
||||||
|
|
Loading…
Reference in a new issue