Skip to main content

revolt_database/models/files/
model.rs

1use crate::{Database, FileHash, Metadata};
2
3use iso8601_timestamp::Timestamp;
4use revolt_result::Result;
5
6auto_derived_partial!(
7    /// File
8    pub struct File {
9        /// Unique Id
10        #[serde(rename = "_id")]
11        pub id: String,
12        /// Tag / bucket this file was uploaded to
13        pub tag: String,
14        /// Original filename
15        pub filename: String,
16        /// Hash of this file
17        pub hash: Option<String>, // these are Option<>s to not break file uploads on legacy Autumn
18
19        /// When this file was uploaded
20        pub uploaded_at: Option<Timestamp>, // these are Option<>s to not break file uploads on legacy Autumn
21        /// ID of user who uploaded this file
22        #[serde(skip_serializing_if = "Option::is_none")]
23        pub uploader_id: Option<String>, // these are Option<>s to not break file uploads on legacy Autumn
24
25        /// What the file was used for
26        #[serde(skip_serializing_if = "Option::is_none")]
27        pub used_for: Option<FileUsedFor>,
28
29        /// Whether this file was deleted
30        #[serde(skip_serializing_if = "Option::is_none")]
31        pub deleted: Option<bool>,
32        /// Whether this file was reported
33        #[serde(skip_serializing_if = "Option::is_none")]
34        pub reported: Option<bool>,
35
36        // !!! DEPRECATED:
37        /// Parsed metadata of this file
38        pub metadata: Metadata,
39        /// Raw content type of this file
40        pub content_type: String,
41        /// Size of this file (in bytes)
42        pub size: isize,
43
44        // TODO: migrate this mess to having:
45        // - author_id
46        // - parent: Parent { Message(id), User(id), etc }
47        #[serde(skip_serializing_if = "Option::is_none")]
48        pub message_id: Option<String>,
49        #[serde(skip_serializing_if = "Option::is_none")]
50        pub user_id: Option<String>,
51        #[serde(skip_serializing_if = "Option::is_none")]
52        pub server_id: Option<String>,
53
54        /// Id of the object this file is associated with
55        #[serde(skip_serializing_if = "Option::is_none")]
56        pub object_id: Option<String>,
57    },
58    "PartialFile"
59);
60
61auto_derived!(
62    /// Type of object file was used for
63    pub enum FileUsedForType {
64        Message,
65        ServerBanner,
66        Emoji,
67        UserAvatar,
68        WebhookAvatar,
69        UserProfileBackground,
70        LegacyGroupIcon,
71        ChannelIcon,
72        ServerIcon,
73        RoleIcon,
74    }
75
76    /// Information about what the file was used for
77    pub struct FileUsedFor {
78        /// Type of the object
79        #[serde(rename = "type")]
80        pub object_type: FileUsedForType,
81        /// ID of the object
82        pub id: String,
83    }
84);
85
86impl File {
87    /// Get the hash entry for this file
88    pub async fn as_hash(&self, db: &Database) -> Result<FileHash> {
89        db.fetch_attachment_hash(self.hash.as_ref().unwrap()).await
90    }
91
92    /// Use a file for a message attachment
93    pub async fn use_attachment(
94        db: &Database,
95        id: &str,
96        parent: &str,
97        uploader_id: &str,
98    ) -> Result<File> {
99        db.find_and_use_attachment(
100            id,
101            "attachments",
102            FileUsedFor {
103                id: parent.to_owned(),
104                object_type: FileUsedForType::Message,
105            },
106            uploader_id.to_owned(),
107        )
108        .await
109    }
110
111    /// Use a file for a user profile background
112    pub async fn use_background(
113        db: &Database,
114        id: &str,
115        parent: &str,
116        uploader_id: &str,
117    ) -> Result<File> {
118        db.find_and_use_attachment(
119            id,
120            "backgrounds",
121            FileUsedFor {
122                id: parent.to_owned(),
123                object_type: FileUsedForType::UserProfileBackground,
124            },
125            uploader_id.to_owned(),
126        )
127        .await
128    }
129
130    /// Use a file for a user avatar
131    pub async fn use_user_avatar(
132        db: &Database,
133        id: &str,
134        parent: &str,
135        uploader_id: &str,
136    ) -> Result<File> {
137        db.find_and_use_attachment(
138            id,
139            "avatars",
140            FileUsedFor {
141                id: parent.to_owned(),
142                object_type: FileUsedForType::UserAvatar,
143            },
144            uploader_id.to_owned(),
145        )
146        .await
147    }
148
149    /// Use a file for a webhook avatar
150    pub async fn use_webhook_avatar(
151        db: &Database,
152        id: &str,
153        parent: &str,
154        uploader_id: &str,
155    ) -> Result<File> {
156        db.find_and_use_attachment(
157            id,
158            "avatars",
159            FileUsedFor {
160                id: parent.to_owned(),
161                object_type: FileUsedForType::WebhookAvatar,
162            },
163            uploader_id.to_owned(),
164        )
165        .await
166    }
167
168    /// Use a file for a server icon
169    pub async fn use_server_icon(
170        db: &Database,
171        id: &str,
172        parent: &str,
173        uploader_id: &str,
174    ) -> Result<File> {
175        db.find_and_use_attachment(
176            id,
177            "icons",
178            FileUsedFor {
179                id: parent.to_owned(),
180                object_type: FileUsedForType::ServerIcon,
181            },
182            uploader_id.to_owned(),
183        )
184        .await
185    }
186
187    /// Use a file for a channel icon
188    pub async fn use_channel_icon(
189        db: &Database,
190        id: &str,
191        parent: &str,
192        uploader_id: &str,
193    ) -> Result<File> {
194        db.find_and_use_attachment(
195            id,
196            "icons",
197            FileUsedFor {
198                id: parent.to_owned(),
199                object_type: FileUsedForType::ChannelIcon,
200            },
201            uploader_id.to_owned(),
202        )
203        .await
204    }
205
206    /// Use a file for a server banner
207    pub async fn use_server_banner(
208        db: &Database,
209        id: &str,
210        parent: &str,
211        uploader_id: &str,
212    ) -> Result<File> {
213        db.find_and_use_attachment(
214            id,
215            "banners",
216            FileUsedFor {
217                id: parent.to_owned(),
218                object_type: FileUsedForType::ServerBanner,
219            },
220            uploader_id.to_owned(),
221        )
222        .await
223    }
224
225    /// Use a file for an emoji
226    pub async fn use_emoji(
227        db: &Database,
228        id: &str,
229        parent: &str,
230        uploader_id: &str,
231    ) -> Result<File> {
232        db.find_and_use_attachment(
233            id,
234            "emojis",
235            FileUsedFor {
236                id: parent.to_owned(),
237                object_type: FileUsedForType::Emoji,
238            },
239            uploader_id.to_owned(),
240        )
241        .await
242    }
243
244    /// Use a file for a role icon
245    pub async fn use_role_icon(
246        db: &Database,
247        id: &str,
248        parent: &str,
249        uploader_id: &str,
250    ) -> Result<File> {
251        db.find_and_use_attachment(
252            id,
253            "icons",
254            FileUsedFor {
255                id: parent.to_owned(),
256                object_type: FileUsedForType::RoleIcon,
257            },
258            uploader_id.to_owned(),
259        )
260        .await
261    }
262}