ruma_client_api/room/
get_summary.rs

1//! `GET /_matrix/client/v1/summary/{roomIdOrAlias}`
2//!
3//! Returns a short description of the state of a room.
4
5pub mod v1 {
6    //! `v1` ([spec])
7    //!
8    //! [spec]: https://spec.matrix.org/latest/client-server-api/#get_matrixclientv1room_summaryroomidoralias
9
10    use ruma_common::{
11        api::{request, Metadata},
12        metadata,
13        room::RoomSummary,
14        OwnedRoomOrAliasId, OwnedServerName,
15    };
16    use ruma_events::room::member::MembershipState;
17
18    const METADATA: Metadata = metadata! {
19        method: GET,
20        rate_limited: false,
21        authentication: AccessTokenOptional,
22        history: {
23            unstable => "/_matrix/client/unstable/im.nheko.summary/rooms/{room_id_or_alias}/summary",
24            1.15 => "/_matrix/client/v1/room_summary/{room_id_or_alias}",
25        }
26    };
27
28    /// Request type for the `get_summary` endpoint.
29    #[request(error = crate::Error)]
30    pub struct Request {
31        /// Alias or ID of the room to be summarized.
32        #[ruma_api(path)]
33        pub room_id_or_alias: OwnedRoomOrAliasId,
34
35        /// A list of servers the homeserver should attempt to use to peek at the room.
36        ///
37        /// Defaults to an empty `Vec`.
38        #[serde(default, skip_serializing_if = "Vec::is_empty")]
39        #[ruma_api(query)]
40        pub via: Vec<OwnedServerName>,
41    }
42
43    impl Request {
44        /// Creates a new `Request` with the given room or alias ID and via server names.
45        pub fn new(room_id_or_alias: OwnedRoomOrAliasId, via: Vec<OwnedServerName>) -> Self {
46            Self { room_id_or_alias, via }
47        }
48    }
49
50    /// Response type for the `get_summary` endpoint.
51    #[derive(Debug, Clone)]
52    #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
53    pub struct Response {
54        /// The summary of the room.
55        pub summary: RoomSummary,
56
57        /// The current membership of this user in the room.
58        ///
59        /// This field will not be present when called unauthenticated, but is required when called
60        /// authenticated. It should be `leave` if the server doesn't know about the room, since
61        /// for all other membership states the server would know about the room already.
62        pub membership: Option<MembershipState>,
63    }
64
65    impl Response {
66        /// Creates a new [`Response`] with the given summary.
67        pub fn new(summary: RoomSummary) -> Self {
68            Self { summary, membership: None }
69        }
70    }
71
72    impl From<RoomSummary> for Response {
73        fn from(value: RoomSummary) -> Self {
74            Self::new(value)
75        }
76    }
77
78    #[cfg(feature = "server")]
79    impl ruma_common::api::OutgoingResponse for Response {
80        fn try_into_http_response<T: Default + bytes::BufMut>(
81            self,
82        ) -> Result<http::Response<T>, ruma_common::api::error::IntoHttpError> {
83            #[derive(serde::Serialize)]
84            struct ResponseSerHelper {
85                #[serde(flatten)]
86                summary: RoomSummary,
87                #[serde(skip_serializing_if = "Option::is_none")]
88                membership: Option<MembershipState>,
89            }
90
91            let body = ResponseSerHelper { summary: self.summary, membership: self.membership };
92
93            http::Response::builder()
94                .header(http::header::CONTENT_TYPE, "application/json")
95                .body(ruma_common::serde::json_to_buf(&body)?)
96                .map_err(Into::into)
97        }
98    }
99
100    #[cfg(feature = "client")]
101    impl ruma_common::api::IncomingResponse for Response {
102        type EndpointError = crate::Error;
103
104        fn try_from_http_response<T: AsRef<[u8]>>(
105            response: http::Response<T>,
106        ) -> Result<Self, ruma_common::api::error::FromHttpResponseError<Self::EndpointError>>
107        {
108            use ruma_common::{api::EndpointError, serde::from_raw_json_value};
109
110            #[derive(serde::Deserialize)]
111            struct ResponseDeHelper {
112                membership: Option<MembershipState>,
113            }
114
115            if response.status().as_u16() >= 400 {
116                return Err(ruma_common::api::error::FromHttpResponseError::Server(
117                    Self::EndpointError::from_http_response(response),
118                ));
119            }
120
121            let raw_json = serde_json::from_slice::<Box<serde_json::value::RawValue>>(
122                response.body().as_ref(),
123            )?;
124            let summary = from_raw_json_value::<RoomSummary, serde_json::Error>(&raw_json)?;
125            let membership =
126                from_raw_json_value::<ResponseDeHelper, serde_json::Error>(&raw_json)?.membership;
127
128            Ok(Self { summary, membership })
129        }
130    }
131}
132
133#[cfg(all(test, feature = "client"))]
134mod tests {
135    use ruma_common::api::IncomingResponse;
136    use ruma_events::room::member::MembershipState;
137    use serde_json::{json, to_vec as to_json_vec};
138
139    use super::v1::Response;
140
141    #[test]
142    fn deserialize_response() {
143        let body = json!({
144            "room_id": "!room:localhost",
145            "num_joined_members": 5,
146            "world_readable": false,
147            "guest_can_join": false,
148            "join_rule": "restricted",
149            "allowed_room_ids": ["!otherroom:localhost"],
150            "membership": "invite",
151        });
152        let response = http::Response::new(to_json_vec(&body).unwrap());
153
154        let response = Response::try_from_http_response(response).unwrap();
155        assert_eq!(response.summary.room_id, "!room:localhost");
156        assert_eq!(response.membership, Some(MembershipState::Invite));
157    }
158}