@@ -1095,6 +1095,112 @@ async fn test_notification_client_sliding_sync_filters_out_events_from_ignored_u
10951095 } ;
10961096}
10971097
1098+ #[ cfg( feature = "unstable-msc4359" ) ]
1099+ #[ async_test]
1100+ async fn test_notification_client_sliding_sync_filters_out_events_from_do_not_disturb_rooms ( ) {
1101+ let server = MatrixMockServer :: new ( ) . await ;
1102+ let client = server. client_builder ( ) . build ( ) . await ;
1103+
1104+ let sender = user_id ! ( "@user:example.org" ) ;
1105+ let my_user_id = client. user_id ( ) . unwrap ( ) . to_owned ( ) ;
1106+
1107+ let room_id = room_id ! ( "!a98sd12bjh:example.org" ) ;
1108+ let room_name = "The Maltese Falcon" ;
1109+ let sender_display_name = "John Mastodon" ;
1110+ let event_id = event_id ! ( "$example_event_id" ) ;
1111+
1112+ let raw_event = EventFactory :: new ( )
1113+ . room ( room_id)
1114+ . sender ( sender)
1115+ . text_msg ( "Heya" )
1116+ . event_id ( event_id)
1117+ . into_raw_sync ( ) ;
1118+
1119+ let event_factory = EventFactory :: new ( ) . room ( room_id) ;
1120+
1121+ let sender_member_event = event_factory
1122+ . member ( sender)
1123+ . display_name ( sender_display_name)
1124+ . membership ( MembershipState :: Join )
1125+ . into_raw_sync ( ) ;
1126+
1127+ let own_member_event = event_factory
1128+ . member ( & my_user_id)
1129+ . display_name ( "My self" )
1130+ . membership ( MembershipState :: Join )
1131+ . into_raw_sync ( ) ;
1132+
1133+ let power_levels_event =
1134+ event_factory. sender ( sender) . power_levels ( & mut BTreeMap :: new ( ) ) . into_raw_sync ( ) ;
1135+
1136+ let pos = Mutex :: new ( 0 ) ;
1137+ Mock :: given ( SlidingSyncMatcher )
1138+ . respond_with ( move |request : & Request | {
1139+ let partial_request: PartialSlidingSyncRequest = request. body_json ( ) . unwrap ( ) ;
1140+ // Repeat the transaction id in the response, to validate sticky parameters.
1141+ let mut pos = pos. lock ( ) . unwrap ( ) ;
1142+ * pos += 1 ;
1143+ let pos_as_str = ( * pos) . to_string ( ) ;
1144+ ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1145+ "txn_id" : partial_request. txn_id,
1146+ "pos" : pos_as_str,
1147+ "rooms" : {
1148+ room_id: {
1149+ "name" : room_name,
1150+ "initial" : true ,
1151+
1152+ "required_state" : [
1153+ // Sender's member information.
1154+ sender_member_event,
1155+
1156+ // Own member information.
1157+ own_member_event,
1158+
1159+ // Power levels.
1160+ power_levels_event,
1161+ ] ,
1162+
1163+ "timeline" : [
1164+ raw_event,
1165+ ]
1166+ }
1167+ } ,
1168+
1169+ "extensions" : {
1170+ "account_data" : {
1171+ "global" : [ {
1172+ "type" : "dm.filament.do_not_disturb" ,
1173+ "content" : {
1174+ "rooms" : { room_id: { } }
1175+ }
1176+ } ]
1177+ }
1178+ }
1179+ } ) )
1180+ } )
1181+ . mount ( server. server ( ) )
1182+ . await ;
1183+
1184+ let dummy_sync_service = Arc :: new ( SyncService :: builder ( client. clone ( ) ) . build ( ) . await . unwrap ( ) ) ;
1185+ let process_setup =
1186+ NotificationProcessSetup :: SingleProcess { sync_service : dummy_sync_service } ;
1187+ let notification_client = NotificationClient :: new ( client, process_setup) . await . unwrap ( ) ;
1188+ let mut result = notification_client
1189+ . get_notifications_with_sliding_sync ( & [ NotificationItemsRequest {
1190+ room_id : room_id. to_owned ( ) ,
1191+ event_ids : vec ! [ event_id. to_owned( ) ] ,
1192+ } ] )
1193+ . await
1194+ . unwrap ( ) ;
1195+
1196+ let Some ( Ok ( item) ) = result. remove ( event_id) else {
1197+ panic ! ( "fetching notification for {event_id} failed" ) ;
1198+ } ;
1199+ let NotificationStatus :: EventFilteredOut = item else {
1200+ panic ! ( "notification for {event_id} was not filtered out" ) ;
1201+ } ;
1202+ }
1203+
10981204#[ async_test]
10991205async fn test_notification_client_context_filters_out_events_from_ignored_users ( ) {
11001206 let server = MatrixMockServer :: new ( ) . await ;
@@ -1172,3 +1278,82 @@ async fn test_notification_client_context_filters_out_events_from_ignored_users(
11721278
11731279 assert_matches ! ( result, NotificationStatus :: EventFilteredOut ) ;
11741280}
1281+
1282+ #[ cfg( feature = "unstable-msc4359" ) ]
1283+ #[ async_test]
1284+ async fn test_notification_client_context_filters_out_events_from_do_not_disturb_rooms ( ) {
1285+ let server = MatrixMockServer :: new ( ) . await ;
1286+ let client = server. client_builder ( ) . build ( ) . await ;
1287+
1288+ let sender = user_id ! ( "@user:example.org" ) ;
1289+ let room_id = room_id ! ( "!a98sd12bjh:example.org" ) ;
1290+ let event_id = event_id ! ( "$example_event_id" ) ;
1291+
1292+ server. sync_joined_room ( & client, room_id) . await ;
1293+
1294+ // Add mock for sliding sync so we get the ignored user list from its account
1295+ // data
1296+ let pos = Mutex :: new ( 0 ) ;
1297+ Mock :: given ( SlidingSyncMatcher )
1298+ . respond_with ( move |request : & Request | {
1299+ let partial_request: PartialSlidingSyncRequest = request. body_json ( ) . unwrap ( ) ;
1300+ // Repeat the transaction id in the response, to validate sticky parameters.
1301+ let mut pos = pos. lock ( ) . unwrap ( ) ;
1302+ * pos += 1 ;
1303+ let pos_as_str = ( * pos) . to_string ( ) ;
1304+ ResponseTemplate :: new ( 200 ) . set_body_json ( json ! ( {
1305+ "txn_id" : partial_request. txn_id,
1306+ "pos" : pos_as_str,
1307+ "rooms" : { } ,
1308+
1309+ "extensions" : {
1310+ "account_data" : {
1311+ "global" : [ {
1312+ "type" : "dm.filament.do_not_disturb" ,
1313+ "content" : {
1314+ "rooms" : { room_id: { } }
1315+ }
1316+ } ]
1317+ }
1318+ }
1319+ } ) )
1320+ } )
1321+ . mount ( server. server ( ) )
1322+ . await ;
1323+
1324+ let event = EventFactory :: new ( )
1325+ . room ( room_id)
1326+ . sender ( sender)
1327+ . text_msg ( "Heya" )
1328+ . event_id ( event_id)
1329+ . into_event ( ) ;
1330+
1331+ // Mock the /context response
1332+ server
1333+ . mock_room_event_context ( )
1334+ . ok ( RoomContextResponseTemplate :: new ( event) . start ( "start" ) . end ( "end" ) )
1335+ . mock_once ( )
1336+ . mount ( )
1337+ . await ;
1338+
1339+ let dummy_sync_service = Arc :: new ( SyncService :: builder ( client. clone ( ) ) . build ( ) . await . unwrap ( ) ) ;
1340+ let process_setup =
1341+ NotificationProcessSetup :: SingleProcess { sync_service : dummy_sync_service } ;
1342+ let notification_client = NotificationClient :: new ( client, process_setup) . await . unwrap ( ) ;
1343+
1344+ // Call sync first so we get the list of ignored users in the notification
1345+ // client This should still work in a real life usage
1346+ let _ = notification_client
1347+ . get_notifications_with_sliding_sync ( & [ NotificationItemsRequest {
1348+ room_id : room_id. to_owned ( ) ,
1349+ event_ids : vec ! [ event_id. to_owned( ) ] ,
1350+ } ] )
1351+ . await ;
1352+
1353+ // If the event is not found even though there was a mocked response for it, it
1354+ // was discarded as expected.
1355+ let result =
1356+ notification_client. get_notification_with_context ( room_id, event_id) . await . unwrap ( ) ;
1357+
1358+ assert_matches ! ( result, NotificationStatus :: EventFilteredOut ) ;
1359+ }
0 commit comments