Skip to main content

freedom_models/
user.rs

1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use time::OffsetDateTime;
5use url::Url;
6
7use crate::Hateoas;
8
9#[cfg(feature = "serde")]
10use super::utils;
11
12#[cfg_attr(
13    feature = "serde",
14    derive(Serialize, Deserialize),
15    serde(rename_all = "camelCase")
16)]
17#[derive(Debug, Clone, PartialEq)]
18#[cfg_attr(not(feature = "unstable"), non_exhaustive)]
19pub struct UserPreferences {
20    pub visibility_days: u32,
21    pub min_elevation: f32,
22    pub max_elevation: f32,
23    pub min_duration: f32,
24    pub elevation_tolerance: f32,
25    pub duration_tolerance: f32,
26    pub notify_via_email: bool,
27    pub notify_via_text: bool,
28}
29
30/// The data model returned from the `api/users/search/whoami` endpoint
31#[cfg_attr(
32    feature = "serde",
33    derive(Serialize, Deserialize),
34    serde(rename_all = "camelCase")
35)]
36#[derive(Debug, Clone, PartialEq)]
37#[cfg_attr(not(feature = "unstable"), non_exhaustive)]
38pub struct WhoAmI {
39    /// ID of the user
40    pub id: i32,
41    /// First name of the user
42    pub first_name: String,
43    /// Last name of the user
44    pub last_name: String,
45    /// Email address of the user
46    pub email: String,
47    /// Describes whether the associated user was created as a machine service user
48    pub machine_service: bool,
49    /// The role assigned to the user
50    pub ui_role: String,
51    /// The set of privileges assigned to the user
52    pub ui_privilege: String,
53    #[cfg_attr(
54        feature = "serde",
55        serde(rename = "_links", with = "utils::links::serde", default)
56    )]
57    pub links: HashMap<String, Url>,
58}
59
60impl Hateoas for WhoAmI {
61    fn get_links(&self) -> &HashMap<String, url::Url> {
62        &self.links
63    }
64
65    fn get_links_mut(&mut self) -> &mut HashMap<String, url::Url> {
66        &mut self.links
67    }
68}
69
70/// A user in freedom
71#[cfg_attr(
72    feature = "serde",
73    derive(Serialize, Deserialize),
74    serde(rename_all = "camelCase")
75)]
76#[derive(Debug, Clone, PartialEq)]
77#[cfg_attr(not(feature = "unstable"), non_exhaustive)]
78pub struct User {
79    #[cfg_attr(feature = "serde", serde(with = "time::serde::iso8601"))]
80    pub created: OffsetDateTime,
81    #[cfg_attr(
82        feature = "serde",
83        serde(default, with = "time::serde::iso8601::option")
84    )]
85    pub modified: Option<OffsetDateTime>,
86    pub first_name: String,
87    pub last_name: String,
88    pub verified: bool,
89    pub email: String,
90    pub preferences: UserPreferences,
91    /// Unavailable for user accounts
92    #[cfg_attr(feature = "serde", serde(default))]
93    pub internal_meta_data: Option<HashMap<String, String>>,
94    /// Unavailable for user accounts
95    #[cfg_attr(feature = "serde", serde(default))]
96    pub deleted: Option<bool>,
97    pub api_access_enabled: bool,
98    #[cfg_attr(
99        feature = "serde",
100        serde(rename = "_links", with = "utils::links::serde", default)
101    )]
102    pub links: HashMap<String, Url>,
103}
104
105impl Hateoas for User {
106    fn get_links(&self) -> &HashMap<String, url::Url> {
107        &self.links
108    }
109
110    fn get_links_mut(&mut self) -> &mut HashMap<String, url::Url> {
111        &mut self.links
112    }
113}
114
115#[cfg(all(feature = "serde", test))]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn whoami_deserializes_full_response() {
121        let json = r#"{
122            "uiRole": "ROLE_OPERATOR",
123            "uiPrivilege": "UI_PRIVILEGE_VIEW_TASKS,UI_PRIVILEGE_VIEW_SATELLITES",
124            "id": 42,
125            "email": "test.user@example.com",
126            "firstName": "Test",
127            "lastName": "User",
128            "machineService": false,
129            "_links": {
130                "self": { "href": "https://api.example.com/api/users/42" },
131                "users": { "href": "https://api.example.com/api/users/42" }
132            }
133        }"#;
134
135        let whoami: WhoAmI = serde_json::from_str(json).unwrap();
136
137        assert_eq!(whoami.id, 42);
138        assert_eq!(whoami.email, "test.user@example.com");
139        assert_eq!(whoami.first_name, "Test");
140        assert_eq!(whoami.last_name, "User");
141        assert!(!whoami.machine_service);
142        assert_eq!(whoami.ui_role, "ROLE_OPERATOR");
143        assert_eq!(
144            whoami.ui_privilege,
145            "UI_PRIVILEGE_VIEW_TASKS,UI_PRIVILEGE_VIEW_SATELLITES"
146        );
147    }
148
149    #[test]
150    fn whoami_deserializes_links() {
151        let json = r#"{
152            "uiRole": "ROLE_ADMIN",
153            "uiPrivilege": "UI_PRIVILEGE_VIEW_ALL",
154            "id": 1,
155            "email": "admin@example.com",
156            "firstName": "Admin",
157            "lastName": "User",
158            "machineService": false,
159            "_links": {
160                "self": { "href": "https://api.example.com/api/users/1" },
161                "users": { "href": "https://api.example.com/api/users/1" }
162            }
163        }"#;
164
165        let whoami: WhoAmI = serde_json::from_str(json).unwrap();
166
167        let self_link = whoami.get_links().get("self").unwrap();
168        assert_eq!(self_link.as_str(), "https://api.example.com/api/users/1");
169        assert!(whoami.get_links().contains_key("users"));
170    }
171
172    #[test]
173    fn whoami_deserializes_without_links() {
174        let json = r#"{
175            "uiRole": "ROLE_USER",
176            "uiPrivilege": "UI_PRIVILEGE_VIEW_TASKS",
177            "id": 99,
178            "email": "nolinks@example.com",
179            "firstName": "No",
180            "lastName": "Links",
181            "machineService": false
182        }"#;
183
184        let whoami: WhoAmI = serde_json::from_str(json).unwrap();
185        assert!(whoami.links.is_empty());
186    }
187
188    #[test]
189    fn whoami_deserializes_machine_service_user() {
190        let json = r#"{
191            "uiRole": "ROLE_SERVICE",
192            "uiPrivilege": "UI_PRIVILEGE_MANAGE_TASKS",
193            "id": 200,
194            "email": "machine@example.com",
195            "firstName": "Machine",
196            "lastName": "Service",
197            "machineService": true
198        }"#;
199
200        let whoami: WhoAmI = serde_json::from_str(json).unwrap();
201        assert!(whoami.machine_service);
202    }
203
204    #[test]
205    fn whoami_serializes_links_with_href_wrapper() {
206        let json = r#"{
207            "uiRole": "ROLE_USER",
208            "uiPrivilege": "UI_PRIVILEGE_VIEW_TASKS",
209            "id": 10,
210            "email": "roundtrip@example.com",
211            "firstName": "Round",
212            "lastName": "Trip",
213            "machineService": false,
214            "_links": {
215                "self": { "href": "https://api.example.com/api/users/10" }
216            }
217        }"#;
218
219        let whoami: WhoAmI = serde_json::from_str(json).unwrap();
220        let serialized = serde_json::to_value(&whoami).unwrap();
221
222        assert_eq!(
223            serialized["_links"]["self"]["href"],
224            "https://api.example.com/api/users/10"
225        );
226    }
227
228    #[test]
229    fn whoami_get_links_mut_allows_insertion() {
230        let json = r#"{
231            "uiRole": "ROLE_USER",
232            "uiPrivilege": "UI_PRIVILEGE_VIEW_TASKS",
233            "id": 5,
234            "email": "mut@example.com",
235            "firstName": "Mut",
236            "lastName": "User",
237            "machineService": false
238        }"#;
239
240        let mut whoami: WhoAmI = serde_json::from_str(json).unwrap();
241        whoami.get_links_mut().insert(
242            "self".into(),
243            "https://api.example.com/api/users/5".parse().unwrap(),
244        );
245
246        assert!(whoami.get_links().contains_key("self"));
247    }
248}