ruma_client_api/profile/
get_profile.rs1pub mod v3 {
6 use std::collections::{BTreeMap, btree_map};
11
12 use ruma_common::{
13 OwnedUserId,
14 api::{auth_scheme::NoAccessToken, request, response},
15 metadata,
16 profile::{ProfileFieldName, ProfileFieldValue},
17 };
18 use serde_json::Value as JsonValue;
19
20 use crate::profile::StaticProfileField;
21
22 metadata! {
23 method: GET,
24 rate_limited: false,
25 authentication: NoAccessToken,
26 history: {
27 1.0 => "/_matrix/client/r0/profile/{user_id}",
28 1.1 => "/_matrix/client/v3/profile/{user_id}",
29 }
30 }
31
32 #[request]
34 pub struct Request {
35 #[ruma_api(path)]
37 pub user_id: OwnedUserId,
38 }
39
40 #[response]
42 #[derive(Default)]
43 pub struct Response {
44 #[ruma_api(body)]
46 data: BTreeMap<String, JsonValue>,
47 }
48
49 impl Request {
50 pub fn new(user_id: OwnedUserId) -> Self {
52 Self { user_id }
53 }
54 }
55
56 impl Response {
57 pub fn new() -> Self {
59 Self::default()
60 }
61
62 pub fn get(&self, field: &str) -> Option<&JsonValue> {
64 self.data.get(field)
65 }
66
67 pub fn get_static<F: StaticProfileField>(
73 &self,
74 ) -> Result<Option<F::Value>, serde_json::Error> {
75 self.data.get(F::NAME).map(|value| serde_json::from_value(value.clone())).transpose()
76 }
77
78 pub fn iter(&self) -> btree_map::Iter<'_, String, JsonValue> {
80 self.data.iter()
81 }
82
83 pub fn set(&mut self, field: String, value: JsonValue) {
85 self.data.insert(field, value);
86 }
87 }
88
89 impl FromIterator<(String, JsonValue)> for Response {
90 fn from_iter<T: IntoIterator<Item = (String, JsonValue)>>(iter: T) -> Self {
91 Self { data: iter.into_iter().collect() }
92 }
93 }
94
95 impl FromIterator<(ProfileFieldName, JsonValue)> for Response {
96 fn from_iter<T: IntoIterator<Item = (ProfileFieldName, JsonValue)>>(iter: T) -> Self {
97 iter.into_iter().map(|(field, value)| (field.as_str().to_owned(), value)).collect()
98 }
99 }
100
101 impl FromIterator<ProfileFieldValue> for Response {
102 fn from_iter<T: IntoIterator<Item = ProfileFieldValue>>(iter: T) -> Self {
103 iter.into_iter().map(|value| (value.field_name(), value.value().into_owned())).collect()
104 }
105 }
106
107 impl Extend<(String, JsonValue)> for Response {
108 fn extend<T: IntoIterator<Item = (String, JsonValue)>>(&mut self, iter: T) {
109 self.data.extend(iter);
110 }
111 }
112
113 impl Extend<(ProfileFieldName, JsonValue)> for Response {
114 fn extend<T: IntoIterator<Item = (ProfileFieldName, JsonValue)>>(&mut self, iter: T) {
115 self.extend(iter.into_iter().map(|(field, value)| (field.as_str().to_owned(), value)));
116 }
117 }
118
119 impl Extend<ProfileFieldValue> for Response {
120 fn extend<T: IntoIterator<Item = ProfileFieldValue>>(&mut self, iter: T) {
121 self.extend(
122 iter.into_iter().map(|value| (value.field_name(), value.value().into_owned())),
123 );
124 }
125 }
126
127 impl IntoIterator for Response {
128 type Item = (String, JsonValue);
129 type IntoIter = btree_map::IntoIter<String, JsonValue>;
130
131 fn into_iter(self) -> Self::IntoIter {
132 self.data.into_iter()
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use serde_json::json;
140
141 use super::v3::Response;
142
143 #[test]
144 #[cfg(feature = "server")]
145 fn serialize_response() {
146 use ruma_common::{api::OutgoingResponse, owned_mxc_uri, profile::ProfileFieldValue};
147 use serde_json::{Value as JsonValue, from_slice as from_json_slice};
148
149 let response = [
150 ProfileFieldValue::AvatarUrl(owned_mxc_uri!("mxc://localhost/abcdef")),
151 ProfileFieldValue::DisplayName("Alice".to_owned()),
152 ProfileFieldValue::new("custom_field", "value".into()).unwrap(),
153 ]
154 .into_iter()
155 .collect::<Response>();
156
157 let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
158
159 assert_eq!(
160 from_json_slice::<JsonValue>(http_response.body().as_ref()).unwrap(),
161 json!({
162 "avatar_url": "mxc://localhost/abcdef",
163 "displayname": "Alice",
164 "custom_field": "value",
165 })
166 );
167 }
168
169 #[test]
170 #[cfg(feature = "client")]
171 fn deserialize_response() {
172 use ruma_common::api::IncomingResponse;
173 use serde_json::to_vec as to_json_vec;
174
175 use crate::profile::{AvatarUrl, DisplayName};
176
177 let body = to_json_vec(&json!({
179 "avatar_url": "mxc://localhost/abcdef",
180 "displayname": "Alice",
181 "custom_field": "value",
182 }))
183 .unwrap();
184
185 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
186 assert_eq!(response.get_static::<AvatarUrl>().unwrap().unwrap(), "mxc://localhost/abcdef");
187 assert_eq!(response.get_static::<DisplayName>().unwrap().unwrap(), "Alice");
188 assert_eq!(response.get("custom_field").unwrap().as_str().unwrap(), "value");
189
190 let body = to_json_vec(&json!({
192 "custom_field": null,
193 }))
194 .unwrap();
195
196 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
197 assert_eq!(response.get_static::<AvatarUrl>().unwrap(), None);
198 assert_eq!(response.get_static::<DisplayName>().unwrap(), None);
199 assert!(response.get("custom_field").unwrap().is_null());
200 }
201}