diff --git a/crates/matrix-sdk-base/src/room/mod.rs b/crates/matrix-sdk-base/src/room/mod.rs index d6f6239ee..89b1dece4 100644 --- a/crates/matrix-sdk-base/src/room/mod.rs +++ b/crates/matrix-sdk-base/src/room/mod.rs @@ -429,6 +429,19 @@ impl Room { self.info.read().cached_user_defined_notification_mode } + /// Removes any existing cached value for the user defined notification + /// mode. + pub fn clear_user_defined_notification_mode(&self) { + self.info.update_if(|info| { + if info.cached_user_defined_notification_mode.is_some() { + info.cached_user_defined_notification_mode = None; + true + } else { + false + } + }) + } + /// Get the list of users ids that are considered to be joined members of /// this room. pub async fn joined_user_ids(&self) -> StoreResult> { diff --git a/crates/matrix-sdk/src/sliding_sync/client.rs b/crates/matrix-sdk/src/sliding_sync/client.rs index 01da84214..7f96fbef7 100644 --- a/crates/matrix-sdk/src/sliding_sync/client.rs +++ b/crates/matrix-sdk/src/sliding_sync/client.rs @@ -277,6 +277,8 @@ async fn update_in_memory_caches( for room in client.joined_rooms() { if let Some(mode) = rules.get_user_defined_room_notification_mode(room.room_id()) { room.update_cached_user_defined_notification_mode(mode); + } else { + room.clear_user_defined_notification_mode(); } } } else { diff --git a/crates/matrix-sdk/tests/integration/room/notification_mode.rs b/crates/matrix-sdk/tests/integration/room/notification_mode.rs index 1bede56e8..ac82ee70a 100644 --- a/crates/matrix-sdk/tests/integration/room/notification_mode.rs +++ b/crates/matrix-sdk/tests/integration/room/notification_mode.rs @@ -1,15 +1,21 @@ use std::time::Duration; use assert_matches::assert_matches; -use matrix_sdk::{config::SyncSettings, notification_settings::RoomNotificationMode}; +use matrix_sdk::{ + SlidingSyncList, config::SyncSettings, notification_settings::RoomNotificationMode, + test_utils::mocks::MatrixMockServer, +}; use matrix_sdk_base::RoomState; use matrix_sdk_test::{ DEFAULT_TEST_ROOM_ID, InvitedRoomBuilder, JoinedRoomBuilder, SyncResponseBuilder, async_test, event_factory::EventFactory, }; use ruma::{ + api::client::sync::sync_events::v5, + events::AnyGlobalAccountDataEvent, push::{Action, ConditionalPushRule, NewSimplePushRule, Ruleset, Tweak}, room_id, + serde::Raw, }; use serde_json::json; use wiremock::{ @@ -102,3 +108,84 @@ async fn test_get_notification_mode() { let mode = room.notification_mode().await; assert_eq!(mode, None); } + +#[async_test] +async fn test_cached_notification_mode_is_updated_when_syncing() { + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; + + // If we receive a sliding sync response with custom rules for a room + let mut ruleset = Ruleset::default(); + ruleset.override_ = + [ConditionalPushRule::master(), ConditionalPushRule::suppress_notices()].into(); + ruleset.room.insert( + NewSimplePushRule::new( + (*DEFAULT_TEST_ROOM_ID).into(), + vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))], + ) + .into(), + ); + ruleset.underride = [ + ConditionalPushRule::call(), + ConditionalPushRule::room_one_to_one(), + ConditionalPushRule::invite_for_me(client.user_id().unwrap()), + ConditionalPushRule::member_event(), + ConditionalPushRule::message(), + ] + .into(); + let f = EventFactory::new(); + let push_rules: Raw = f.push_rules(ruleset).into_raw(); + let mut response = v5::Response::new("pos".to_owned()); + response.extensions.account_data.global.push(push_rules); + response.rooms.insert(DEFAULT_TEST_ROOM_ID.to_owned(), v5::response::Room::default()); + + server + .mock_sliding_sync() + .ok_and_run( + &client, + |builder| builder.add_list(SlidingSyncList::builder("rooms")), + response, + ) + .await; + + server.verify_and_reset().await; + + // We can later check the custom mode is applied + let room = client.get_room(&DEFAULT_TEST_ROOM_ID).expect("Room not found"); + assert_eq!( + room.cached_user_defined_notification_mode(), + Some(RoomNotificationMode::AllMessages) + ); + + // Now if we receive a response with no custom push rules for the room, just the + // base ones + let mut ruleset = Ruleset::default(); + ruleset.underride = [ + ConditionalPushRule::call(), + ConditionalPushRule::room_one_to_one(), + ConditionalPushRule::invite_for_me(client.user_id().unwrap()), + ConditionalPushRule::member_event(), + ConditionalPushRule::message(), + ] + .into(); + + let f = EventFactory::new(); + let push_rules: Raw = f.push_rules(ruleset).into_raw(); + let mut response = v5::Response::new("pos".to_owned()); + response.extensions.account_data.global.push(push_rules); + + server + .mock_sliding_sync() + .ok_and_run( + &client, + |builder| builder.add_list(SlidingSyncList::builder("rooms")), + response, + ) + .await; + + server.verify_and_reset().await; + + // And the custom notification mode for the room has been removed + let room = client.get_room(&DEFAULT_TEST_ROOM_ID).expect("Room not found"); + assert!(room.cached_user_defined_notification_mode().is_none()); +}