diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Cargo.lock | 37 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/config.rs | 2 | ||||
| -rw-r--r-- | src/errors.rs | 7 | ||||
| -rw-r--r-- | src/files.rs | 44 | ||||
| -rw-r--r-- | src/main.rs | 1 |
7 files changed, 93 insertions, 2 deletions
@@ -1 +1,2 @@ /target +/uploads @@ -113,6 +113,7 @@ dependencies = [ "matchit", "memchr", "mime", + "multer", "percent-encoding", "pin-project-lite", "serde", @@ -353,6 +354,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] name = "event-listener" version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -774,6 +784,24 @@ dependencies = [ ] [[package]] +name = "multer" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30ba6d97eb198c5e8a35d67d5779d6680cca35652a60ee90fc23dc431d4fde8" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.4", + "version_check", +] + +[[package]] name = "nom" version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1078,7 +1106,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -1268,6 +1296,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" + +[[package]] name = "sqlformat" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1781,6 +1815,7 @@ dependencies = [ "http-body", "jsonwebtoken", "once_cell", + "rand", "serde", "serde_json", "sha256", @@ -6,7 +6,7 @@ authors = ["Santo Cariotti <santo@dcariotti.me>"] [dependencies] async-trait = "0.1" -axum = { version = "0.5.15", features = ["headers"] } +axum = { version = "0.5.15", features = ["headers", "multipart"] } http-body = "0.4.3" jsonwebtoken = "8.1" once_cell = "1.13" @@ -20,3 +20,4 @@ sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres", "chro sha256 = "1.0.3" validator = { version = "0.16.0", features = ["derive"] } chrono = { version = "0.4", features = ["serde"] } +rand = "0.8.5" diff --git a/src/config.rs b/src/config.rs index 6449a3f..5783656 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1 +1,3 @@ pub static PAGE_LIMIT: i64 = 20; +pub const MAX_UPLOAD_FILE_SIZE: u64 = 1024 * 1024; // 1 MB +pub const SAVE_FILE_BASE_PATH: &str = "./uploads"; diff --git a/src/errors.rs b/src/errors.rs index 72eb837..2251ad4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -55,3 +55,10 @@ impl From<sqlx::Error> for AppError { AppError::Database } } + +/// Raise a generic error from a string +impl From<std::string::String> for AppError { + fn from(error: std::string::String) -> AppError { + AppError::BadRequest(error) + } +} diff --git a/src/files.rs b/src/files.rs new file mode 100644 index 0000000..63b8eec --- /dev/null +++ b/src/files.rs @@ -0,0 +1,44 @@ +use crate::config::SAVE_FILE_BASE_PATH; +use crate::errors::AppError; +use axum::extract::Multipart; + +use rand::random; + +/// Upload a file. Returns an `AppError` or the path of the uploaded file +pub async fn upload( + mut multipart: Multipart, + allowed_extensions: Vec<&str>, +) -> Result<String, AppError> { + let mut save_filename = 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("/") + .map(|i| i) + .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() + .position(|&x| x.to_lowercase() == ext_name) + .is_some() + { + let rnd = (random::<f32>() * 1000000000 as f32) as i32; + + save_filename = format!("{}/{}.{}", SAVE_FILE_BASE_PATH, rnd, ext_name); + + let data = file.bytes().await.unwrap(); + + tokio::fs::write(&save_filename, &data) + .await + .map_err(|err| err.to_string())?; + } + } + + Ok(save_filename) +} diff --git a/src/main.rs b/src/main.rs index 4f548d2..f0d7661 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod config; mod db; mod errors; +mod files; mod logger; mod models; mod pagination; |
