shared/domain/
animation.rs

1//! Types for animations.
2
3use crate::api::endpoints::PathPart;
4
5use super::{meta::AnimationStyleId, Publish};
6use chrono::{DateTime, Utc};
7use macros::make_path_parts;
8use serde::{Deserialize, Serialize};
9#[cfg(feature = "backend")]
10use sqlx::postgres::PgRow;
11
12/// Animation Kinds
13#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
14#[cfg_attr(feature = "backend", derive(sqlx::Type))]
15#[repr(i16)]
16pub enum AnimationKind {
17    /// Gif Animation
18    Gif = 0,
19    /// Spritesheet Animation
20    Spritesheet = 1,
21}
22
23impl AnimationKind {
24    /// returns `self` in a string representation.
25    #[must_use]
26    pub const fn to_str(self) -> &'static str {
27        match self {
28            Self::Gif => "gif",
29            Self::Spritesheet => "spritesheet",
30        }
31    }
32}
33
34wrap_uuid! {
35    /// Wrapper type around [`Uuid`], represents the ID of an animation.
36    pub struct AnimationId
37}
38
39make_path_parts!(AnimationGetPath => "/v1/animation/{}" => AnimationId);
40
41/// Response for getting a single animation file.
42#[derive(Serialize, Deserialize, Debug)]
43pub struct AnimationResponse {
44    /// The animation's metadata.
45    pub metadata: AnimationMetadata,
46}
47
48/// Over the wire representation of an animation's metadata.
49#[derive(Serialize, Deserialize, Debug)]
50pub struct AnimationMetadata {
51    /// The animation's ID.
52    pub id: AnimationId,
53
54    /// The name of the animation.
55    pub name: String,
56
57    /// The description of the animation.
58    pub description: String,
59
60    /// Is the animation premium?
61    pub is_premium: bool,
62
63    /// When the animation should be considered published (if at all).
64    pub publish_at: Option<DateTime<Utc>>,
65
66    /// The styles associated with the animation.
67    pub styles: Vec<AnimationStyleId>,
68
69    /// What kind of animation this is.
70    pub kind: AnimationKind,
71
72    /// Should the animation loop?
73    pub is_looping: bool,
74
75    /// When the animation was originally created.
76    pub created_at: DateTime<Utc>,
77
78    /// When the animation was last updated.
79    pub updated_at: Option<DateTime<Utc>>,
80}
81
82// HACK: can't get `Vec<_>` directly from the DB. See `[crate::domain::image::ImageMetadata]`
83#[cfg(feature = "backend")]
84impl<'r> sqlx::FromRow<'r, PgRow> for AnimationMetadata {
85    fn from_row(row: &'r PgRow) -> Result<Self, sqlx::Error> {
86        let DbAnimation {
87            id,
88            kind,
89            name,
90            description,
91            is_premium,
92            publish_at,
93            styles,
94            is_looping,
95            created_at,
96            updated_at,
97        } = DbAnimation::from_row(row)?;
98
99        Ok(Self {
100            id,
101            kind,
102            name,
103            description,
104            is_premium,
105            publish_at,
106            styles: styles.into_iter().map(|(it,)| it).collect(),
107            is_looping,
108            created_at,
109            updated_at,
110        })
111    }
112}
113
114#[cfg_attr(feature = "backend", derive(sqlx::FromRow))]
115#[cfg(feature = "backend")]
116struct DbAnimation {
117    pub id: AnimationId,
118    pub kind: AnimationKind,
119    pub name: String,
120    pub description: String,
121    pub is_premium: bool,
122    pub publish_at: Option<DateTime<Utc>>,
123    pub styles: Vec<(AnimationStyleId,)>,
124    pub is_looping: bool,
125    pub created_at: DateTime<Utc>,
126    pub updated_at: Option<DateTime<Utc>>,
127}
128
129make_path_parts!(AnimationCreatePath => "/v1/animation");
130
131// todo: # errors doc section
132/// Request to create a new animation.
133#[derive(Serialize, Deserialize, Debug)]
134pub struct AnimationCreateRequest {
135    /// The name of the animation.
136    pub name: String,
137
138    /// The description of the animation.
139    pub description: String,
140
141    /// Is the animation premium?
142    pub is_premium: bool,
143
144    /// When to publish the animation.
145    ///
146    /// If [`Some`] publish the animation according to the `Publish`. Otherwise, don't publish it.
147    pub publish_at: Option<Publish>,
148
149    /// The styles associated with the animation.
150    pub styles: Vec<AnimationStyleId>,
151
152    /// What kind of animation this is.
153    pub kind: AnimationKind,
154
155    /// Should the animation loop?
156    pub is_looping: bool,
157}
158
159make_path_parts!(AnimationUploadPath => "/v1/animation/{}/raw" => AnimationId);
160
161/// Request to indicate the size of an user library image for upload.
162#[derive(Serialize, Deserialize, Debug)]
163pub struct AnimationUploadRequest {
164    /// The size of the image to be uploaded in bytes.
165    pub file_size: usize,
166}
167
168/// URL to upload an user library image, supports resumable uploading.
169#[derive(Serialize, Deserialize, Debug)]
170pub struct AnimationUploadResponse {
171    /// The session URI used for uploading, including the query for uploader ID
172    pub session_uri: String,
173}
174
175make_path_parts!(AnimationDeletePath => "/v1/animation/{}" => AnimationId);