summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock37
-rw-r--r--Cargo.toml3
-rw-r--r--src/config.rs2
-rw-r--r--src/errors.rs7
-rw-r--r--src/files.rs44
-rw-r--r--src/main.rs1
7 files changed, 93 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index ea8c4bf..dccea96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/target
+/uploads
diff --git a/Cargo.lock b/Cargo.lock
index 5804124..c98ff4b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index 8744df1..736ec20 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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;