oparl_types/
person.rs

1// SPDX-FileCopyrightText: Politik im Blick developers
2// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2
5
6use url::Url;
7
8use crate::{
9    namespace::PersonNamespaceUrl, BodyId, DateTime, EmailAddress, Keyword, Location, LocationId,
10    Membership, Name, PersonId,
11};
12
13#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct Person {
16    pub id: PersonId,
17
18    #[serde(rename = "type")]
19    pub namespace: PersonNamespaceUrl,
20
21    #[serde(default, skip_serializing_if = "Option::is_none")]
22    pub body: Option<BodyId>,
23
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub name: Option<Name>,
26
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub family_name: Option<Name>,
29
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub given_name: Option<Name>,
32
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub form_of_address: Option<String>,
35
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub affix: Option<String>,
38
39    #[serde(default, skip_serializing_if = "Vec::is_empty")]
40    pub title: Vec<String>,
41
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub gender: Option<String>,
44
45    #[serde(default, skip_serializing_if = "Vec::is_empty")]
46    pub phone: Vec<String>,
47
48    #[serde(default, skip_serializing_if = "Vec::is_empty")]
49    pub email: Vec<EmailAddress>,
50
51    #[serde(default, skip_serializing_if = "Option::is_none")]
52    pub location: Option<LocationId>,
53
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub location_object: Option<Location>,
56
57    #[serde(default, skip_serializing_if = "Vec::is_empty")]
58    pub status: Vec<String>,
59
60    #[serde(default, skip_serializing_if = "Vec::is_empty")]
61    pub membership: Vec<Membership>,
62
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub life: Option<String>,
65
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub life_source: Option<String>,
68
69    #[serde(default, skip_serializing_if = "Option::is_none")]
70    pub license: Option<Url>,
71
72    #[serde(default, skip_serializing_if = "Vec::is_empty")]
73    pub keyword: Vec<Keyword>,
74
75    pub created: DateTime,
76
77    pub modified: DateTime,
78
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    pub web: Option<Url>,
81
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub deleted: Option<bool>,
84}
85
86#[cfg(test)]
87mod serde_tests {
88    use super::Person;
89    use crate::{
90        namespace::{MembershipNamespaceUrl, PersonNamespaceUrl},
91        Membership,
92    };
93
94    use pretty_assertions::assert_eq;
95    use serde_json::json;
96    use time::macros::{date, datetime};
97
98    fn example_person() -> Person {
99        Person {
100            id: "https://oparl.example.org/person/29"
101                .parse()
102                .expect("value must be parseable as id"),
103            namespace: PersonNamespaceUrl::Identifier,
104            body: Some(
105                "https://oparl.example.org/body/0"
106                    .parse()
107                    .expect("value must be parseable as url"),
108            ),
109            name: Some("Prof. Dr. Max Mustermann".into()),
110            family_name: Some("Mustermann".into()),
111            given_name: Some("Max".into()),
112            form_of_address: Some("Ratsfrau".into()),
113            affix: None,
114            title: vec!["Prof.".into(), "Dr.".into()],
115            gender: Some("male".into()),
116            email: vec!["max@mustermann.de"
117                .parse()
118                .expect("value must be parseable as email")],
119            phone: vec!["+493012345678".into()],
120            location: None,
121            location_object: None,
122            status: vec!["Bezirksbürgermeister".into()],
123            membership: vec![
124                Membership {
125                    id: "https://oparl.example.org/memberships/385"
126                        .parse()
127                        .expect("value must be parseable as id"),
128                    namespace: MembershipNamespaceUrl::Identifier,
129                    person: None,
130                    organization: Some(
131                        "https://oparl.example.org/organizations/5"
132                            .parse()
133                            .expect("value must be parseable as url"),
134                    ),
135                    role: Some("Vorsitzende".into()),
136                    voting_right: Some(true),
137                    start_date: Some(date!(2013 - 12 - 03).into()),
138                    end_date: None,
139                    on_behalf_of: None,
140                    license: None,
141                    keyword: vec![],
142                    created: datetime!(2011-11-11 11:11:00 +01:00).into(),
143                    modified: datetime!(2012-08-16 14:05:27 +02:00).into(),
144                    web: None,
145                    deleted: None,
146                },
147                Membership {
148                    id: "https://oparl.example.org/memberships/693"
149                        .parse()
150                        .expect("value must be parseable as id"),
151                    namespace: MembershipNamespaceUrl::Identifier,
152                    person: None,
153                    organization: Some(
154                        "https://oparl.example.org/organizations/9"
155                            .parse()
156                            .expect("value must be parseable as url"),
157                    ),
158                    role: Some("Sachkundige Bürgerin".into()),
159                    voting_right: Some(false),
160                    start_date: Some(date!(2013 - 12 - 03).into()),
161                    end_date: Some(date!(2014 - 07 - 28).into()),
162                    on_behalf_of: None,
163                    license: None,
164                    keyword: vec![],
165                    created: datetime!(2011-11-11 11:11:00 +01:00).into(),
166                    modified: datetime!(2012-08-16 14:05:27 +02:00).into(),
167                    web: None,
168                    deleted: None,
169                },
170            ],
171            life: None,
172            life_source: None,
173            license: None,
174            keyword: vec![],
175            created: datetime!(2011-11-11 11:11:00 +01:00).into(),
176            modified: datetime!(2012-08-16 14:05:27 +02:00).into(),
177            web: None,
178            deleted: None,
179        }
180    }
181
182    fn example_person_json() -> serde_json::Value {
183        json!({
184            "id": "https://oparl.example.org/person/29",
185            "type": "https://schema.oparl.org/1.1/Person",
186            "body": "https://oparl.example.org/body/0",
187            "name": "Prof. Dr. Max Mustermann",
188            "familyName": "Mustermann",
189            "givenName": "Max",
190            "title": [
191                "Prof.",
192                "Dr."
193            ],
194            "formOfAddress": "Ratsfrau",
195            "gender": "male",
196            "email": [
197                "max@mustermann.de"
198            ],
199            "phone": [
200                "+493012345678"
201            ],
202            "status": [
203                "Bezirksbürgermeister"
204            ],
205            "membership": [
206                {
207                    "id": "https://oparl.example.org/memberships/385",
208                    "type": "https://schema.oparl.org/1.1/Membership",
209                    "organization": "https://oparl.example.org/organizations/5",
210                    "role": "Vorsitzende",
211                    "votingRight": true,
212                    "startDate": "2013-12-03",
213                    "created": "2011-11-11T11:11:00+01:00",
214                    "modified": "2012-08-16T14:05:27+02:00"
215                },
216                {
217                    "id": "https://oparl.example.org/memberships/693",
218                    "type": "https://schema.oparl.org/1.1/Membership",
219                    "organization": "https://oparl.example.org/organizations/9",
220                    "role": "Sachkundige Bürgerin",
221                    "votingRight": false,
222                    "startDate": "2013-12-03",
223                    "endDate": "2014-07-28",
224                    "created": "2011-11-11T11:11:00+01:00",
225                    "modified": "2012-08-16T14:05:27+02:00"
226                }
227            ],
228            "created": "2011-11-11T11:11:00+01:00",
229            "modified": "2012-08-16T14:05:27+02:00"
230        })
231    }
232
233    #[test]
234    fn serialize() {
235        assert_eq!(json!(example_person()), example_person_json());
236    }
237
238    #[test]
239    fn deserialize_good() {
240        let deserialized: Person = serde_json::from_value(example_person_json())
241            .expect("value must be deserializable as Person");
242        assert_eq!(deserialized, example_person());
243    }
244
245    #[test]
246    fn deserialize_bad() {
247        assert!(serde_json::from_value::<Person>(json!("xyzabcd")).is_err());
248        assert!(serde_json::from_value::<Person>(json!(true)).is_err());
249        assert!(serde_json::from_value::<Person>(json!(123)).is_err());
250    }
251}