|
|
|
@ -1,17 +1,117 @@
|
|
|
|
|
mod data;
|
|
|
|
|
|
|
|
|
|
pub use data::Data;
|
|
|
|
|
use ruma::{OwnedRoomId, OwnedUserId, RoomId, UserId};
|
|
|
|
|
use ruma::{
|
|
|
|
|
events::{
|
|
|
|
|
push_rules::PushRulesEvent, room::power_levels::RoomPowerLevelsEventContent,
|
|
|
|
|
GlobalAccountDataEventType, StateEventType,
|
|
|
|
|
},
|
|
|
|
|
push::{Action, Ruleset, Tweak},
|
|
|
|
|
OwnedRoomId, OwnedUserId, RoomId, UserId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::Result;
|
|
|
|
|
use crate::{services, Error, Result};
|
|
|
|
|
|
|
|
|
|
pub struct Service {
|
|
|
|
|
pub db: &'static dyn Data,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Service {
|
|
|
|
|
pub fn reset_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
|
|
|
|
self.db.reset_notification_counts(user_id, room_id)
|
|
|
|
|
pub fn update_notification_counts(&self, user_id: &UserId, room_id: &RoomId) -> Result<()> {
|
|
|
|
|
let power_levels: RoomPowerLevelsEventContent = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.state_accessor
|
|
|
|
|
.room_state_get(room_id, &StateEventType::RoomPowerLevels, "")?
|
|
|
|
|
.map(|ev| {
|
|
|
|
|
serde_json::from_str(ev.content.get())
|
|
|
|
|
.map_err(|_| Error::bad_database("invalid m.room.power_levels event"))
|
|
|
|
|
})
|
|
|
|
|
.transpose()?
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
let read_event = services()
|
|
|
|
|
.rooms
|
|
|
|
|
.edus
|
|
|
|
|
.read_receipt
|
|
|
|
|
.private_read_get(room_id, user_id)
|
|
|
|
|
.unwrap_or(None)
|
|
|
|
|
.unwrap_or(0u64);
|
|
|
|
|
let mut notification_count = 0u64;
|
|
|
|
|
let mut highlight_count = 0u64;
|
|
|
|
|
|
|
|
|
|
services()
|
|
|
|
|
.rooms
|
|
|
|
|
.timeline
|
|
|
|
|
.pdus_since(user_id, room_id, read_event)?
|
|
|
|
|
.filter_map(|pdu| pdu.ok())
|
|
|
|
|
.map(|(_, pdu)| pdu)
|
|
|
|
|
.filter(|pdu| {
|
|
|
|
|
// Don't include user's own messages in notification counts
|
|
|
|
|
user_id != &pdu.sender
|
|
|
|
|
&& services()
|
|
|
|
|
.rooms
|
|
|
|
|
.short
|
|
|
|
|
.get_or_create_shorteventid(&pdu.event_id)
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
!= read_event
|
|
|
|
|
})
|
|
|
|
|
.filter_map(|pdu| {
|
|
|
|
|
let rules_for_user = services()
|
|
|
|
|
.account_data
|
|
|
|
|
.get(
|
|
|
|
|
None,
|
|
|
|
|
user_id,
|
|
|
|
|
GlobalAccountDataEventType::PushRules.to_string().into(),
|
|
|
|
|
)
|
|
|
|
|
.ok()?
|
|
|
|
|
.map(|event| {
|
|
|
|
|
serde_json::from_str::<PushRulesEvent>(event.get())
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid push rules event in db."))
|
|
|
|
|
})
|
|
|
|
|
.transpose()
|
|
|
|
|
.ok()?
|
|
|
|
|
.map(|ev: PushRulesEvent| ev.content.global)
|
|
|
|
|
.unwrap_or_else(|| Ruleset::server_default(user_id));
|
|
|
|
|
|
|
|
|
|
let mut highlight = false;
|
|
|
|
|
let mut notify = false;
|
|
|
|
|
|
|
|
|
|
for action in services()
|
|
|
|
|
.pusher
|
|
|
|
|
.get_actions(
|
|
|
|
|
user_id,
|
|
|
|
|
&rules_for_user,
|
|
|
|
|
&power_levels,
|
|
|
|
|
&pdu.to_sync_room_event(),
|
|
|
|
|
&pdu.room_id,
|
|
|
|
|
)
|
|
|
|
|
.ok()?
|
|
|
|
|
{
|
|
|
|
|
match action {
|
|
|
|
|
Action::DontNotify => notify = false,
|
|
|
|
|
// TODO: Implement proper support for coalesce
|
|
|
|
|
Action::Notify | Action::Coalesce => notify = true,
|
|
|
|
|
Action::SetTweak(Tweak::Highlight(true)) => {
|
|
|
|
|
highlight = true;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if notify {
|
|
|
|
|
notification_count += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if highlight {
|
|
|
|
|
highlight_count += 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Some(())
|
|
|
|
|
})
|
|
|
|
|
.for_each(|_| {});
|
|
|
|
|
|
|
|
|
|
self.db
|
|
|
|
|
.update_notification_counts(user_id, room_id, notification_count, highlight_count)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn notification_count(&self, user_id: &UserId, room_id: &RoomId) -> Result<u64> {
|
|
|
|
|