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