ruma_client_api/profile/
get_profile.rs1pub mod v3 {
6 use std::collections::{btree_map, BTreeMap};
11
12 use ruma_common::{
13 api::{request, response, Metadata},
14 metadata, OwnedUserId,
15 };
16 use serde_json::Value as JsonValue;
17
18 #[cfg(feature = "unstable-msc4133")]
19 use crate::profile::{ProfileFieldName, ProfileFieldValue, StaticProfileField};
20
21 const METADATA: Metadata = metadata! {
22 method: GET,
23 rate_limited: false,
24 authentication: None,
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 #[cfg(feature = "unstable-msc4133")]
72 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 #[cfg(feature = "unstable-msc4133")]
85 pub fn set(&mut self, field: &str, value: JsonValue) {
86 self.data.insert(field.to_owned(), value);
87 }
88 }
89
90 impl FromIterator<(String, JsonValue)> for Response {
91 fn from_iter<T: IntoIterator<Item = (String, JsonValue)>>(iter: T) -> Self {
92 Self { data: iter.into_iter().collect() }
93 }
94 }
95
96 #[cfg(feature = "unstable-msc4133")]
97 impl FromIterator<(ProfileFieldName, JsonValue)> for Response {
98 fn from_iter<T: IntoIterator<Item = (ProfileFieldName, JsonValue)>>(iter: T) -> Self {
99 iter.into_iter().map(|(field, value)| (field.as_str().to_owned(), value)).collect()
100 }
101 }
102
103 #[cfg(feature = "unstable-msc4133")]
104 impl FromIterator<ProfileFieldValue> for Response {
105 fn from_iter<T: IntoIterator<Item = ProfileFieldValue>>(iter: T) -> Self {
106 iter.into_iter().map(|value| (value.field_name(), value.value().into_owned())).collect()
107 }
108 }
109
110 impl Extend<(String, JsonValue)> for Response {
111 fn extend<T: IntoIterator<Item = (String, JsonValue)>>(&mut self, iter: T) {
112 self.data.extend(iter);
113 }
114 }
115
116 #[cfg(feature = "unstable-msc4133")]
117 impl Extend<(ProfileFieldName, JsonValue)> for Response {
118 fn extend<T: IntoIterator<Item = (ProfileFieldName, JsonValue)>>(&mut self, iter: T) {
119 self.extend(iter.into_iter().map(|(field, value)| (field.as_str().to_owned(), value)));
120 }
121 }
122
123 #[cfg(feature = "unstable-msc4133")]
124 impl Extend<ProfileFieldValue> for Response {
125 fn extend<T: IntoIterator<Item = ProfileFieldValue>>(&mut self, iter: T) {
126 self.extend(
127 iter.into_iter().map(|value| (value.field_name(), value.value().into_owned())),
128 );
129 }
130 }
131
132 impl IntoIterator for Response {
133 type Item = (String, JsonValue);
134 type IntoIter = btree_map::IntoIter<String, JsonValue>;
135
136 fn into_iter(self) -> Self::IntoIter {
137 self.data.into_iter()
138 }
139 }
140}
141
142#[cfg(all(test, feature = "unstable-msc4133"))]
143mod tests {
144 use ruma_common::owned_mxc_uri;
145 use serde_json::{
146 from_slice as from_json_slice, json, to_vec as to_json_vec, Value as JsonValue,
147 };
148
149 use super::v3::Response;
150
151 #[test]
152 #[cfg(feature = "server")]
153 fn serialize_response() {
154 use ruma_common::api::OutgoingResponse;
155
156 use crate::profile::ProfileFieldValue;
157
158 let response = [
159 ProfileFieldValue::AvatarUrl(owned_mxc_uri!("mxc://localhost/abcdef")),
160 ProfileFieldValue::DisplayName("Alice".to_owned()),
161 ProfileFieldValue::new("custom_field", "value".into()).unwrap(),
162 ]
163 .into_iter()
164 .collect::<Response>();
165
166 let http_response = response.try_into_http_response::<Vec<u8>>().unwrap();
167
168 assert_eq!(
169 from_json_slice::<JsonValue>(http_response.body().as_ref()).unwrap(),
170 json!({
171 "avatar_url": "mxc://localhost/abcdef",
172 "displayname": "Alice",
173 "custom_field": "value",
174 })
175 );
176 }
177
178 #[test]
179 #[cfg(feature = "client")]
180 fn deserialize_response() {
181 use ruma_common::api::IncomingResponse;
182
183 use crate::profile::{AvatarUrl, DisplayName};
184
185 let body = to_json_vec(&json!({
187 "avatar_url": "mxc://localhost/abcdef",
188 "displayname": "Alice",
189 "custom_field": "value",
190 }))
191 .unwrap();
192
193 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
194 assert_eq!(response.get_static::<AvatarUrl>().unwrap().unwrap(), "mxc://localhost/abcdef");
195 assert_eq!(response.get_static::<DisplayName>().unwrap().unwrap(), "Alice");
196 assert_eq!(response.get("custom_field").unwrap().as_str().unwrap(), "value");
197
198 let body = to_json_vec(&json!({
200 "custom_field": null,
201 }))
202 .unwrap();
203
204 let response = Response::try_from_http_response(http::Response::new(body)).unwrap();
205 assert_eq!(response.get_static::<AvatarUrl>().unwrap(), None);
206 assert_eq!(response.get_static::<DisplayName>().unwrap(), None);
207 assert!(response.get("custom_field").unwrap().is_null());
208 }
209}