summaryrefslogtreecommitdiffstats
path: root/src/files.rs
blob: 16a11b6eceadfbe42dccbba8f978b066471c7f85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::config::CONFIG;
use crate::errors::AppError;
use axum::{
    extract::{Multipart, Path},
    http::header::{HeaderMap, HeaderName, HeaderValue},
};
use std::fs;

use rand::random;

/// Upload a file. Returns an `AppError` or the path of the uploaded file.
/// If `filename` param has a value choose it as filename
pub async fn upload(
    mut multipart: Multipart,
    allowed_extensions: Vec<&str>,
    filename: Option<String>,
) -> Result<String, AppError> {
    let mut uploaded_file = String::new();

    if let Some(file) = multipart.next_field().await.unwrap() {
        let content_type = file.content_type().unwrap().to_string();

        let index = content_type.find('/').unwrap_or(usize::max_value());
        let mut ext_name = "xxx";
        if index != usize::max_value() {
            ext_name = &content_type[index + 1..];
        }

        if allowed_extensions
            .iter()
            .any(|&x| x.to_lowercase() == ext_name)
        {
            let name = match filename {
                Some(name) => name,
                None => (random::<f32>() * 1000000000 as f32).to_string(),
            };

            let save_filename = format!("{}/{}.{}", CONFIG.save_file_base_path, name, ext_name);
            uploaded_file = format!("{}/{}.{}", CONFIG.uploads_endpoint, name, ext_name);

            let data = file.bytes().await.unwrap();

            tokio::fs::write(&save_filename, &data)
                .await
                .map_err(|err| err.to_string())?;
        }
    }

    if !uploaded_file.is_empty() {
        return Ok(uploaded_file);
    }

    Err(AppError::BadRequest(
        "File extension not supported".to_string(),
    ))
}

/// Delete a file from the filesystem
pub async fn delete_upload(filename: String) -> Result<(), AppError> {
    fs::remove_file(filename)?;

    Ok(())
}

/// Axum endpoint which shows uploaded file
pub async fn show_uploads(Path(id): Path<String>) -> (HeaderMap, Vec<u8>) {
    let index = id.find('.').unwrap_or(usize::max_value());

    let mut ext_name = "xxx";
    if index != usize::max_value() {
        ext_name = &id[index + 1..];
    }
    let mut headers = HeaderMap::new();

    if vec!["jpg", "jpeg", "png", "gif", "webp"]
        .iter()
        .any(|&x| x == ext_name)
    {
        let content_type = format!("image/{}", ext_name);
        headers.insert(
            HeaderName::from_static("content-type"),
            HeaderValue::from_str(&content_type).unwrap(),
        );
    }
    let file_name = format!("{}/{}", CONFIG.save_file_base_path, id);
    (headers, fs::read(&file_name).unwrap())
}