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