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    }
74
75    /// Information about what the file was used for
76    pub struct FileUsedFor {
77        /// Type of the object
78        #[serde(rename = "type")]
79        pub object_type: FileUsedForType,
80        /// ID of the object
81        pub id: String,
82    }
83);
84
85impl File {
86    /// Get the hash entry for this file
87    pub async fn as_hash(&self, db: &Database) -> Result<FileHash> {
88        db.fetch_attachment_hash(self.hash.as_ref().unwrap()).await
89    }
90
91    /// Use a file for a message attachment
92    pub async fn use_attachment(
93        db: &Database,
94        id: &str,
95        parent: &str,
96        uploader_id: &str,
97    ) -> Result<File> {
98        db.find_and_use_attachment(
99            id,
100            "attachments",
101            FileUsedFor {
102                id: parent.to_owned(),
103                object_type: FileUsedForType::Message,
104            },
105            uploader_id.to_owned(),
106        )
107        .await
108    }
109
110    /// Use a file for a user profile background
111    pub async fn use_background(
112        db: &Database,
113        id: &str,
114        parent: &str,
115        uploader_id: &str,
116    ) -> Result<File> {
117        db.find_and_use_attachment(
118            id,
119            "backgrounds",
120            FileUsedFor {
121                id: parent.to_owned(),
122                object_type: FileUsedForType::UserProfileBackground,
123            },
124            uploader_id.to_owned(),
125        )
126        .await
127    }
128
129    /// Use a file for a user avatar
130    pub async fn use_user_avatar(
131        db: &Database,
132        id: &str,
133        parent: &str,
134        uploader_id: &str,
135    ) -> Result<File> {
136        db.find_and_use_attachment(
137            id,
138            "avatars",
139            FileUsedFor {
140                id: parent.to_owned(),
141                object_type: FileUsedForType::UserAvatar,
142            },
143            uploader_id.to_owned(),
144        )
145        .await
146    }
147
148    /// Use a file for a webhook avatar
149    pub async fn use_webhook_avatar(
150        db: &Database,
151        id: &str,
152        parent: &str,
153        uploader_id: &str,
154    ) -> Result<File> {
155        db.find_and_use_attachment(
156            id,
157            "avatars",
158            FileUsedFor {
159                id: parent.to_owned(),
160                object_type: FileUsedForType::WebhookAvatar,
161            },
162            uploader_id.to_owned(),
163        )
164        .await
165    }
166
167    /// Use a file for a server icon
168    pub async fn use_server_icon(
169        db: &Database,
170        id: &str,
171        parent: &str,
172        uploader_id: &str,
173    ) -> Result<File> {
174        db.find_and_use_attachment(
175            id,
176            "icons",
177            FileUsedFor {
178                id: parent.to_owned(),
179                object_type: FileUsedForType::ServerIcon,
180            },
181            uploader_id.to_owned(),
182        )
183        .await
184    }
185
186    /// Use a file for a channel icon
187    pub async fn use_channel_icon(
188        db: &Database,
189        id: &str,
190        parent: &str,
191        uploader_id: &str,
192    ) -> Result<File> {
193        db.find_and_use_attachment(
194            id,
195            "icons",
196            FileUsedFor {
197                id: parent.to_owned(),
198                object_type: FileUsedForType::ChannelIcon,
199            },
200            uploader_id.to_owned(),
201        )
202        .await
203    }
204
205    /// Use a file for a server banner
206    pub async fn use_server_banner(
207        db: &Database,
208        id: &str,
209        parent: &str,
210        uploader_id: &str,
211    ) -> Result<File> {
212        db.find_and_use_attachment(
213            id,
214            "banners",
215            FileUsedFor {
216                id: parent.to_owned(),
217                object_type: FileUsedForType::ServerBanner,
218            },
219            uploader_id.to_owned(),
220        )
221        .await
222    }
223
224    /// Use a file for an emoji
225    pub async fn use_emoji(
226        db: &Database,
227        id: &str,
228        parent: &str,
229        uploader_id: &str,
230    ) -> Result<File> {
231        db.find_and_use_attachment(
232            id,
233            "emojis",
234            FileUsedFor {
235                id: parent.to_owned(),
236                object_type: FileUsedForType::Emoji,
237            },
238            uploader_id.to_owned(),
239        )
240        .await
241    }
242}