Skip to main content

ruma_client_api/profile/
query_profile.rs

1//! `POST /_matrix/client/*/profile/query`
2//!
3//! Get profile information of multiple users.
4
5pub mod unstable {
6    //! `msc4536` ([MSC])
7    //!
8    //! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/4536
9
10    use std::collections::BTreeMap;
11
12    use ruma_common::{
13        OwnedUserId,
14        api::{auth_scheme::AccessToken, request, response},
15        metadata,
16        profile::{ProfileFieldName, UserProfile},
17    };
18
19    metadata! {
20        method: POST,
21        rate_limited: true,
22        authentication: AccessToken,
23        history: {
24            unstable("org.matrix.msc4536") => "/_matrix/client/unstable/org.matrix.msc4536/profile/query",
25        }
26    }
27
28    /// Request type for the `query_profile` endpoint.
29    #[request]
30    pub struct Request {
31        /// The user IDs to query for.
32        ///
33        /// The homeserver may reject requests for over 100 users.
34        pub users: Vec<OwnedUserId>,
35
36        /// List of fields to include in the response.
37        ///
38        /// If `None`, all profile fields will be returned.
39        #[serde(skip_serializing_if = "Option::is_none")]
40        pub fields: Option<Vec<ProfileFieldName>>,
41    }
42
43    /// Response type for the `query_profile` endpoint.
44    #[response]
45    #[derive(Default)]
46    pub struct Response {
47        /// The requested profile information.
48        #[ruma_api(body)]
49        pub profiles: BTreeMap<OwnedUserId, UserProfile>,
50    }
51
52    impl Request {
53        /// Creates a new `Request` with the given user IDs.
54        pub fn new(users: Vec<OwnedUserId>) -> Self {
55            Self { users, fields: None }
56        }
57    }
58
59    impl Response {
60        /// Creates a new `Response` with the given profiles.
61        pub fn new(profiles: BTreeMap<OwnedUserId, UserProfile>) -> Self {
62            Self { profiles }
63        }
64    }
65}
66
67#[cfg(all(test, feature = "client"))]
68mod tests {
69    use std::borrow::Cow;
70
71    use ruma_common::{
72        api::{
73            IncomingResponseExt as _, MatrixVersion, OutgoingRequestExt as _, SupportedVersions,
74            auth_scheme::SendAccessToken,
75        },
76        owned_user_id,
77    };
78    use serde_json::{Value as JsonValue, json};
79
80    use super::unstable::{Request, Response};
81    use crate::profile::{AvatarUrl, DisplayName, ProfileFieldName};
82
83    #[test]
84    fn serialize_request() {
85        let supported = SupportedVersions {
86            versions: [MatrixVersion::V1_1].into(),
87            features: Default::default(),
88        };
89        let mut request = Request::new(vec![
90            owned_user_id!("@alice:localhost"),
91            owned_user_id!("@bob:localhost"),
92        ]);
93        request.fields = Some(vec![ProfileFieldName::DisplayName, ProfileFieldName::AvatarUrl]);
94
95        let request: http::Request<Vec<u8>> = request
96            .try_into_http_request(
97                "https://homeserver.tld",
98                SendAccessToken::IfRequired("auth_tok"),
99                Cow::Owned(supported),
100            )
101            .unwrap();
102        let (parts, body) = request.into_parts();
103
104        assert_eq!(
105            "https://homeserver.tld/_matrix/client/unstable/org.matrix.msc4536/profile/query",
106            parts.uri
107        );
108        assert_eq!("POST", parts.method);
109        assert_eq!(
110            json!({
111                "users": ["@alice:localhost", "@bob:localhost"],
112                "fields": ["displayname", "avatar_url"],
113            }),
114            serde_json::from_slice::<JsonValue>(&body).unwrap()
115        );
116    }
117
118    #[test]
119    fn deserialize_response() {
120        let body = json!({
121            "@alice:localhost": {
122                "avatar_url": "mxc://localhost/abcdef",
123                "displayname": "Alice",
124            },
125            "@bob:localhost": {
126                "displayname": "Bob",
127            },
128        })
129        .to_string();
130
131        let response =
132            Response::try_from_http_response(http::Response::new(body.as_bytes())).unwrap();
133        assert_eq!(response.profiles.len(), 2);
134
135        let alice = &response.profiles["@alice:localhost"];
136        assert_eq!(alice.get_static::<AvatarUrl>().unwrap().unwrap(), "mxc://localhost/abcdef");
137        assert_eq!(alice.get_static::<DisplayName>().unwrap().unwrap(), "Alice");
138
139        let bob = &response.profiles["@bob:localhost"];
140        assert_eq!(bob.get_static::<AvatarUrl>().unwrap(), None);
141        assert_eq!(bob.get_static::<DisplayName>().unwrap().unwrap(), "Bob");
142    }
143}