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