1use crate::{asn, correspondent, document_type, saved_view, storage_path, tag};
6use chrono::{DateTime, NaiveDate, Utc};
7use reqwest::Url;
8use serde::Deserialize;
9
10#[derive(Debug, Deserialize, Copy, Clone)]
11pub struct Id(u64);
12
13impl From<u64> for Id {
14 fn from(value: u64) -> Self {
15 Self(value)
16 }
17}
18impl From<Id> for u64 {
19 fn from(value: Id) -> Self {
20 value.0
21 }
22}
23impl ToString for Id {
24 fn to_string(&self) -> String {
25 self.0.to_string()
26 }
27}
28
29#[derive(Debug, Deserialize)]
30pub struct Document {
31 pub id: Id,
32 pub correspondent: Option<correspondent::Id>,
33 pub document_type: Option<correspondent::Id>,
34 pub storage_path: Option<storage_path::Id>,
35 pub title: String,
36 pub content: String,
37 pub tags: Vec<tag::Id>,
38 pub created: DateTime<Utc>,
39 pub created_date: NaiveDate,
40 pub modified: DateTime<Utc>,
41 pub added: DateTime<Utc>,
42 pub archive_serial_number: Option<asn::ASN>,
43 pub original_file_name: Option<String>,
44 pub archived_file_name: Option<String>,
45}
46
47#[derive(Debug, Default)]
51pub struct Filter {
52 pub query: Option<String>,
54 pub title_content_contains: Option<String>,
55 pub is_in_inbox: Option<bool>,
56 pub title_starts_with: Option<String>,
57 pub title_ends_with: Option<String>,
58 pub title_contains: Option<String>,
59 pub title_is: Option<String>,
60 pub content_starts_with: Option<String>,
61 pub content_ends_with: Option<String>,
62 pub content_contains: Option<String>,
63 pub content_is: Option<String>,
64 pub archive_serial_number_is: Option<asn::ASN>,
65 pub archive_serial_numer_gt: Option<asn::ASN>,
66 pub archive_serial_number_gte: Option<asn::ASN>,
67 pub archive_serial_numer_lt: Option<asn::ASN>,
68 pub archive_serial_number_lte: Option<asn::ASN>,
69 pub archive_serial_number_isnull: Option<bool>,
70 pub created_year: Option<usize>,
71 pub created_month: Option<usize>,
72 pub created_day: Option<usize>,
73 pub created_date_gt: Option<NaiveDate>,
74 pub created_gt: Option<DateTime<Utc>>,
75 pub created_date_lt: Option<NaiveDate>,
76 pub created_lt: Option<DateTime<Utc>>,
77 pub added_year: Option<usize>,
78 pub added_month: Option<usize>,
79 pub added_day: Option<usize>,
80 pub added_date_gt: Option<NaiveDate>,
81 pub added_gt: Option<DateTime<Utc>>,
82 pub added_date_lt: Option<NaiveDate>,
83 pub added_lt: Option<DateTime<Utc>>,
84 pub modified_year: Option<usize>,
85 pub modified_month: Option<usize>,
86 pub modified_day: Option<usize>,
87 pub modified_date_gt: Option<NaiveDate>,
88 pub modified_gt: Option<DateTime<Utc>>,
89 pub modified_date_lt: Option<NaiveDate>,
90 pub modified_lt: Option<DateTime<Utc>>,
91 pub correspondent_isnull: Option<bool>,
92 pub correspondent_id_in: Option<Vec<correspondent::Id>>,
93 pub correspondent_id: Option<correspondent::Id>,
94 pub correspondent_name_starts_with: Option<String>,
95 pub correspondent_name_ends_with: Option<String>,
96 pub correspondent_name_contains: Option<String>,
97 pub correspondent_name_is: Option<String>,
98 pub is_tagged: Option<bool>,
99 pub tag_id_all: Vec<tag::Id>,
101 pub tag_id_none: Vec<tag::Id>,
103 pub tag_id_in: Vec<tag::Id>,
105 pub tag_id: Option<tag::Id>,
107 pub tag_name_starts_with: Option<String>,
108 pub tag_name_ends_with: Option<String>,
109 pub tag_name_contains: Option<String>,
110 pub tag_name_is: Option<String>,
111 pub document_type_isnull: Option<bool>,
112 pub document_type_id_in: Vec<document_type::Id>,
113 pub document_type_id: Option<document_type::Id>,
114 pub document_type_name_starts_with: Option<String>,
115 pub document_type_name_ends_with: Option<String>,
116 pub document_type_name_contains: Option<String>,
117 pub document_type_name_is: Option<String>,
118 pub storage_path_isnull: Option<bool>,
119 pub storage_path_id_in: Vec<storage_path::Id>,
120 pub storage_path_id: Option<storage_path::Id>,
121 pub storage_path_name_starts_with: Option<String>,
122 pub storage_path_name_ends_with: Option<String>,
123 pub storage_path_name_contains: Option<String>,
124 pub storage_path_name_is: Option<String>,
125 pub more_like: Option<Id>,
126}
127
128impl Filter {
129 #[rustfmt::skip]
130 pub(crate) fn insert_query(self, url: &mut Url) {
132 if let Some(more_like) = self.more_like {
133 url.query_pairs_mut().append_pair("more_like_id", &more_like.to_string());
134 }
135 if let Some(query) = self.query {
136 url.query_pairs_mut().append_pair("query", &query.to_string());
137 }
138 if let Some(is_tagged) = self.is_tagged {
139 url.query_pairs_mut().append_pair("is_tagged", &is_tagged.to_string());
140 }
141
142 url.query_pairs_mut()
143 .append_pair("title_content", &self.title_content_contains.unwrap_or_default())
144 .append_pair("is_in_inbox", &if let Some(is_in_inbox) = self.is_in_inbox { is_in_inbox.to_string() } else { String::default() })
145 .append_pair("title__istartswith", &self.title_starts_with.unwrap_or_default())
146 .append_pair("title__iendswith", &self.title_ends_with.unwrap_or_default())
147 .append_pair("title__icontains", &self.title_contains.unwrap_or_default())
148 .append_pair("title__iexact", &self.title_is.unwrap_or_default())
149 .append_pair("content__istartswith", &self.content_starts_with.unwrap_or_default())
150 .append_pair("content__iendswith", &self.content_ends_with.unwrap_or_default())
151 .append_pair("content__icontains", &self.content_contains.unwrap_or_default())
152 .append_pair("content__iexact", &self.content_is.unwrap_or_default())
153 .append_pair("archive_serial_number", &self.archive_serial_number_is.map(|asn| asn.to_string()).unwrap_or_default())
154 .append_pair("archive_serial_number__gt", &self.archive_serial_numer_gt.map(|asn| asn.to_string()).unwrap_or_default())
155 .append_pair("archive_serial_number__gte", &self.archive_serial_number_gte.map(|asn| asn.to_string()).unwrap_or_default())
156 .append_pair("archive_serial_number__lt", &self.archive_serial_numer_lt.map(|asn| asn.to_string()).unwrap_or_default())
157 .append_pair("archive_serial_number__lte", &self.archive_serial_number_lte.map(|asn| asn.to_string()).unwrap_or_default())
158 .append_pair("archive_serial_number__isnull", &if let Some(isnull) = self.archive_serial_number_isnull { isnull.to_string() } else { String::default() })
159 .append_pair("created__year", &self.created_year.map(|year| year.to_string()).unwrap_or_default())
160 .append_pair("created__month", &self.created_year.map(|month| month.to_string()).unwrap_or_default())
161 .append_pair("created__day", &self.created_year.map(|day| day.to_string()).unwrap_or_default())
162 .append_pair("created__date__gt", &self.created_date_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
163 .append_pair("created__gt", &self.created_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
164 .append_pair("created__date__lt", &self.created_date_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
165 .append_pair("created__lt", &self.created_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
166 .append_pair("added__year", &self.added_year.map(|year| year.to_string()).unwrap_or_default())
167 .append_pair("added__month", &self.added_year.map(|month| month.to_string()).unwrap_or_default())
168 .append_pair("added__day", &self.added_year.map(|day| day.to_string()).unwrap_or_default())
169 .append_pair("added__date__gt", &self.added_date_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
170 .append_pair("added__gt", &self.added_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
171 .append_pair("added__date__lt", &self.added_date_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
172 .append_pair("added__lt", &self.added_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
173 .append_pair("modified__year", &self.modified_year.map(|year| year.to_string()).unwrap_or_default())
174 .append_pair("modified__month", &self.modified_year.map(|month| month.to_string()).unwrap_or_default())
175 .append_pair("modified__day", &self.modified_year.map(|day| day.to_string()).unwrap_or_default())
176 .append_pair("modified__date__gt", &self.modified_date_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
177 .append_pair("modified__gt", &self.modified_gt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
178 .append_pair("modified__date__lt", &self.modified_date_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
179 .append_pair("modified__lt", &self.modified_lt.map(|d| d.format("%Y-%m-%dT%H:%M:%SZ").to_string()).unwrap_or_default())
180 .append_pair("correspondent__isnull",&if let Some(isnull) = self.correspondent_isnull { isnull.to_string() } else { String::default() })
181 .append_pair("correspondent__id__in", &self.correspondent_id_in.map(|ids| ids.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(",")).unwrap_or_default())
182 .append_pair("correspondent__id", &self.correspondent_id.map(|id| id.to_string()).unwrap_or_default())
183 .append_pair("correspondent__name__istartswith", &self.correspondent_name_starts_with.unwrap_or_default())
184 .append_pair("correspondent__name__iendswith", &self.correspondent_name_ends_with.unwrap_or_default())
185 .append_pair("correspondent__name__icontains", &self.correspondent_name_contains.unwrap_or_default())
186 .append_pair("correspondent__name__iexact", &self.correspondent_name_is.unwrap_or_default())
187 .append_pair("tags__id__in", &self.tag_id_in.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(","))
188 .append_pair("tags__id__all", &self.tag_id_all.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(","))
189 .append_pair("tags__id__none", &self.tag_id_none.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(","))
190 .append_pair("tags__id", &self.tag_id.map(|id| id.to_string()).unwrap_or_default())
191 .append_pair("tags__name__istartswith", &self.tag_name_starts_with.unwrap_or_default())
192 .append_pair("tags__name__iendswith", &self.tag_name_ends_with.unwrap_or_default())
193 .append_pair("tags__name__icontains", &self.tag_name_contains.unwrap_or_default())
194 .append_pair("tags__name__iexact", &self.tag_name_is.unwrap_or_default())
195 .append_pair("document_type__isnull",&if let Some(isnull) = self.document_type_isnull { isnull.to_string() } else { String::default() })
196 .append_pair("document_type__id__in", &self.document_type_id_in.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(","))
197 .append_pair("document_type__id", &self.document_type_id.map(|id| id.to_string()).unwrap_or_default())
198 .append_pair("document_type__name__istartswith", &self.document_type_name_starts_with.unwrap_or_default())
199 .append_pair("document_type__name__iendswith", &self.document_type_name_ends_with.unwrap_or_default())
200 .append_pair("document_type__name__icontains", &self.document_type_name_contains.unwrap_or_default())
201 .append_pair("document_type__name__iexact", &self.document_type_name_is.unwrap_or_default())
202 .append_pair("storage_path__isnull",&if let Some(isnull) = self.storage_path_isnull { isnull.to_string() } else { String::default() })
203 .append_pair("storage_path__id__in", &self.storage_path_id_in.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(","))
204 .append_pair("storage_path__id", &self.storage_path_id.map(|id| id.to_string()).unwrap_or_default())
205 .append_pair("storage_path__name__istartswith", &self.storage_path_name_starts_with.unwrap_or_default())
206 .append_pair("storage_path__name__iendswith", &self.storage_path_name_ends_with.unwrap_or_default())
207 .append_pair("storage_path__name__icontains", &self.storage_path_name_contains.unwrap_or_default())
208 .append_pair("storage_path__name__iexact", &self.storage_path_name_is.unwrap_or_default());
209 }
210
211 pub fn from_filter_rules(filter_rules: &[saved_view::FilterRule]) -> Self {
213 let mut filter = Self::default();
214 for rule in filter_rules {
215 match rule {
216 saved_view::FilterRule::TitleContains(v) => {
217 filter.title_contains = v.clone();
218 }
219 saved_view::FilterRule::ContentContains(v) => {
220 filter.content_contains = v.clone();
221 }
222 saved_view::FilterRule::ASNIs(Some(v)) => {
223 filter.archive_serial_number_is = Some(v.clone());
224 }
225 saved_view::FilterRule::ASNIs(None) => {
226 filter.archive_serial_number_isnull = Some(true);
227 }
228 saved_view::FilterRule::CorrespondentIs(Some(v)) => {
229 filter.correspondent_id = Some(v.clone());
230 }
231 saved_view::FilterRule::CorrespondentIs(None) => {
232 filter.correspondent_isnull = Some(true);
233 }
234 saved_view::FilterRule::DocumentTypeIs(Some(v)) => {
235 filter.document_type_id = Some(v.clone());
236 }
237 saved_view::FilterRule::DocumentTypeIs(None) => {
238 filter.document_type_isnull = Some(true);
239 }
240 saved_view::FilterRule::IsInInbox(v) => {
241 filter.is_in_inbox = v.clone();
242 }
243 saved_view::FilterRule::HasTag(Some(tag)) => {
244 filter.tag_id_all.push(tag.clone());
245 }
246 saved_view::FilterRule::HasAnyTag(v) => {
247 filter.is_tagged = v.clone();
248 }
249 saved_view::FilterRule::CreatedBefore(v) => {
250 filter.created_lt = v.clone();
251 }
252 saved_view::FilterRule::CreatedAfter(v) => {
253 filter.created_gt = v.clone();
254 }
255 saved_view::FilterRule::CreatedYearIs(v) => {
256 filter.created_year = v.clone();
257 }
258 saved_view::FilterRule::CreatedMountIs(v) => {
259 filter.created_month = v.clone();
260 }
261 saved_view::FilterRule::CreatedDayIs(v) => {
262 filter.created_day = v.clone();
263 }
264 saved_view::FilterRule::AddedBefore(v) => {
265 filter.added_lt = v.clone();
266 }
267 saved_view::FilterRule::AddedAfter(v) => {
268 filter.added_gt = v.clone();
269 }
270 saved_view::FilterRule::ModifiedBefore(v) => {
271 filter.modified_lt = v.clone();
272 }
273 saved_view::FilterRule::ModifiedAfter(v) => {
274 filter.modified_gt = v.clone();
275 }
276 saved_view::FilterRule::DontHaveTag(Some(tag)) => {
277 filter.tag_id_none.push(tag.clone());
278 }
279 saved_view::FilterRule::DontHaveASN(v) => {
280 filter.archive_serial_number_isnull = v.clone();
281 }
282 saved_view::FilterRule::TitleOrContentContains(v) => {
283 filter.title_content_contains = v.clone();
284 }
285 saved_view::FilterRule::FullTextQuery(v) => {
286 filter.query = v.clone();
287 }
288 saved_view::FilterRule::MoreLikeThis(v) => {
289 filter.more_like = v.clone();
290 }
291 saved_view::FilterRule::HasTagIn(Some(tag)) => {
292 filter.tag_id_in.push(tag.clone());
293 }
294 saved_view::FilterRule::ASNGreaterThan(v) => {
295 filter.archive_serial_numer_gt = v.clone();
296 }
297 saved_view::FilterRule::ASNLessThan(v) => {
298 filter.archive_serial_numer_lt = v.clone();
299 }
300 saved_view::FilterRule::StoragePathIs(Some(v)) => {
301 filter.storage_path_id = Some(v.clone());
302 }
303 saved_view::FilterRule::StoragePathIs(None) => {
304 filter.storage_path_isnull = Some(true);
305 }
306 r => {
307 println!("Ignore {:?}", r)
308 }
309 }
310 }
311 filter
312 }
313}
314
315