@@ -276,10 +276,8 @@ impl SpaceService {
276276 let child_room =
277277 self . client . get_room ( & child_id) . ok_or ( Error :: RoomNotFound ( child_id. to_owned ( ) ) ) ?;
278278
279- if space_room
280- . get_state_event_static_for_key :: < SpaceChildEventContent , _ > ( & child_id)
281- . await
282- . is_ok ( )
279+ if let Ok ( Some ( _) ) =
280+ space_room. get_state_event_static_for_key :: < SpaceChildEventContent , _ > ( & child_id) . await
283281 {
284282 // Redacting state is a "weird" thing to do, so send {} instead.
285283 // https://github.com/matrix-org/matrix-spec/issues/2252
@@ -295,10 +293,8 @@ impl SpaceService {
295293 warn ! ( "A space child event wasn't found on the parent, ignoring." ) ;
296294 }
297295
298- if child_room
299- . get_state_event_static_for_key :: < SpaceParentEventContent , _ > ( & space_id)
300- . await
301- . is_ok ( )
296+ if let Ok ( Some ( _) ) =
297+ child_room. get_state_event_static_for_key :: < SpaceParentEventContent , _ > ( & space_id) . await
302298 {
303299 // Same as the comment above.
304300 child_room
@@ -477,48 +473,36 @@ mod tests {
477473 let child_space_id_1 = room_id ! ( "!child_space_1:example.org" ) ;
478474 let child_space_id_2 = room_id ! ( "!child_space_2:example.org" ) ;
479475
480- server
481- . sync_room (
482- & client,
483- JoinedRoomBuilder :: new ( child_space_id_1)
484- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
485- . add_state_event (
486- factory
487- . space_parent ( parent_space_id. to_owned ( ) , child_space_id_1. to_owned ( ) )
488- . sender ( user_id) ,
489- ) ,
490- )
491- . await ;
492-
493- server
494- . sync_room (
495- & client,
496- JoinedRoomBuilder :: new ( child_space_id_2)
497- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
498- . add_state_event (
499- factory
500- . space_parent ( parent_space_id. to_owned ( ) , child_space_id_2. to_owned ( ) )
501- . sender ( user_id) ,
502- ) ,
503- )
504- . await ;
505- server
506- . sync_room (
507- & client,
508- JoinedRoomBuilder :: new ( parent_space_id)
509- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
510- . add_state_event (
511- factory
512- . space_child ( parent_space_id. to_owned ( ) , child_space_id_1. to_owned ( ) )
513- . sender ( user_id) ,
514- )
515- . add_state_event (
516- factory
517- . space_child ( parent_space_id. to_owned ( ) , child_space_id_2. to_owned ( ) )
518- . sender ( user_id) ,
519- ) ,
520- )
521- . await ;
476+ add_room_with_relationships (
477+ child_space_id_1,
478+ vec ! [ parent_space_id] ,
479+ vec ! [ ] ,
480+ & client,
481+ & server,
482+ & factory,
483+ user_id,
484+ )
485+ . await ;
486+ add_room_with_relationships (
487+ child_space_id_2,
488+ vec ! [ parent_space_id] ,
489+ vec ! [ ] ,
490+ & client,
491+ & server,
492+ & factory,
493+ user_id,
494+ )
495+ . await ;
496+ add_room_with_relationships (
497+ parent_space_id,
498+ vec ! [ ] ,
499+ vec ! [ child_space_id_1, child_space_id_2] ,
500+ & client,
501+ & server,
502+ & factory,
503+ user_id,
504+ )
505+ . await ;
522506
523507 // Only the parent space is returned
524508 assert_eq ! (
@@ -745,57 +729,36 @@ mod tests {
745729 let unknown_parent_space_id = room_id ! ( "!unknown_parent_space:example.org" ) ;
746730 let child_space_id = room_id ! ( "!child_space:example.org" ) ;
747731
748- server
749- . sync_room (
750- & client,
751- JoinedRoomBuilder :: new ( child_space_id)
752- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
753- . add_state_event (
754- factory
755- . space_parent ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
756- . sender ( user_id) ,
757- )
758- . add_state_event (
759- factory
760- . space_parent ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
761- . sender ( user_id) ,
762- )
763- . add_state_event (
764- factory
765- . space_parent (
766- unknown_parent_space_id. to_owned ( ) ,
767- child_space_id. to_owned ( ) ,
768- )
769- . sender ( user_id) ,
770- ) ,
771- )
772- . await ;
773-
774- server
775- . sync_room (
776- & client,
777- JoinedRoomBuilder :: new ( parent_space_id_1)
778- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
779- . add_state_event (
780- factory
781- . space_child ( parent_space_id_1. to_owned ( ) , child_space_id. to_owned ( ) )
782- . sender ( user_id) ,
783- ) ,
784- )
785- . await ;
786-
787- server
788- . sync_room (
789- & client,
790- JoinedRoomBuilder :: new ( parent_space_id_2)
791- . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) )
792- . add_state_event (
793- factory
794- . space_child ( parent_space_id_2. to_owned ( ) , child_space_id. to_owned ( ) )
795- . sender ( user_id) ,
796- ) ,
797- )
798- . await ;
732+ add_room_with_relationships (
733+ child_space_id,
734+ vec ! [ parent_space_id_1, parent_space_id_2, unknown_parent_space_id] ,
735+ vec ! [ ] ,
736+ & client,
737+ & server,
738+ & factory,
739+ user_id,
740+ )
741+ . await ;
742+ add_room_with_relationships (
743+ parent_space_id_1,
744+ vec ! [ ] ,
745+ vec ! [ parent_space_id_1] ,
746+ & client,
747+ & server,
748+ & factory,
749+ user_id,
750+ )
751+ . await ;
752+ add_room_with_relationships (
753+ parent_space_id_2,
754+ vec ! [ ] ,
755+ vec ! [ parent_space_id_1] ,
756+ & client,
757+ & server,
758+ & factory,
759+ user_id,
760+ )
761+ . await ;
799762
800763 let space_service = SpaceService :: new ( client. clone ( ) ) ;
801764
@@ -924,6 +887,137 @@ mod tests {
924887 assert ! ( result. is_ok( ) ) ;
925888 }
926889
890+ #[ async_test]
891+ async fn test_remove_child_from_space ( ) {
892+ // Given a space and child room where the user is admin of both.
893+ let server = MatrixMockServer :: new ( ) . await ;
894+ let client = server. client_builder ( ) . build ( ) . await ;
895+ let user_id = client. user_id ( ) . unwrap ( ) ;
896+ let factory = EventFactory :: new ( ) ;
897+
898+ server. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
899+
900+ let space_child_event_id = event_id ! ( "$1" ) ;
901+ let space_parent_event_id = event_id ! ( "$2" ) ;
902+ server. mock_set_space_child ( ) . ok ( space_child_event_id. to_owned ( ) ) . expect ( 1 ) . mount ( ) . await ;
903+ server. mock_set_space_parent ( ) . ok ( space_parent_event_id. to_owned ( ) ) . expect ( 1 ) . mount ( ) . await ;
904+
905+ let parent_id = room_id ! ( "!parent_space:example.org" ) ;
906+ let child_id = room_id ! ( "!child_space:example.org" ) ;
907+
908+ add_room_with_relationships (
909+ parent_id,
910+ vec ! [ ] ,
911+ vec ! [ child_id] ,
912+ & client,
913+ & server,
914+ & factory,
915+ user_id,
916+ )
917+ . await ;
918+ add_room_with_relationships (
919+ child_id,
920+ vec ! [ parent_id] ,
921+ vec ! [ ] ,
922+ & client,
923+ & server,
924+ & factory,
925+ user_id,
926+ )
927+ . await ;
928+
929+ let space_service = SpaceService :: new ( client. clone ( ) ) ;
930+
931+ // When removing the child from the space.
932+ let result =
933+ space_service. remove_child_from_space ( child_id. to_owned ( ) , parent_id. to_owned ( ) ) . await ;
934+
935+ // Then both space child and parent events are removed successfully.
936+ assert ! ( result. is_ok( ) ) ;
937+ }
938+
939+ #[ async_test]
940+ async fn test_remove_child_from_space_without_parent_event ( ) {
941+ // Given a space with a child where the m.space.parent event wasn't set.
942+ let server = MatrixMockServer :: new ( ) . await ;
943+ let client = server. client_builder ( ) . build ( ) . await ;
944+ let user_id = client. user_id ( ) . unwrap ( ) ;
945+ let factory = EventFactory :: new ( ) ;
946+
947+ server. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
948+
949+ let space_child_event_id = event_id ! ( "$1" ) ;
950+ server. mock_set_space_child ( ) . ok ( space_child_event_id. to_owned ( ) ) . expect ( 1 ) . mount ( ) . await ;
951+ server. mock_set_space_parent ( ) . unauthorized ( ) . expect ( 0 ) . mount ( ) . await ;
952+
953+ let parent_id = room_id ! ( "!parent_space:example.org" ) ;
954+ let child_id = room_id ! ( "!child_space:example.org" ) ;
955+
956+ add_room_with_relationships (
957+ parent_id,
958+ vec ! [ ] ,
959+ vec ! [ child_id] ,
960+ & client,
961+ & server,
962+ & factory,
963+ user_id,
964+ )
965+ . await ;
966+ add_room_with_relationships ( child_id, vec ! [ ] , vec ! [ ] , & client, & server, & factory, user_id)
967+ . await ;
968+
969+ let space_service = SpaceService :: new ( client. clone ( ) ) ;
970+
971+ // When removing the child from the space.
972+ let result =
973+ space_service. remove_child_from_space ( child_id. to_owned ( ) , parent_id. to_owned ( ) ) . await ;
974+
975+ // Then the child event is removed successfully and the parent event removal is
976+ // not attempted.
977+ assert ! ( result. is_ok( ) ) ;
978+ }
979+
980+ #[ async_test]
981+ async fn test_remove_child_from_space_without_child_event ( ) {
982+ // Given a space with a child where the space's m.space.child event wasn't set.
983+ let server = MatrixMockServer :: new ( ) . await ;
984+ let client = server. client_builder ( ) . build ( ) . await ;
985+ let user_id = client. user_id ( ) . unwrap ( ) ;
986+ let factory = EventFactory :: new ( ) ;
987+
988+ server. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
989+
990+ let space_parent_event_id = event_id ! ( "$2" ) ;
991+ server. mock_set_space_child ( ) . unauthorized ( ) . expect ( 0 ) . mount ( ) . await ;
992+ server. mock_set_space_parent ( ) . ok ( space_parent_event_id. to_owned ( ) ) . expect ( 1 ) . mount ( ) . await ;
993+
994+ let parent_id = room_id ! ( "!parent_space:example.org" ) ;
995+ let child_id = room_id ! ( "!child_space:example.org" ) ;
996+
997+ add_room_with_relationships ( parent_id, vec ! [ ] , vec ! [ ] , & client, & server, & factory, user_id)
998+ . await ;
999+ add_room_with_relationships (
1000+ child_id,
1001+ vec ! [ parent_id] ,
1002+ vec ! [ ] ,
1003+ & client,
1004+ & server,
1005+ & factory,
1006+ user_id,
1007+ )
1008+ . await ;
1009+
1010+ let space_service = SpaceService :: new ( client. clone ( ) ) ;
1011+
1012+ // When removing the child from the space.
1013+ let result =
1014+ space_service. remove_child_from_space ( child_id. to_owned ( ) , parent_id. to_owned ( ) ) . await ;
1015+
1016+ // Then the parent event is removed successfully and the child event removal is
1017+ // not attempted.
1018+ assert ! ( result. is_ok( ) ) ;
1019+ }
1020+
9271021 async fn add_space_rooms_with (
9281022 rooms : Vec < ( & RoomId , Option < & str > ) > ,
9291023 client : & Client ,
@@ -948,6 +1042,33 @@ mod tests {
9481042 }
9491043 }
9501044
1045+ async fn add_room_with_relationships (
1046+ room_id : & RoomId ,
1047+ parents : Vec < & RoomId > ,
1048+ children : Vec < & RoomId > ,
1049+ client : & Client ,
1050+ server : & MatrixMockServer ,
1051+ factory : & EventFactory ,
1052+ user_id : & UserId ,
1053+ ) {
1054+ let mut builder = JoinedRoomBuilder :: new ( room_id)
1055+ . add_state_event ( factory. create ( user_id, RoomVersionId :: V1 ) . with_space_type ( ) ) ;
1056+
1057+ for parent_id in parents {
1058+ builder = builder. add_state_event (
1059+ factory. space_parent ( parent_id. to_owned ( ) , room_id. to_owned ( ) ) . sender ( user_id) ,
1060+ ) ;
1061+ }
1062+
1063+ for child_id in children {
1064+ builder = builder. add_state_event (
1065+ factory. space_child ( room_id. to_owned ( ) , child_id. to_owned ( ) ) . sender ( user_id) ,
1066+ ) ;
1067+ }
1068+
1069+ server. sync_room ( client, builder) . await ;
1070+ }
1071+
9511072 async fn add_rooms_with_power_level (
9521073 rooms : Vec < ( & RoomId , i32 ) > ,
9531074 client : & Client ,
0 commit comments