shared/domain/
meta.rs

1//! Types for metadata.
2
3use chrono::{DateTime, Utc};
4use macros::make_path_parts;
5use serde::{Deserialize, Serialize};
6
7use crate::api::endpoints::PathPart;
8
9wrap_uuid! {
10    /// Wrapper type around [`Uuid`], represents [`ImageStyle::id`].
11    pub struct ImageStyleId
12}
13
14wrap_uuid! {
15    /// Wrapper type around [`Uuid`], represents [`AnimationStyle::id`].
16    pub struct AnimationStyleId
17}
18
19wrap_uuid! {
20    /// Wrapper type around [`Uuid`], represents [`AudioStyle::id`]. Note: not yet implemented
21    pub struct AudioStyleId
22}
23
24wrap_uuid! {
25    /// Wrapper type around [`Uuid`], represents [`AgeRange::id`].
26    pub struct AgeRangeId
27}
28
29wrap_uuid! {
30    /// Wrapper type around [`Uuid`], represents [`Affiliation::id`].
31    pub struct AffiliationId
32}
33
34wrap_uuid! {
35    /// Wrapper type around [`Uuid`], represents [`AdditionalResource::id`].
36    pub struct ResourceTypeId
37}
38
39wrap_uuid! {
40    /// Wrapper type around [`Uuid`], represents [`Subject::id`].
41    pub struct SubjectId
42}
43
44wrap_uuid! {
45    /// Wrapper type around [`Uuid`], represents [`Report::id`].
46    pub struct ReportId
47}
48
49/// Wrapper type around [`i16`](std::i16), represents the index of an image tag.
50///
51/// This is used instead of UUIDs for image tags as they aren't created dynamically and
52/// a simple and consistent way to identify them is desired.
53#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Debug, Hash)]
54#[cfg_attr(feature = "backend", derive(sqlx::Type))]
55#[cfg_attr(feature = "backend", sqlx(transparent))]
56pub struct ImageTagIndex(pub i16);
57
58into_i16_index!(ImageTagIndex);
59
60make_path_parts!(GetMetadataPath => "/v1/metadata");
61
62/// Represents an image style.
63#[derive(Serialize, Deserialize, Debug, Clone)]
64pub struct ImageStyle {
65    /// The id of the image style.
66    pub id: ImageStyleId,
67
68    /// The image style's name.
69    pub display_name: String,
70
71    /// When the image style was created.
72    pub created_at: DateTime<Utc>,
73
74    /// When the image style was last updated.
75    pub updated_at: Option<DateTime<Utc>>,
76}
77
78/// Represents an animation style.
79#[derive(Serialize, Deserialize, Debug, Clone)]
80pub struct AnimationStyle {
81    /// The id of the animation style.
82    pub id: AnimationStyleId,
83
84    /// The animation style's name.
85    pub display_name: String,
86
87    /// When the animation style was created.
88    pub created_at: DateTime<Utc>,
89
90    /// When the animation style was last updated.
91    pub updated_at: Option<DateTime<Utc>>,
92}
93
94/// Represents an image style.
95#[derive(Serialize, Deserialize, Debug)]
96pub struct PdfStyle {
97    /// The id of the image style.
98    pub id: ImageStyleId,
99
100    /// The image style's name.
101    pub display_name: String,
102
103    /// When the image style was created.
104    pub created_at: DateTime<Utc>,
105
106    /// When the image style was last updated.
107    pub updated_at: Option<DateTime<Utc>>,
108}
109
110/// Represents a age range.
111#[derive(Clone, Serialize, Deserialize, Debug)]
112pub struct AgeRange {
113    /// The id of the age range.
114    pub id: AgeRangeId,
115
116    /// The age range's name.
117    pub display_name: String,
118
119    /// The age range's abbreviated name.
120    pub short_display_name: Option<String>,
121
122    /// When the age range was created.
123    pub created_at: DateTime<Utc>,
124
125    /// When the age range was last updated.
126    pub updated_at: Option<DateTime<Utc>>,
127}
128
129/// Represents an affiliation.
130#[derive(Serialize, Deserialize, Debug, Clone)]
131pub struct Affiliation {
132    /// The id of the affiliation.
133    pub id: AffiliationId,
134
135    /// The affiliation's name.
136    pub display_name: String,
137
138    /// When the affiliation was created.
139    pub created_at: DateTime<Utc>,
140
141    /// When the affiliation was last updated.
142    pub updated_at: Option<DateTime<Utc>>,
143}
144
145/// Represents an additional resource.
146#[derive(Clone, Serialize, Deserialize, Debug)]
147pub struct ResourceType {
148    /// The id of the additional resource.
149    pub id: ResourceTypeId,
150
151    /// The additional resource name.
152    pub display_name: String,
153
154    /// When the age range was created.
155    pub created_at: DateTime<Utc>,
156
157    /// When the age range was last updated.
158    pub updated_at: Option<DateTime<Utc>>,
159}
160
161/// Represents a subject.
162#[derive(Serialize, Deserialize, Debug, Clone)]
163pub struct Subject {
164    /// The id of the subject.
165    pub id: SubjectId,
166
167    /// The subject's name.
168    pub display_name: String,
169
170    /// When the subject was created.
171    pub created_at: DateTime<Utc>,
172
173    /// When the subject was last updated.
174    pub updated_at: Option<DateTime<Utc>>,
175}
176
177/// Represents a tag.
178#[derive(Serialize, Deserialize, Debug, Clone)]
179pub struct ImageTag {
180    /// Index of the tag.
181    pub index: ImageTagIndex,
182
183    /// The tag's name.
184    pub display_name: String,
185
186    /// When the tag was created.
187    pub created_at: DateTime<Utc>,
188
189    /// When the tag was last updated.
190    pub updated_at: Option<DateTime<Utc>>,
191}
192
193/// Response for fetching all metadata.
194#[derive(Serialize, Deserialize, Debug, Clone)]
195pub struct MetadataResponse {
196    /// All image styles the server has.
197    pub image_styles: Vec<ImageStyle>,
198
199    /// All animation styles the server has.
200    pub animation_styles: Vec<AnimationStyle>,
201
202    /// All audio...
203    // TODO
204
205    /// All age ranges the server has.
206    pub age_ranges: Vec<AgeRange>,
207
208    /// All affiliations the server has.
209    pub affiliations: Vec<Affiliation>,
210
211    /// All additional resources the server has.
212    pub resource_types: Vec<ResourceType>,
213
214    /// All subjects the server has.
215    pub subjects: Vec<Subject>,
216
217    /// All tags for images.
218    pub image_tags: Vec<ImageTag>,
219}
220
221/// Metadata kinds.
222#[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Debug)]
223pub enum MetaKind {
224    /// [`Affiliation`]
225    Affiliation,
226
227    /// [`ResourceType`]
228    ResourceType,
229
230    /// [`ImageStyle`]
231    ImageStyle,
232
233    /// [`AnimationStyle`]
234    AnimationStyle,
235
236    /// [`AgeRange`]
237    AgeRange,
238
239    /// [`Category`](super::category::Category)
240    Category,
241
242    /// [`Subject`]
243    Subject,
244
245    /// [`ImageTag`]
246    Tag,
247}
248
249/// Representation of a Google autocomplete result
250#[derive(Clone, Serialize, Deserialize, Debug)]
251pub struct GoogleLocation {
252    /// Input text
253    pub input: String,
254    /// Place returned by Google
255    pub place: GooglePlace,
256}
257
258/// Representation of a Google Place
259#[derive(Clone, Serialize, Deserialize, Debug)]
260pub struct GooglePlace {
261    /// List of address components
262    pub address_components: Vec<GoogleAddressComponent>,
263}
264
265impl GooglePlace {
266    /// Finds the first address component of this Google Place which matches the Address Type
267    pub fn address_component_by_type(
268        &self,
269        address_type: GoogleAddressType,
270    ) -> Option<&GoogleAddressComponent> {
271        self.address_components.iter().find(|component| {
272            component
273                .types
274                .iter()
275                .find(|t| **t == address_type)
276                .is_some()
277        })
278    }
279}
280
281/// Representation of a Google Address Component
282#[derive(Clone, Serialize, Deserialize, Debug)]
283pub struct GoogleAddressComponent {
284    /// Components long name
285    pub long_name: String,
286    /// Components short name
287    pub short_name: String,
288    /// List of address types associated with the component
289    pub types: Vec<GoogleAddressType>,
290}
291
292impl std::fmt::Display for GoogleAddressComponent {
293    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294        write!(f, "{}", self.long_name)
295    }
296}
297
298impl From<&GoogleAddressComponent> for String {
299    fn from(component: &GoogleAddressComponent) -> String {
300        format!("{}", component)
301    }
302}
303
304/// Representation of common Google Address Types
305#[derive(Clone, Serialize, Eq, PartialEq, Deserialize, Debug)]
306#[serde(rename_all = "snake_case")]
307pub enum GoogleAddressType {
308    /// Indicates an incorporated city or town political entity
309    Locality,
310    /// Indicates a first-order civil entity below a locality
311    Sublocality,
312    /// Indicates a postal code as used to address postal mail within the country
313    PostalCode,
314    /// Indicates the national political entity
315    Country,
316    /// Indicates a first-order civil entity below the country level
317    #[serde(rename = "administrative_area_level_1")]
318    AdministrativeAreaLevel1,
319    /// Indicates a second-order civil entity below the country level
320    #[serde(rename = "administrative_area_level_2")]
321    AdministrativeAreaLevel2,
322    /// Indicates a political entity
323    Political,
324    /// Any other address type found [here](https://developers.google.com/maps/documentation/geocoding/requests-geocoding#Types)
325    #[serde(untagged)]
326    Other(String),
327}