1use url::Url;
7
8use crate::{
9 date::Date, namespace::FileNamespaceUrl, AgendaItemId, DateTime, FileId, Keyword, MeetingId,
10 Name, PaperId, Sha1Sum, Sha512Sum,
11};
12
13#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct File {
16 pub id: FileId,
17
18 #[serde(rename = "type")]
19 pub namespace: FileNamespaceUrl,
20
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub name: Option<Name>,
23
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub file_name: Option<Name>,
26
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub mime_type: Option<String>,
29
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub date: Option<Date>,
32
33 #[serde(default, skip_serializing_if = "Option::is_none")]
34 pub size: Option<u64>,
35
36 #[serde(default, skip_serializing_if = "Option::is_none")]
37 pub sha1_checksum: Option<Sha1Sum>,
38
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub sha512_checksum: Option<Sha512Sum>,
41
42 #[serde(default, skip_serializing_if = "Option::is_none")]
43 pub text: Option<String>,
44
45 pub access_url: Url,
46
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub download_url: Option<Url>,
49
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub external_service_url: Option<Url>,
52
53 #[serde(default, skip_serializing_if = "Option::is_none")]
54 pub master_file: Option<FileId>,
55
56 #[serde(default, skip_serializing_if = "Vec::is_empty")]
57 pub derivative_file: Vec<FileId>,
58
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub file_license: Option<Url>,
61
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub meeting: Vec<MeetingId>,
64
65 #[serde(default, skip_serializing_if = "Vec::is_empty")]
66 pub agenda_item: Vec<AgendaItemId>,
67
68 #[serde(default, skip_serializing_if = "Vec::is_empty")]
69 pub paper: Vec<PaperId>,
70
71 #[serde(default, skip_serializing_if = "Option::is_none")]
72 pub license: Option<Url>,
73
74 #[serde(default, skip_serializing_if = "Vec::is_empty")]
75 pub keyword: Vec<Keyword>,
76
77 pub created: DateTime,
78
79 pub modified: DateTime,
80
81 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub web: Option<Url>,
83
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 pub deleted: Option<bool>,
86}
87
88#[cfg(test)]
89mod serde_tests {
90 use super::File;
91 use crate::{namespace::FileNamespaceUrl, Sha1Sum};
92
93 use pretty_assertions::assert_eq;
94 use serde_json::json;
95 use time::macros::{date, datetime};
96
97 fn example_file() -> File {
98 File {
99 id: "https://oparl.example.org/files/57737"
100 .parse()
101 .expect("value must be parseable as id"),
102 namespace: FileNamespaceUrl::Identifier,
103 file_name: Some("anlage_1_zur_anfrage.pdf".into()),
104 name: Some("Anlage 1 zur Anfrage".into()),
105 mime_type: Some("application/pdf".into()),
106 date: Some(date!(2013 - 01 - 04).into()),
107 size: Some(82930),
108 sha1_checksum: Some(Sha1Sum::from([
109 0xd7, 0x49, 0x75, 0x1a, 0xf4, 0x4a, 0x32, 0xc8, 0x18, 0xb9, 0xb1, 0xe1, 0x51, 0x52,
110 0x51, 0xc6, 0x77, 0x34, 0xf5, 0xd2,
111 ])),
112 sha512_checksum: None,
113 text: None,
114 access_url: "https://oparl.example.org/files/57737.pdf"
115 .parse()
116 .expect("value must be parseable as url"),
117 download_url: Some(
118 "https://oparl.example.org/files/download/57737.pdf"
119 .parse()
120 .expect("value must be parseable as url"),
121 ),
122 external_service_url: None,
123 master_file: None,
124 derivative_file: vec!["https://oparl.example.org/files/57739"
125 .parse()
126 .expect("value must be parseable as url")],
127 file_license: Some(
128 "http://www.opendefinition.org/licenses/cc-by"
129 .parse()
130 .expect("value must be parseable as url"),
131 ),
132 meeting: vec![],
133 agenda_item: vec![],
134 paper: vec![],
135 license: None,
136 keyword: vec![],
137 created: datetime!(2013-01-04 07:54:13 +01:00).into(),
138 modified: datetime!(2013-01-04 07:54:13 +01:00).into(),
139 web: None,
140 deleted: None,
141 }
142 }
143
144 fn example_file_json() -> serde_json::Value {
145 json!({
146 "id": "https://oparl.example.org/files/57737",
147 "type": "https://schema.oparl.org/1.1/File",
148 "name": "Anlage 1 zur Anfrage",
149 "fileName": "anlage_1_zur_anfrage.pdf",
150 "mimeType": "application/pdf",
151 "date": "2013-01-04",
152 "size": 82930,
153 "sha1Checksum": "d749751af44a32c818b9b1e1515251c67734f5d2",
154 "accessUrl": "https://oparl.example.org/files/57737.pdf",
155 "downloadUrl": "https://oparl.example.org/files/download/57737.pdf",
156 "derivativeFile": [
157 "https://oparl.example.org/files/57739"
158 ],
159 "fileLicense": "http://www.opendefinition.org/licenses/cc-by",
160 "created": "2013-01-04T07:54:13+01:00",
161 "modified": "2013-01-04T07:54:13+01:00"
162 })
163 }
164
165 #[test]
166 fn serialize() {
167 assert_eq!(json!(example_file()), example_file_json());
168 }
169
170 #[test]
171 fn deserialize_good() {
172 let deserialized: File = serde_json::from_value(example_file_json())
173 .expect("value must be deserializable as File");
174 assert_eq!(deserialized, example_file());
175 }
176
177 #[test]
178 fn deserialize_bad() {
179 assert!(serde_json::from_value::<File>(json!("xyzabcd")).is_err());
180 assert!(serde_json::from_value::<File>(json!(true)).is_err());
181 assert!(serde_json::from_value::<File>(json!(123)).is_err());
182 }
183}