prelude_xml_parser/native/
user_native.rs1use serde::{Deserialize, Serialize};
2
3#[cfg(feature = "python")]
4use pyo3::{exceptions::PyValueError, prelude::*, types::PyDict};
5
6pub use crate::native::common::{Category, Comment, Entry, Field, Form, Reason, State, Value};
7use crate::native::deserializers::{default_string_none, deserialize_empty_string_as_none};
8
9#[cfg(not(feature = "python"))]
10#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
11#[serde(rename_all = "camelCase")]
12pub struct User {
13 #[serde(rename = "uniqueId")]
14 #[serde(alias = "@uniqueId")]
15 #[serde(alias = "uniqueId")]
16 pub unique_id: String,
17
18 #[serde(rename = "lastLanguage")]
19 #[serde(alias = "@lastLanguage")]
20 #[serde(alias = "lastLanguage")]
21 #[serde(
22 default = "default_string_none",
23 deserialize_with = "deserialize_empty_string_as_none"
24 )]
25 pub last_language: Option<String>,
26 #[serde(rename = "creator")]
27 #[serde(alias = "@creator")]
28 #[serde(alias = "creator")]
29 pub creator: String,
30 #[serde(rename = "numberOfForms")]
31 #[serde(alias = "@numberOfForms")]
32 #[serde(alias = "numberOfForms")]
33 pub number_of_forms: usize,
34
35 #[serde(alias = "form")]
36 pub forms: Option<Vec<Form>>,
37}
38
39#[cfg(feature = "python")]
40#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
41#[serde(rename_all = "camelCase")]
42#[pyclass(get_all)]
43pub struct User {
44 #[serde(rename = "uniqueId")]
45 #[serde(alias = "@uniqueId")]
46 #[serde(alias = "uniqueId")]
47 pub unique_id: String,
48
49 #[serde(rename = "lastLanguage")]
50 #[serde(alias = "@lastLanguage")]
51 #[serde(alias = "lastLanguage")]
52 #[serde(
53 default = "default_string_none",
54 deserialize_with = "deserialize_empty_string_as_none"
55 )]
56 pub last_language: Option<String>,
57 #[serde(rename = "creator")]
58 #[serde(alias = "@creator")]
59 #[serde(alias = "creator")]
60 pub creator: String,
61 #[serde(rename = "numberOfForms")]
62 #[serde(alias = "@numberOfForms")]
63 #[serde(alias = "numberOfForms")]
64 pub number_of_forms: usize,
65
66 #[serde(alias = "form")]
67 pub forms: Option<Vec<Form>>,
68}
69
70#[cfg(feature = "python")]
71#[pymethods]
72impl User {
73 #[getter]
74 fn unique_id(&self) -> PyResult<String> {
75 Ok(self.unique_id.clone())
76 }
77
78 #[getter]
79 fn last_language(&self) -> PyResult<Option<String>> {
80 Ok(self.last_language.clone())
81 }
82
83 #[getter]
84 fn creator(&self) -> PyResult<String> {
85 Ok(self.creator.clone())
86 }
87
88 #[getter]
89 fn forms(&self) -> PyResult<Option<Vec<Form>>> {
90 Ok(self.forms.clone())
91 }
92
93 pub fn to_dict<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
94 let dict = PyDict::new(py);
95 dict.set_item("unique_id", &self.unique_id)?;
96 dict.set_item("last_language", &self.last_language)?;
97 dict.set_item("creator", &self.creator)?;
98 dict.set_item("number_of_forms", self.number_of_forms)?;
99
100 let mut form_dicts = Vec::new();
101 if let Some(forms) = &self.forms {
102 for form in forms {
103 let form_dict = form.to_dict(py)?;
104 form_dicts.push(form_dict);
105 }
106 dict.set_item("forms", form_dicts)?;
107 } else {
108 dict.set_item("forms", py.None())?;
109 }
110
111 Ok(dict)
112 }
113}
114
115#[cfg(not(feature = "python"))]
116#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
118#[serde(rename_all = "camelCase")]
119pub struct UserNative {
120 #[serde(alias = "user")]
121 pub users: Vec<User>,
122}
123
124#[cfg(not(feature = "python"))]
125impl UserNative {
126 pub fn to_json(&self) -> serde_json::Result<String> {
143 let json = serde_json::to_string(&self)?;
144
145 Ok(json)
146 }
147}
148
149#[cfg(feature = "python")]
150#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
152#[serde(rename_all = "camelCase")]
153#[pyclass(get_all)]
154pub struct UserNative {
155 #[serde(alias = "user")]
156 pub users: Vec<User>,
157}
158
159#[cfg(feature = "python")]
160#[pymethods]
161impl UserNative {
162 #[getter]
163 fn users(&self) -> PyResult<Vec<User>> {
164 Ok(self.users.clone())
165 }
166
167 fn to_dict<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
169 let dict = PyDict::new(py);
170 let mut user_dicts = Vec::new();
171 for user in &self.users {
172 let user_dict = user.to_dict(py)?;
173 user_dicts.push(user_dict);
174 }
175 dict.set_item("users", user_dicts)?;
176 Ok(dict)
177 }
178
179 fn to_json(&self) -> PyResult<String> {
181 serde_json::to_string(&self)
182 .map_err(|_| PyErr::new::<PyValueError, _>("Error converting to JSON"))
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use insta::assert_yaml_snapshot;
190
191 #[test]
192 fn deserialize_user_native_json() {
193 let json_str = r#"{
194 "users": [
195 {
196 "uniqueId": "1691421275437",
197 "lastLanguage": null,
198 "creator": "Paul Sanders(1681162687395)",
199 "numberOfForms": 1,
200 "forms": [
201 {
202 "name": "form.name.demographics",
203 "lastModified": "2023-08-07T15:15:41Z",
204 "whoLastModifiedName": "Paul Sanders",
205 "whoLastModifiedRole": "Project Manager",
206 "whenCreated": 1691421341578,
207 "hasErrors": false,
208 "hasWarnings": false,
209 "locked": false,
210 "user": null,
211 "dateTimeChanged": null,
212 "formTitle": "User Demographics",
213 "formIndex": 1,
214 "formGroup": null,
215 "formState": "In-Work",
216 "states": [
217 {
218 "value": "form.state.in.work",
219 "signer": "Paul Sanders - Project Manager",
220 "signerUniqueId": "1681162687395",
221 "dateSigned": "2023-08-07T15:15:41Z"
222 }
223 ],
224 "categories": [
225 {
226 "name": "demographics",
227 "categoryType": "normal",
228 "highestIndex": 0,
229 "fields": [
230 {
231 "name": "address",
232 "fieldType": "text",
233 "dataType": "string",
234 "errorCode": "undefined",
235 "whenCreated": "2024-01-12T20:14:09Z",
236 "keepHistory": true,
237 "entries": null
238 },
239 {
240 "name": "email",
241 "fieldType": "text",
242 "dataType": "string",
243 "errorCode": "undefined",
244 "whenCreated": "2023-08-07T15:15:41Z",
245 "keepHistory": true,
246 "entries": [
247 {
248 "entryId": "1",
249 "value": {
250 "by": "Paul Sanders",
251 "byUniqueId": "1681162687395",
252 "role": "Project Manager",
253 "when": "2023-08-07T15:15:41Z",
254 "value": "jazz@artemis.com"
255 },
256 "reason": null
257 }
258 ]
259 }
260 ]
261 },
262 {
263 "name": "Administrative",
264 "categoryType": "normal",
265 "highestIndex": 0,
266 "fields": [
267 {
268 "name": "study_assignment",
269 "fieldType": "text",
270 "dataType": null,
271 "errorCode": "undefined",
272 "whenCreated": "2023-08-07T15:15:41Z",
273 "keepHistory": true,
274 "entries": [
275 {
276 "entryId": "1",
277 "value": {
278 "by": "set from calculation",
279 "byUniqueId": null,
280 "role": "System",
281 "when": "2023-08-07T15:15:41Z",
282 "value": "On 07-Aug-2023 10:15 -0500, Paul Sanders assigned user from another study"
283 },
284 "reason": {
285 "by": "set from calculation",
286 "byUniqueId": null,
287 "role": "System",
288 "when": "2023-08-07T15:15:41Z",
289 "value": "calculated value"
290 }
291 }
292 ]
293 }
294 ]
295 }
296 ]
297 }
298 ]
299 }
300 ]
301}
302
303 "#;
304
305 let result: UserNative = serde_json::from_str(json_str).unwrap();
306
307 assert_yaml_snapshot!(result);
308 }
309}