@@ -54,7 +54,6 @@ use matrix_sdk_common::{
54
54
executor:: { spawn, JoinHandle } ,
55
55
timeout:: timeout,
56
56
} ;
57
- use messages:: { ListThreadsOptions , ThreadRoots } ;
58
57
use mime:: Mime ;
59
58
use reply:: Reply ;
60
59
#[ cfg( feature = "e2e-encryption" ) ]
@@ -132,7 +131,10 @@ use tracing::{debug, info, instrument, warn};
132
131
use self :: futures:: { SendAttachment , SendMessageLikeEvent , SendRawMessageLikeEvent } ;
133
132
pub use self :: {
134
133
member:: { RoomMember , RoomMemberRole } ,
135
- messages:: { EventWithContextResponse , Messages , MessagesOptions } ,
134
+ messages:: {
135
+ EventWithContextResponse , IncludeRelations , ListThreadsOptions , Messages , MessagesOptions ,
136
+ Relations , RelationsOptions , ThreadRoots ,
137
+ } ,
136
138
} ;
137
139
#[ cfg( doc) ]
138
140
use crate :: event_cache:: EventCache ;
@@ -3566,6 +3568,27 @@ impl Room {
3566
3568
3567
3569
Ok ( ThreadRoots { chunk, prev_batch_token : response. next_batch } )
3568
3570
}
3571
+
3572
+ /// Retrieve a list of relations for the given event, according to the given
3573
+ /// options.
3574
+ ///
3575
+ /// Since this client-server API is paginated, the return type may include a
3576
+ /// token used to resuming back-pagination into the list of results, in
3577
+ /// [`Relations::prev_batch_token`]. This token can be fed back into
3578
+ /// [`RelationsOptions::from`] to continue the pagination from the previous
3579
+ /// position.
3580
+ ///
3581
+ /// **Note**: if [`RelationsOptions::from`] is set for a subsequent request,
3582
+ /// then it must be used with the same
3583
+ /// [`RelationsOptions::include_relations`] value as the request that
3584
+ /// returns the `from` token, otherwise the server behavior is undefined.
3585
+ pub async fn relations (
3586
+ & self ,
3587
+ event_id : OwnedEventId ,
3588
+ opts : RelationsOptions ,
3589
+ ) -> Result < Relations > {
3590
+ opts. send ( self , event_id) . await
3591
+ }
3569
3592
}
3570
3593
3571
3594
#[ cfg( all( feature = "e2e-encryption" , not( target_arch = "wasm32" ) ) ) ]
@@ -3885,7 +3908,11 @@ mod tests {
3885
3908
async_test, event_factory:: EventFactory , test_json, JoinedRoomBuilder , StateTestEvent ,
3886
3909
SyncResponseBuilder ,
3887
3910
} ;
3888
- use ruma:: { event_id, events:: room:: member:: MembershipState , int, room_id, user_id} ;
3911
+ use ruma:: {
3912
+ event_id,
3913
+ events:: { relation:: RelationType , room:: member:: MembershipState } ,
3914
+ int, owned_event_id, room_id, user_id,
3915
+ } ;
3889
3916
use wiremock:: {
3890
3917
matchers:: { header, method, path_regex} ,
3891
3918
Mock , MockServer , ResponseTemplate ,
@@ -3894,8 +3921,12 @@ mod tests {
3894
3921
use super :: ReportedContentScore ;
3895
3922
use crate :: {
3896
3923
config:: RequestConfig ,
3897
- room:: messages:: ListThreadsOptions ,
3898
- test_utils:: { client:: mock_matrix_session, logged_in_client, mocks:: MatrixMockServer } ,
3924
+ room:: messages:: { IncludeRelations , ListThreadsOptions , RelationsOptions } ,
3925
+ test_utils:: {
3926
+ client:: mock_matrix_session,
3927
+ logged_in_client,
3928
+ mocks:: { MatrixMockServer , RoomRelationsResponseTemplate } ,
3929
+ } ,
3899
3930
Client ,
3900
3931
} ;
3901
3932
@@ -4282,4 +4313,128 @@ mod tests {
4282
4313
assert_eq ! ( result. chunk[ 0 ] . event_id( ) . unwrap( ) , eid2) ;
4283
4314
assert ! ( result. prev_batch_token. is_none( ) ) ;
4284
4315
}
4316
+
4317
+ #[ async_test]
4318
+ async fn test_relations ( ) {
4319
+ let server = MatrixMockServer :: new ( ) . await ;
4320
+ let client = server. client_builder ( ) . build ( ) . await ;
4321
+
4322
+ let room_id = room_id ! ( "!a:b.c" ) ;
4323
+ let sender_id = user_id ! ( "@alice:b.c" ) ;
4324
+ let f = EventFactory :: new ( ) . room ( room_id) . sender ( sender_id) ;
4325
+
4326
+ let target_event_id = owned_event_id ! ( "$target" ) ;
4327
+ let eid1 = event_id ! ( "$1" ) ;
4328
+ let eid2 = event_id ! ( "$2" ) ;
4329
+ let batch1 = vec ! [ f. text_msg( "Related event 1" ) . event_id( eid1) . into_raw_sync( ) . cast( ) ] ;
4330
+ let batch2 = vec ! [ f. text_msg( "Related event 2" ) . event_id( eid2) . into_raw_sync( ) . cast( ) ] ;
4331
+
4332
+ server
4333
+ . mock_room_relations ( )
4334
+ . match_target_event ( target_event_id. clone ( ) )
4335
+ . ok ( RoomRelationsResponseTemplate :: default ( ) . events ( batch1) . next_batch ( "next_batch" ) )
4336
+ . mock_once ( )
4337
+ . mount ( )
4338
+ . await ;
4339
+
4340
+ server
4341
+ . mock_room_relations ( )
4342
+ . match_target_event ( target_event_id. clone ( ) )
4343
+ . match_from ( "next_batch" )
4344
+ . ok ( RoomRelationsResponseTemplate :: default ( ) . events ( batch2) )
4345
+ . mock_once ( )
4346
+ . mount ( )
4347
+ . await ;
4348
+
4349
+ let room = server. sync_joined_room ( & client, room_id) . await ;
4350
+
4351
+ // Main endpoint: no relation type filtered out.
4352
+ let mut opts = RelationsOptions {
4353
+ include_relations : IncludeRelations :: AllRelations ,
4354
+ ..Default :: default ( )
4355
+ } ;
4356
+ let result = room
4357
+ . relations ( target_event_id. clone ( ) , opts. clone ( ) )
4358
+ . await
4359
+ . expect ( "Failed to list relations the first time" ) ;
4360
+ assert_eq ! ( result. chunk. len( ) , 1 ) ;
4361
+ assert_eq ! ( result. chunk[ 0 ] . event_id( ) . unwrap( ) , eid1) ;
4362
+ assert ! ( result. prev_batch_token. is_none( ) ) ;
4363
+ assert ! ( result. next_batch_token. is_some( ) ) ;
4364
+ assert ! ( result. recursion_depth. is_none( ) ) ;
4365
+
4366
+ opts. from = result. next_batch_token ;
4367
+ let result = room
4368
+ . relations ( target_event_id, opts)
4369
+ . await
4370
+ . expect ( "Failed to list relations the second time" ) ;
4371
+ assert_eq ! ( result. chunk. len( ) , 1 ) ;
4372
+ assert_eq ! ( result. chunk[ 0 ] . event_id( ) . unwrap( ) , eid2) ;
4373
+ assert ! ( result. prev_batch_token. is_none( ) ) ;
4374
+ assert ! ( result. next_batch_token. is_none( ) ) ;
4375
+ assert ! ( result. recursion_depth. is_none( ) ) ;
4376
+ }
4377
+
4378
+ #[ async_test]
4379
+ async fn test_relations_with_reltype ( ) {
4380
+ let server = MatrixMockServer :: new ( ) . await ;
4381
+ let client = server. client_builder ( ) . build ( ) . await ;
4382
+
4383
+ let room_id = room_id ! ( "!a:b.c" ) ;
4384
+ let sender_id = user_id ! ( "@alice:b.c" ) ;
4385
+ let f = EventFactory :: new ( ) . room ( room_id) . sender ( sender_id) ;
4386
+
4387
+ let target_event_id = owned_event_id ! ( "$target" ) ;
4388
+ let eid1 = event_id ! ( "$1" ) ;
4389
+ let eid2 = event_id ! ( "$2" ) ;
4390
+ let batch1 = vec ! [ f. text_msg( "In-thread event 1" ) . event_id( eid1) . into_raw_sync( ) . cast( ) ] ;
4391
+ let batch2 = vec ! [ f. text_msg( "In-thread event 2" ) . event_id( eid2) . into_raw_sync( ) . cast( ) ] ;
4392
+
4393
+ server
4394
+ . mock_room_relations ( )
4395
+ . match_target_event ( target_event_id. clone ( ) )
4396
+ . match_subrequest ( IncludeRelations :: RelationsOfType ( RelationType :: Thread ) )
4397
+ . ok ( RoomRelationsResponseTemplate :: default ( ) . events ( batch1) . next_batch ( "next_batch" ) )
4398
+ . mock_once ( )
4399
+ . mount ( )
4400
+ . await ;
4401
+
4402
+ server
4403
+ . mock_room_relations ( )
4404
+ . match_target_event ( target_event_id. clone ( ) )
4405
+ . match_from ( "next_batch" )
4406
+ . match_subrequest ( IncludeRelations :: RelationsOfType ( RelationType :: Thread ) )
4407
+ . ok ( RoomRelationsResponseTemplate :: default ( ) . events ( batch2) )
4408
+ . mock_once ( )
4409
+ . mount ( )
4410
+ . await ;
4411
+
4412
+ let room = server. sync_joined_room ( & client, room_id) . await ;
4413
+
4414
+ // Reltype-filtered endpoint, for threads \o/
4415
+ let mut opts = RelationsOptions {
4416
+ include_relations : IncludeRelations :: RelationsOfType ( RelationType :: Thread ) ,
4417
+ ..Default :: default ( )
4418
+ } ;
4419
+ let result = room
4420
+ . relations ( target_event_id. clone ( ) , opts. clone ( ) )
4421
+ . await
4422
+ . expect ( "Failed to list relations the first time" ) ;
4423
+ assert_eq ! ( result. chunk. len( ) , 1 ) ;
4424
+ assert_eq ! ( result. chunk[ 0 ] . event_id( ) . unwrap( ) , eid1) ;
4425
+ assert ! ( result. prev_batch_token. is_none( ) ) ;
4426
+ assert ! ( result. next_batch_token. is_some( ) ) ;
4427
+ assert ! ( result. recursion_depth. is_none( ) ) ;
4428
+
4429
+ opts. from = result. next_batch_token ;
4430
+ let result = room
4431
+ . relations ( target_event_id, opts)
4432
+ . await
4433
+ . expect ( "Failed to list relations the second time" ) ;
4434
+ assert_eq ! ( result. chunk. len( ) , 1 ) ;
4435
+ assert_eq ! ( result. chunk[ 0 ] . event_id( ) . unwrap( ) , eid2) ;
4436
+ assert ! ( result. prev_batch_token. is_none( ) ) ;
4437
+ assert ! ( result. next_batch_token. is_none( ) ) ;
4438
+ assert ! ( result. recursion_depth. is_none( ) ) ;
4439
+ }
4285
4440
}
0 commit comments