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