Skip to main content

waifuvault/
api.rs

1//! API types that can be received from the Waifu Vault API
2use serde::{Deserialize, Serialize};
3use std::path::Path;
4
5/// The main API responses that can be received
6///
7/// Serde will deserialize these into the appropriate type
8#[derive(Deserialize, Debug, Clone)]
9#[serde(untagged)]
10pub(crate) enum WaifuApiResponse {
11    /// Everything is good, contains the info about the uploaded file
12    WaifuFileResponse(WaifuFileEntry),
13
14    /// Everything is good, contains info about the album
15    WaifuAlbumResponse(WaifuAlbumEntry),
16
17    /// Everything is good, contains info about the bucket
18    WaifuBucketResponse(WaifuBucketEntry),
19
20    /// Everything is good, contains generic success / failure message
21    WaifuGenericResponse(WaifuGenericMessage),
22
23    /// Something went wrong, shows the error type and reason
24    WaifuError(WaifuError),
25
26    /// Special case for the delete endpoint, just a boolean flag
27    /// if it was successful or not
28    Delete(bool),
29}
30
31/// This is a standard response for the service containing info about the entry
32#[derive(Debug, Deserialize, Clone)]
33pub struct WaifuFileEntry {
34    /// File token - used for file info and deleting
35    pub token: String,
36
37    /// Location of the uploaded file
38    pub url: String,
39
40    /// Bucket identifier
41    pub bucket: Option<String>,
42
43    /// ID of the file
44    pub id: usize,
45
46    /// Album the file is associated with, if any
47    pub album: Option<WaifuAlbumMetadata>,
48
49    /// Number of views the file has
50    pub views: usize,
51
52    /// How long the file will exist for
53    #[serde(rename = "retentionPeriod")]
54    pub retention_period: serde_json::Value,
55
56    /// Response options for the file
57    pub options: Option<WaifuFileOptions>,
58}
59
60/// Response options for the uploaded file
61#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
62pub struct WaifuFileOptions {
63    /// If the filename is hidden
64    #[serde(rename = "hideFilename")]
65    pub hide_filename: bool,
66
67    /// If this file will be deleted when it is accessed
68    #[serde(rename = "oneTimeDownload")]
69    pub one_time_download: bool,
70
71    /// If this file requires a password
72    pub protected: bool,
73}
74
75/// Successful response from the API when interacting with the Bucket API
76#[derive(Debug, Deserialize, Clone)]
77pub struct WaifuBucketEntry {
78    /// Bucket token identifier
79    pub token: String,
80
81    /// Files contained within the bucket
82    pub files: Vec<WaifuFileEntry>,
83
84    /// Albums associated with the bucket, if any
85    pub albums: Option<Vec<WaifuAlbumMetadata>>,
86}
87
88/// Successful response from the API when interacting with the Album API
89#[derive(Debug, Deserialize, Clone)]
90pub struct WaifuAlbumEntry {
91    /// Album token identifier
92    pub token: String,
93
94    /// Bucket token identifier
95    #[serde(rename = "bucketToken")]
96    pub bucket_token: String,
97
98    /// Public token identifier
99    #[serde(rename = "publicToken")]
100    pub public_token: Option<String>,
101
102    /// Name of the Album
103    pub name: String,
104
105    /// Files contained within the Album
106    pub files: Vec<WaifuFileEntry>,
107}
108
109/// Album metadata which shows which album a file is apart of
110#[derive(Debug, Deserialize, Clone)]
111pub struct WaifuAlbumMetadata {
112    /// Album token
113    pub token: String,
114
115    /// Public token
116    #[serde(rename = "publicToken")]
117    pub public_token: Option<String>,
118
119    /// Album name
120    pub name: String,
121
122    /// Bucket name
123    pub bucket: String,
124
125    /// Date the album was created
126    #[serde(rename = "dateCreated")]
127    pub date_created: u64,
128}
129
130/// Generic response returned by the API indicating success / failure of operation
131#[derive(Debug, Deserialize, Clone)]
132pub struct WaifuGenericMessage {
133    /// If the operation was a success or not
134    pub success: bool,
135
136    /// Description provided by the API
137    pub description: String,
138}
139
140/// A standard error, all errors from the service take this shape
141#[derive(Debug, Deserialize, Clone)]
142pub struct WaifuError {
143    /// The name of the error, this is normally the HTTP exception thrown
144    pub name: String,
145
146    /// The thing that went wrong
147    pub message: String,
148
149    /// The HTTP status
150    pub status: u16,
151}
152
153impl std::fmt::Display for WaifuError {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        write!(
156            f,
157            "WaifuError {} ({})\nMessage: {}",
158            self.name, self.status, self.message
159        )
160    }
161}
162
163impl std::error::Error for WaifuError {}
164
165/// Upload request to upload content to the Waifu Vault
166#[derive(Debug, Default, Clone)]
167pub struct WaifuUploadRequest {
168    /// Path to a file to upload
169    pub(crate) file: Option<String>,
170
171    /// URL of a resource to upload
172    pub(crate) url: Option<String>,
173
174    /// Raw bytes to upload to the vault
175    pub(crate) bytes: Option<Vec<u8>>,
176
177    /// Token of the bucket to upload to
178    pub(crate) bucket: Option<String>,
179
180    /// Filename to be used when uploading raw bytes
181    pub(crate) filename: Option<String>,
182
183    /// Set an expiry for the content
184    /// This is a string containing a number and a letter (m for mins, h for hours, d for days)
185    /// Leave blank to keep the file for as long as the retention policy allows
186    pub(crate) expires: Option<String>,
187
188    /// Hide the filename from the generated URL
189    pub(crate) hide_filename: bool,
190
191    /// Set a password for the file
192    /// This encrypts the file on the server which can only be accessed by
193    /// retrieving it with the x-password header set
194    pub(crate) password: Option<String>,
195
196    /// Delete the file after first access
197    pub(crate) one_time_download: bool,
198}
199
200impl WaifuUploadRequest {
201    /// Create a new upload request
202    pub fn new() -> Self {
203        Self::default()
204    }
205
206    /// Sets the file field on the request
207    pub fn file(mut self, file: impl AsRef<Path>) -> Self {
208        let file = file.as_ref().display().to_string();
209        self.file = Some(file);
210        self
211    }
212
213    /// Sets the url field on the request
214    pub fn url(mut self, url: impl AsRef<str>) -> Self {
215        self.url = Some(url.as_ref().to_string());
216        self
217    }
218
219    /// Sets the bytes field on the request
220    pub fn bytes(mut self, bytes: Vec<u8>, filename: impl AsRef<str>) -> Self {
221        self.bytes = Some(bytes);
222        self.filename = Some(filename.as_ref().to_string());
223        self
224    }
225
226    /// Sets the bucket token on the request
227    pub fn bucket(mut self, token: impl AsRef<str>) -> Self {
228        self.bucket = Some(token.as_ref().to_string());
229        self
230    }
231
232    /// Sets the expires field on the request
233    pub fn expires(mut self, expires: impl AsRef<str>) -> Self {
234        self.expires = Some(expires.as_ref().to_string());
235        self
236    }
237
238    /// Sets the hide_filename field on the request
239    pub fn hide_filename(mut self, hide: bool) -> Self {
240        self.hide_filename = hide;
241        self
242    }
243
244    /// Sets the password field on the request
245    pub fn password(mut self, password: impl AsRef<str>) -> Self {
246        self.password = Some(password.as_ref().to_string());
247        self
248    }
249
250    /// Sets the one_time_download field on the request
251    pub fn one_time_download(mut self, otd: bool) -> Self {
252        self.one_time_download = otd;
253        self
254    }
255}
256
257/// Request to be sent when requesting file information from the API
258#[derive(Debug, Default, Clone)]
259pub struct WaifuGetRequest {
260    /// Token used to access the content
261    pub(crate) token: String,
262
263    /// Flag to display the expiry time in human-readable format
264    pub(crate) formatted: bool,
265}
266
267impl WaifuGetRequest {
268    /// Create a new Get Request
269    pub fn new(token: impl AsRef<str>) -> Self {
270        Self {
271            token: token.as_ref().to_string(),
272            ..Default::default()
273        }
274    }
275
276    /// Set the formatted field on the request
277    pub fn formatted(mut self, format: bool) -> Self {
278        self.formatted = format;
279        self
280    }
281}
282
283/// Modification request to be sent when updating options on
284/// the target resource stored in the vault
285#[derive(Debug, Default, Clone, Serialize)]
286pub struct WaifuModificationRequest {
287    /// Token used to access the content
288    #[serde(skip)]
289    pub(crate) token: String,
290
291    /// Sets a password for the content
292    #[serde(skip_serializing_if = "Option::is_none")]
293    pub(crate) password: Option<String>,
294
295    /// The previous password of the content used when switching password
296    /// if one existed before
297    #[serde(skip_serializing_if = "Option::is_none")]
298    #[serde(rename = "previousPassword")]
299    pub(crate) previous_password: Option<String>,
300
301    /// Update the expiry time on the content
302    #[serde(skip_serializing_if = "Option::is_none")]
303    #[serde(rename = "customExpiry")]
304    pub(crate) custom_expiry: Option<String>,
305
306    /// Update the hide_filename flag for the content
307    #[serde(skip_serializing_if = "Option::is_none")]
308    #[serde(rename = "hideFilename")]
309    pub(crate) hide_filename: Option<bool>,
310}
311
312impl WaifuModificationRequest {
313    /// Create a new Modification request
314    pub fn new(token: impl AsRef<str>) -> Self {
315        Self {
316            token: token.as_ref().to_string(),
317            ..Default::default()
318        }
319    }
320
321    /// Set the password field on the request
322    pub fn password(mut self, password: impl AsRef<str>) -> Self {
323        self.password = Some(password.as_ref().to_string());
324        self
325    }
326
327    /// Set the previous_password field on the request
328    pub fn previous_password(mut self, prev_pwd: impl AsRef<str>) -> Self {
329        self.previous_password = Some(prev_pwd.as_ref().to_string());
330        self
331    }
332
333    /// Set the custom_expiry field on the request
334    pub fn custom_expiry(mut self, expiry: impl AsRef<str>) -> Self {
335        self.custom_expiry = Some(expiry.as_ref().to_string());
336        self
337    }
338
339    /// Set the hide_filename field on the request
340    pub fn hide_filename(mut self, hide: bool) -> Self {
341        self.hide_filename = Some(hide);
342        self
343    }
344}