1#![cfg_attr(features = "extra-derive", deny(missing_debug_implementations))]
4#![deny(rustdoc::broken_intra_doc_links)]
5#![cfg_attr(test, deny(warnings))]
6
7use serde::{Deserialize, Serialize};
16use time::Date;
17
18#[cfg(feature = "extra-derive")]
19use thiserror::Error;
20
21#[cfg(feature = "entity-conversions")]
22mod conv;
23
24type RevisionValue = u64;
25type Url = String;
26
27#[derive(Serialize, Deserialize)]
28#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Copy, Eq, PartialEq))]
29pub struct UnixTimeMillis(i64);
30
31#[derive(Serialize, Deserialize)]
32#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Copy, Eq, PartialEq))]
33pub struct UnixTimeSeconds(i64);
34
35impl From<time::OffsetDateTime> for UnixTimeSeconds {
36 fn from(from: time::OffsetDateTime) -> Self {
37 Self(from.unix_timestamp())
38 }
39}
40
41impl TryFrom<UnixTimeSeconds> for time::OffsetDateTime {
42 type Error = time::error::ComponentRange;
43 fn try_from(from: UnixTimeSeconds) -> Result<Self, Self::Error> {
44 Self::from_unix_timestamp(from.0)
45 }
46}
47
48#[rustfmt::skip]
49#[derive(Serialize, Deserialize)]
50#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq))]
51pub struct Entry {
52 pub id : String,
53 pub created : i64,
54 pub version : u64,
55 pub title : String,
56 pub description : String,
57 pub lat : f64,
58 pub lng : f64,
59 pub street : Option<String>,
60 pub zip : Option<String>,
61 pub city : Option<String>,
62 pub country : Option<String>,
63 pub state : Option<String>,
64 pub contact_name : Option<String>,
65 pub email : Option<String>,
66 pub telephone : Option<String>,
67 pub homepage : Option<Url>,
68 pub opening_hours : Option<String>,
69 pub founded_on : Option<Date>,
70 pub categories : Vec<String>,
71 pub tags : Vec<String>,
72 pub ratings : Vec<String>,
73 pub license : Option<String>,
74 pub image_url : Option<Url>,
75 pub image_link_url : Option<Url>,
76
77 #[serde(rename = "custom", skip_serializing_if = "Vec::is_empty", default = "Default::default")]
78 pub custom_links : Vec<CustomLink>,
79}
80
81#[rustfmt::skip]
82#[derive(Serialize, Deserialize)]
83#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
84pub struct CustomLink {
85 pub url : String,
86 pub title : Option<String>,
87 pub description : Option<String>,
88}
89
90#[rustfmt::skip]
91#[derive(Serialize, Deserialize)]
92#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq))]
93pub struct NewPlace {
94 pub title : String,
95 pub description : String,
96 pub lat : f64,
97 pub lng : f64,
98 pub street : Option<String>,
99 pub zip : Option<String>,
100 pub city : Option<String>,
101 pub country : Option<String>,
102 pub state : Option<String>,
103 pub contact_name : Option<String>,
104 pub email : Option<String>,
105 pub telephone : Option<String>,
106 pub homepage : Option<String>,
107 pub opening_hours : Option<String>,
108 pub founded_on : Option<Date>,
109
110 #[serde(default = "Default::default")]
111 pub categories : Vec<String>,
112
113 #[serde(default = "Default::default")]
114 pub tags : Vec<String>,
115
116 #[serde(default = "Default::default")]
117 pub license : String,
118
119 pub image_url : Option<String>,
120 pub image_link_url : Option<String>,
121
122 #[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
123 pub links : Vec<CustomLink>,
124}
125
126#[rustfmt::skip]
127#[derive(Serialize, Deserialize)]
128#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq))]
129pub struct UpdatePlace {
130 pub version : u64,
131 pub title : String,
132 pub description : String,
133 pub lat : f64,
134 pub lng : f64,
135 pub street : Option<String>,
136 pub zip : Option<String>,
137 pub city : Option<String>,
138 pub country : Option<String>,
139 pub state : Option<String>,
140 pub contact_name : Option<String>,
141 pub email : Option<String>,
142 pub telephone : Option<String>,
143 pub homepage : Option<String>,
144 pub opening_hours : Option<String>,
145 pub founded_on : Option<Date>,
146 pub categories : Vec<String>,
147 pub tags : Vec<String>,
148 pub image_url : Option<String>,
149 pub image_link_url : Option<String>,
150
151 #[serde(skip_serializing_if = "Vec::is_empty", default = "Default::default")]
152 pub links : Vec<CustomLink>,
153}
154
155#[derive(Serialize, Deserialize)]
156#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
157pub struct NewEvent {
158 pub title: String,
159 pub description: Option<String>,
160 pub start: i64,
161 pub end: Option<i64>,
162 pub lat: Option<f64>,
163 pub lng: Option<f64>,
164 pub street: Option<String>,
165 pub zip: Option<String>,
166 pub city: Option<String>,
167 pub country: Option<String>,
168 pub state: Option<String>,
169 pub email: Option<String>,
170 pub telephone: Option<String>,
171 pub homepage: Option<String>,
172 pub tags: Option<Vec<String>>,
173 pub created_by: Option<String>,
174 pub registration: Option<String>,
175 pub organizer: Option<String>,
176 pub image_url: Option<String>,
177 pub image_link_url: Option<String>,
178}
179
180#[derive(Serialize, Deserialize)]
181#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
182pub struct Event {
183 pub id: String,
184 pub title: String,
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub description: Option<String>,
187 pub start: UnixTimeSeconds,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub end: Option<UnixTimeSeconds>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub lat: Option<f64>,
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub lng: Option<f64>,
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub street: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub zip: Option<String>,
198 #[serde(skip_serializing_if = "Option::is_none")]
199 pub city: Option<String>,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub country: Option<String>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub state: Option<String>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub email: Option<String>,
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub telephone: Option<String>,
208 #[serde(skip_serializing_if = "Option::is_none")]
209 pub homepage: Option<String>,
210 pub tags: Vec<String>,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub registration: Option<String>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub organizer: Option<String>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub image_url: Option<String>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub image_link_url: Option<String>,
219}
220
221#[derive(Serialize, Deserialize)]
222#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Copy, PartialEq))]
223pub struct Coordinate {
224 pub lat: f64,
225 pub lng: f64,
226}
227
228#[derive(Serialize, Deserialize)]
229#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
230pub struct NewUser {
231 pub email: String,
232 pub password: String,
233}
234
235#[derive(Serialize, Deserialize)]
236#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq))]
237pub struct User {
238 pub email: String,
239 pub email_confirmed: bool,
240 pub role: UserRole,
241}
242
243#[derive(Serialize, Deserialize)]
244#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Copy))]
245pub struct RatingValue(i8);
246
247#[derive(Serialize, Deserialize)]
248#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Copy))]
249pub struct AvgRatingValue(f64);
250
251impl From<f64> for AvgRatingValue {
252 fn from(v: f64) -> Self {
253 Self(v)
254 }
255}
256
257impl From<AvgRatingValue> for f64 {
258 fn from(from: AvgRatingValue) -> Self {
259 from.0
260 }
261}
262
263impl From<i8> for RatingValue {
264 fn from(from: i8) -> Self {
265 Self(from)
266 }
267}
268
269#[derive(Serialize, Deserialize)]
270#[cfg_attr(
271 feature = "extra-derive",
272 derive(Debug, Clone, Copy, PartialEq, Eq, Hash)
273)]
274#[serde(rename_all = "snake_case")]
275pub enum RatingContext {
276 Diversity,
277 Renewable,
278 Fairness,
279 Humanity,
280 Transparency,
281 Solidarity,
282}
283
284#[derive(Serialize, Deserialize)]
285#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
286pub struct EntrySearchRatings {
287 pub total: AvgRatingValue,
288 pub diversity: AvgRatingValue,
289 pub fairness: AvgRatingValue,
290 pub humanity: AvgRatingValue,
291 pub renewable: AvgRatingValue,
292 pub solidarity: AvgRatingValue,
293 pub transparency: AvgRatingValue,
294}
295
296#[derive(Serialize, Deserialize)]
297#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
298pub struct Comment {
299 pub id: String,
300 pub created: i64,
301 pub text: String,
302}
303
304#[derive(Serialize, Deserialize)]
305#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
306pub struct Category {
307 pub id: String,
308 pub name: String,
309}
310
311#[derive(Serialize, Deserialize)]
312#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
313pub struct PlaceSearchResult {
314 pub id: String,
315 pub status: Option<ReviewStatus>,
316 pub lat: f64,
317 pub lng: f64,
318 pub title: String,
319 pub description: String,
320 pub categories: Vec<String>,
321 pub tags: Vec<String>,
322 pub ratings: EntrySearchRatings,
323}
324
325#[derive(Serialize, Deserialize)]
326#[cfg_attr(
327 feature = "extra-derive",
328 derive(Debug, Clone, Copy, PartialEq, Eq, Hash)
329)]
330#[serde(rename_all = "lowercase")]
331pub enum ReviewStatus {
332 Archived,
333 Confirmed,
334 Created,
335 Rejected,
336}
337
338#[derive(Serialize, Deserialize)]
339#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
340pub struct Review {
341 pub status: ReviewStatus,
342 pub comment: Option<String>,
343}
344
345#[derive(Serialize, Deserialize)]
346#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
347pub struct SearchResponse {
348 pub visible: Vec<PlaceSearchResult>,
349 pub invisible: Vec<PlaceSearchResult>,
350}
351
352#[derive(Serialize, Deserialize)]
353#[cfg_attr(
354 feature = "extra-derive",
355 derive(Debug, Clone, Copy, PartialEq, Eq, Hash)
356)]
357#[serde(rename_all = "lowercase")]
358pub enum UserRole {
359 Guest,
360 User,
361 Scout,
362 Admin,
363}
364
365#[derive(Serialize, Deserialize)]
366#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq))]
367pub struct BboxSubscription {
368 pub id: String,
369 pub south_west_lat: f64,
370 pub south_west_lng: f64,
371 pub north_east_lat: f64,
372 pub north_east_lng: f64,
373}
374
375#[derive(Serialize, Deserialize)]
376#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
377pub struct MapBbox {
378 pub sw: MapPoint,
379 pub ne: MapPoint,
380}
381
382#[derive(Serialize, Deserialize)]
383#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
384pub struct MapPoint {
385 pub lat: f64,
386 pub lng: f64,
387}
388
389#[derive(Serialize, Deserialize)]
390#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
391pub struct RequestPasswordReset {
392 pub email: String,
393}
394
395#[derive(Serialize, Deserialize)]
396#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
397pub struct ResetPassword {
398 pub token: String,
399 pub new_password: String,
400}
401
402#[derive(Serialize, Deserialize)]
403#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, Default))]
404pub struct Credentials {
405 pub email: String,
406 pub password: String,
407}
408
409#[derive(Serialize, Deserialize)]
410#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
411pub struct ConfirmEmailAddress {
412 pub token: String,
413}
414
415#[derive(Serialize, Deserialize)]
416#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
417pub struct TagFrequency(pub String, pub u64);
418
419#[derive(Serialize, Deserialize)]
420#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
421pub struct Rating {
422 pub id: String,
423 pub title: String,
424 pub created: i64,
425 pub value: RatingValue,
426 pub context: RatingContext,
427 pub comments: Vec<Comment>,
428 pub source: String,
429}
430
431#[derive(Serialize, Deserialize)]
432#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
433pub struct NewPlaceRating {
434 pub entry: String,
435 pub title: String,
436 pub value: RatingValue,
437 pub context: RatingContext,
438 pub comment: String,
439 pub source: Option<String>,
440 pub user: Option<String>,
441}
442
443#[derive(Serialize, Deserialize)]
444#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
445pub struct PendingClearanceForPlace {
446 pub place_id: String,
447 pub created_at: UnixTimeMillis,
448 pub last_cleared_revision: Option<RevisionValue>,
449}
450
451#[derive(Serialize, Deserialize)]
452#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
453pub struct ClearanceForPlace {
454 pub place_id: String,
455 pub cleared_revision: Option<RevisionValue>,
456}
457
458#[derive(Serialize, Deserialize)]
459#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
460pub struct ResultCount {
461 pub count: u64,
462}
463
464#[derive(Serialize, Deserialize)]
465#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq))]
466pub struct LatLonDegrees(f64, f64);
467
468#[derive(Serialize, Deserialize, Default)]
469#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq, Eq))]
470pub struct Address {
471 #[serde(skip_serializing_if = "Option::is_none")]
472 pub street: Option<String>,
473
474 #[serde(skip_serializing_if = "Option::is_none")]
475 pub zip: Option<String>,
476
477 #[serde(skip_serializing_if = "Option::is_none")]
478 pub city: Option<String>,
479
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub country: Option<String>,
482
483 #[serde(skip_serializing_if = "Option::is_none")]
484 pub state: Option<String>,
485}
486
487impl Address {
488 pub fn is_empty(&self) -> bool {
489 self.street.is_none()
490 && self.zip.is_none()
491 && self.city.is_none()
492 && self.country.is_none()
493 && self.state.is_none()
494 }
495}
496
497#[derive(Serialize, Deserialize)]
498#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq))]
499pub struct Location {
500 #[serde(rename = "deg")]
501 pub latlon: LatLonDegrees,
502
503 #[serde(
504 rename = "adr",
505 skip_serializing_if = "Address::is_empty",
506 default = "Default::default"
507 )]
508 pub address: Address,
509}
510
511#[derive(Serialize, Deserialize, Default)]
512#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq, Eq))]
513pub struct Contact {
514 #[serde(skip_serializing_if = "Option::is_none")]
515 pub name: Option<String>,
516
517 #[serde(skip_serializing_if = "Option::is_none")]
518 pub email: Option<String>,
519
520 #[serde(skip_serializing_if = "Option::is_none")]
521 pub phone: Option<String>,
522}
523
524impl Contact {
525 pub fn is_empty(&self) -> bool {
526 self.email.is_none() && self.phone.is_none()
527 }
528}
529
530#[derive(Serialize, Deserialize, Default)]
531#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq, Eq))]
532pub struct Links {
533 #[serde(rename = "www", skip_serializing_if = "Option::is_none")]
534 pub homepage: Option<Url>,
535
536 #[serde(rename = "img", skip_serializing_if = "Option::is_none")]
537 pub image: Option<Url>,
538
539 #[serde(rename = "img_href", skip_serializing_if = "Option::is_none")]
540 pub image_href: Option<Url>,
541
542 #[serde(
543 rename = "custom",
544 skip_serializing_if = "Vec::is_empty",
545 default = "Default::default"
546 )]
547 pub custom: Vec<CustomLink>,
548}
549
550impl Links {
551 pub fn is_empty(&self) -> bool {
552 let Self {
553 homepage,
554 image,
555 image_href,
556 custom,
557 } = self;
558 homepage.is_none() && image.is_none() && image_href.is_none() && custom.is_empty()
559 }
560}
561
562#[derive(Serialize, Deserialize)]
563#[cfg_attr(feature = "extra-derive", derive(Debug, PartialEq, Eq))]
564pub struct Activity {
565 pub at: UnixTimeMillis,
566
567 #[serde(skip_serializing_if = "Option::is_none")]
568 pub by: Option<String>,
569}
570
571#[derive(Serialize, Deserialize)]
572#[cfg_attr(feature = "extra-derive", derive(Debug))]
573pub struct PlaceRoot {
574 pub id: String,
575
576 #[serde(rename = "lic")]
577 pub license: String,
578}
579
580#[derive(Serialize, Deserialize)]
581#[cfg_attr(feature = "extra-derive", derive(Debug))]
582pub struct PlaceRevision {
583 #[serde(rename = "rev")]
584 pub revision: u64,
585
586 pub created: Activity,
587
588 #[serde(rename = "tit")]
589 pub title: String,
590
591 #[serde(rename = "dsc")]
592 pub description: String,
593
594 #[serde(rename = "loc")]
595 pub location: Location,
596
597 #[serde(
598 rename = "cnt",
599 skip_serializing_if = "Contact::is_empty",
600 default = "Default::default"
601 )]
602 pub contact: Contact,
603
604 #[serde(rename = "hrs", skip_serializing_if = "Option::is_none")]
605 pub opening_hours: Option<String>,
606
607 #[serde(rename = "fnd", skip_serializing_if = "Option::is_none")]
608 pub founded_on: Option<Date>,
609
610 #[serde(
611 rename = "lnk",
612 skip_serializing_if = "Links::is_empty",
613 default = "Default::default"
614 )]
615 pub links: Links,
616
617 #[serde(
618 rename = "tag",
619 skip_serializing_if = "Vec::is_empty",
620 default = "Default::default"
621 )]
622 pub tags: Vec<String>,
623}
624
625#[derive(Serialize, Deserialize)]
626#[cfg_attr(feature = "extra-derive", derive(Debug))]
627pub struct PlaceHistory {
628 pub place: PlaceRoot,
629 pub revisions: Vec<(PlaceRevision, Vec<ReviewStatusLog>)>,
630}
631
632#[derive(Serialize, Deserialize)]
633#[cfg_attr(feature = "extra-derive", derive(Debug))]
634pub struct ActivityLog {
635 pub at: UnixTimeMillis,
636
637 #[serde(skip_serializing_if = "Option::is_none")]
638 pub by: Option<String>,
639
640 #[serde(skip_serializing_if = "Option::is_none")]
641 pub ctx: Option<String>,
642
643 #[serde(skip_serializing_if = "Option::is_none")]
644 pub comment: Option<String>,
645}
646
647#[derive(Serialize, Deserialize)]
648#[cfg_attr(feature = "extra-derive", derive(Debug))]
649pub struct ReviewStatusLog {
650 pub rev: u64,
651 pub act: ActivityLog,
652 pub status: ReviewStatus,
653}
654
655#[derive(Serialize, Deserialize)]
656#[cfg_attr(feature = "extra-derive", derive(Debug))]
657pub struct ReviewWithToken {
658 pub token: String,
659 pub status: ReviewStatus,
660}
661
662impl From<Entry> for UpdatePlace {
663 fn from(e: Entry) -> Self {
664 let Entry {
665 version,
666 title,
667 description,
668 lat,
669 lng,
670 street,
671 zip,
672 city,
673 country,
674 state,
675 contact_name,
676 email,
677 telephone,
678 homepage,
679 opening_hours,
680 founded_on,
681 categories,
682 tags,
683 image_url,
684 image_link_url,
685 custom_links,
686 ..
687 } = e;
688
689 UpdatePlace {
690 version,
691 title,
692 description,
693 lat,
694 lng,
695 street,
696 zip,
697 city,
698 country,
699 state,
700 contact_name,
701 email,
702 telephone,
703 homepage,
704 opening_hours,
705 founded_on,
706 categories,
707 tags,
708 image_url,
709 image_link_url,
710 links: custom_links,
711 }
712 }
713}
714
715#[derive(Serialize, Deserialize)]
716#[cfg_attr(feature = "extra-derive", derive(Debug, Clone))]
717pub struct JwtToken {
718 pub token: String,
719}
720
721#[derive(Serialize, Deserialize)]
722#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq, Error))]
723#[cfg_attr(feature = "extra-derive", error("{http_status}:{message}"))]
724pub struct Error {
725 pub http_status: u16,
727 pub message: String,
729}
730
731#[derive(Serialize, Deserialize)]
732#[cfg_attr(feature = "extra-derive", derive(Debug, Clone, PartialEq, Eq))]
733pub enum DuplicateType {
734 SimilarChars,
735 SimilarWords,
736}