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 serde_json::json;
139
140 use super::v3::Response;
141
142 #[test]
143 #[cfg(feature = "server")]
144 fn serialize_response() {
145 use ruma_common::{api::OutgoingResponse, owned_mxc_uri};
146 use serde_json::{Value as JsonValue, from_slice as from_json_slice};
147
148 use crate::profile::ProfileFieldValue;
149
150 let response = [
151 ProfileFieldValue::AvatarUrl(owned_mxc_uri!("mxc://localhost/abcdef")),
152 ProfileFieldValue::DisplayName("Alice".to_owned()),
153 ProfileFieldValue::new("custom_field", "value".into()).unwrap(),
154 ]
155 .into_iter()
156 .collect::<Response>();
157
158 let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
159
160 assert_eq!(
161 from_json_slice::<JsonValue>(http_response.body().as_ref()).unwrap(),
162 json!({
163 "avatar_url": "mxc://localhost/abcdef",
164 "displayname": "Alice",
165 "custom_field": "value",
166 })
167 );
168 }
169
170 #[test]
171 #[cfg(feature = "client")]
172 fn deserialize_response() {
173 use ruma_common::api::IncomingResponse;
174 use serde_json::to_vec as to_json_vec;
175
176 use crate::profile::{AvatarUrl, DisplayName};
177
178 let body = to_json_vec(&json!({
180 "avatar_url": "mxc://localhost/abcdef",
181 "displayname": "Alice",
182 "custom_field": "value",
183 }))
184 .unwrap();
185
186 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
187 assert_eq!(response.get_static::<AvatarUrl>().unwrap().unwrap(), "mxc://localhost/abcdef");
188 assert_eq!(response.get_static::<DisplayName>().unwrap().unwrap(), "Alice");
189 assert_eq!(response.get("custom_field").unwrap().as_str().unwrap(), "value");
190
191 let body = to_json_vec(&json!({
193 "custom_field": null,
194 }))
195 .unwrap();
196
197 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
198 assert_eq!(response.get_static::<AvatarUrl>().unwrap(), None);
199 assert_eq!(response.get_static::<DisplayName>().unwrap(), None);
200 assert!(response.get("custom_field").unwrap().is_null());
201 }
202}