ruma_federation_api/space/
get_hierarchy.rs

1//! `GET /_matrix/federation/*/hierarchy/{roomId}`
2//!
3//! Get the space tree in a depth-first manner to locate child rooms of a given space.
4
5pub mod v1 {
6    //! `/v1/` ([spec])
7    //!
8    //! [spec]: https://spec.matrix.org/latest/server-server-api/#get_matrixfederationv1hierarchyroomid
9
10    use ruma_common::{
11        api::{request, response, Metadata},
12        metadata,
13        room::RoomSummary,
14        OwnedRoomId,
15    };
16
17    use crate::space::SpaceHierarchyParentSummary;
18
19    const METADATA: Metadata = metadata! {
20        method: GET,
21        rate_limited: false,
22        authentication: ServerSignatures,
23        history: {
24            unstable => "/_matrix/federation/unstable/org.matrix.msc2946/hierarchy/{room_id}",
25            1.2 => "/_matrix/federation/v1/hierarchy/{room_id}",
26        }
27    };
28
29    /// Request type for the `hierarchy` endpoint.
30    #[request]
31    pub struct Request {
32        /// The room ID of the space to get a hierarchy for.
33        #[ruma_api(path)]
34        pub room_id: OwnedRoomId,
35
36        /// Whether or not the server should only consider suggested rooms.
37        ///
38        /// Suggested rooms are annotated in their `m.space.child` event contents.
39        #[ruma_api(query)]
40        #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
41        pub suggested_only: bool,
42    }
43
44    /// Response type for the `hierarchy` endpoint.
45    #[response]
46    pub struct Response {
47        /// A summary of the space’s children.
48        ///
49        /// Rooms which the requesting server cannot peek/join will be excluded.
50        pub children: Vec<RoomSummary>,
51
52        /// The list of room IDs the requesting server doesn’t have a viable way to peek/join.
53        ///
54        /// Rooms which the responding server cannot provide details on will be outright
55        /// excluded from the response instead.
56        pub inaccessible_children: Vec<OwnedRoomId>,
57
58        /// A summary of the requested room.
59        pub room: SpaceHierarchyParentSummary,
60    }
61
62    impl Request {
63        /// Creates a `Request` with the given room ID.
64        pub fn new(room_id: OwnedRoomId) -> Self {
65            Self { room_id, suggested_only: false }
66        }
67    }
68
69    impl Response {
70        /// Creates a new `Response` with the given room summary.
71        pub fn new(room_summary: SpaceHierarchyParentSummary) -> Self {
72            Self { children: Vec::new(), inaccessible_children: Vec::new(), room: room_summary }
73        }
74    }
75}
76
77#[cfg(all(test, feature = "client"))]
78mod tests {
79    use ruma_common::{api::IncomingResponse, OwnedRoomId};
80    use serde_json::{json, to_vec as to_json_vec};
81
82    use super::v1::Response;
83
84    #[test]
85    fn deserialize_response() {
86        let body = json!({
87            "children": [
88                {
89                    "room_id": "!a:localhost",
90                    "num_joined_members": 6,
91                    "world_readable": true,
92                    "guest_can_join": false,
93                    "join_rule": "public",
94                },
95            ],
96            "inaccessible_children": [],
97            "room": {
98                "room_id": "!room:localhost",
99                "num_joined_members": 5,
100                "world_readable": false,
101                "guest_can_join": false,
102                "join_rule": "restricted",
103                "allowed_room_ids": ["!otherroom:localhost"],
104                "type": "space",
105                "children_state": [
106                    {
107                        "content": {
108                            "via": [
109                                "example.org"
110                            ]
111                        },
112                        "origin_server_ts": 1_629_413_349,
113                        "sender": "@alice:example.org",
114                        "state_key": "!a:example.org",
115                        "type": "m.space.child"
116                    }
117                ],
118            },
119        });
120        let response = http::Response::new(to_json_vec(&body).unwrap());
121
122        let response = Response::try_from_http_response(response).unwrap();
123
124        assert_eq!(response.room.summary.room_id, "!room:localhost");
125        let space_child = response.room.children_state[0].deserialize().unwrap();
126        assert_eq!(space_child.state_key, "!a:example.org");
127        assert_eq!(response.inaccessible_children, &[] as &[OwnedRoomId]);
128        assert_eq!(response.children[0].room_id, "!a:localhost");
129    }
130}