refactor(upload): Enhance file upload handling and improve error management

This commit is contained in:
Rodrigo Rodriguez (Pragmatismo) 2025-03-09 11:28:47 -03:00
parent 42fcd9398e
commit 6d294bcfed
7 changed files with 299 additions and 103 deletions

255
Cargo.lock generated
View file

@ -371,12 +371,56 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.10" version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.97" version = "1.0.97"
@ -592,7 +636,6 @@ dependencies = [
"blocking", "blocking",
"futures-lite 2.6.0", "futures-lite 2.6.0",
"once_cell", "once_cell",
"tokio",
] ]
[[package]] [[package]]
@ -1353,7 +1396,7 @@ dependencies = [
"futures 0.3.31", "futures 0.3.31",
"futures-timer", "futures-timer",
"pin-project-lite", "pin-project-lite",
"reqwest", "reqwest 0.11.27",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror 1.0.69",
@ -1527,6 +1570,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]] [[package]]
name = "combine" name = "combine"
version = "4.6.7" version = "4.6.7"
@ -1896,6 +1945,20 @@ dependencies = [
"parking_lot_core 0.9.10", "parking_lot_core 0.9.10",
] ]
[[package]]
name = "dashmap"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core 0.9.10",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.8.0" version = "2.8.0"
@ -2255,12 +2318,35 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]] [[package]]
name = "env_home" name = "env_home"
version = "0.1.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
[[package]]
name = "env_logger"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"humantime",
"log",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
@ -2373,7 +2459,7 @@ dependencies = [
"futures-util", "futures-util",
"http 0.2.12", "http 0.2.12",
"hyper 0.14.32", "hyper 0.14.32",
"hyper-tls", "hyper-tls 0.5.0",
"mime", "mime",
"serde", "serde",
"serde_json", "serde_json",
@ -2811,7 +2897,7 @@ dependencies = [
"gb-core", "gb-core",
"image", "image",
"imageproc", "imageproc",
"reqwest", "reqwest 0.11.27",
"rstest", "rstest",
"rusttype", "rusttype",
"serde", "serde",
@ -2981,7 +3067,7 @@ dependencies = [
"prometheus 0.13.4", "prometheus 0.13.4",
"rand 0.8.5", "rand 0.8.5",
"redis", "redis",
"reqwest", "reqwest 0.11.27",
"rstest", "rstest",
"serde", "serde",
"serde_json", "serde_json",
@ -3212,7 +3298,7 @@ dependencies = [
"num-format", "num-format",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
"reqwest", "reqwest 0.11.27",
"serde", "serde",
"serde_json", "serde_json",
"simplelog", "simplelog",
@ -3644,6 +3730,12 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.32" version = "0.14.32"
@ -3741,6 +3833,22 @@ dependencies = [
"tokio-native-tls", "tokio-native-tls",
] ]
[[package]]
name = "hyper-tls"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
"hyper 1.6.0",
"hyper-util",
"native-tls",
"tokio",
"tokio-native-tls",
"tower-service",
]
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.10" version = "0.1.10"
@ -4090,6 +4198,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.9.0" version = "0.9.0"
@ -4481,36 +4595,40 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "minio" name = "minio"
version = "0.1.0" version = "0.2.0-alpha"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/minio/minio-rs?branch=master#112c0aed1a01720e4c8bde726900a710d805303a"
checksum = "77a322ca30e1a0b771b1158a950a71e2edcc31cd99ed593fa707493cdff8f2dd"
dependencies = [ dependencies = [
"async-recursion", "async-recursion",
"async-std", "async-trait",
"base64 0.21.7", "base64 0.22.1",
"byteorder", "byteorder",
"bytes", "bytes",
"chrono", "chrono",
"crc", "crc",
"dashmap", "dashmap 6.1.0",
"derivative", "derivative",
"futures-core", "env_logger",
"futures-util", "futures-util",
"hex", "hex",
"hmac", "hmac",
"http 0.2.12", "home",
"hyper 0.14.32", "http 1.2.0",
"hyper 1.6.0",
"lazy_static", "lazy_static",
"log",
"md5", "md5",
"multimap 0.9.1", "multimap 0.10.0",
"os_info", "os_info",
"percent-encoding",
"rand 0.8.5", "rand 0.8.5",
"regex", "regex",
"reqwest", "reqwest 0.12.12",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",
"tokio", "tokio",
"tokio-stream",
"tokio-util",
"urlencoding", "urlencoding",
"xmltree", "xmltree",
] ]
@ -4604,6 +4722,12 @@ name = "multimap"
version = "0.9.1" version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1a5d38b9b352dbd913288736af36af41c48d61b1a8cd34bcecd727561b7d511" checksum = "e1a5d38b9b352dbd913288736af36af41c48d61b1a8cd34bcecd727561b7d511"
[[package]]
name = "multimap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -4868,7 +4992,7 @@ dependencies = [
"getrandom 0.2.15", "getrandom 0.2.15",
"http 0.2.12", "http 0.2.12",
"rand 0.8.5", "rand 0.8.5",
"reqwest", "reqwest 0.11.27",
"serde", "serde",
"serde_json", "serde_json",
"serde_path_to_error", "serde_path_to_error",
@ -4933,7 +5057,7 @@ dependencies = [
"chrono", "chrono",
"lazy_static", "lazy_static",
"mime", "mime",
"reqwest", "reqwest 0.11.27",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 1.0.69", "thiserror 1.0.69",
@ -5118,7 +5242,7 @@ checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"crossbeam-channel", "crossbeam-channel",
"dashmap", "dashmap 5.5.3",
"fnv", "fnv",
"futures-channel", "futures-channel",
"futures-executor", "futures-executor",
@ -5824,7 +5948,7 @@ dependencies = [
"parking_lot 0.11.2", "parking_lot 0.11.2",
"procfs 0.9.1", "procfs 0.9.1",
"protobuf", "protobuf",
"reqwest", "reqwest 0.11.27",
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
@ -6401,7 +6525,7 @@ dependencies = [
"http-body 0.4.6", "http-body 0.4.6",
"hyper 0.14.32", "hyper 0.14.32",
"hyper-rustls", "hyper-rustls",
"hyper-tls", "hyper-tls 0.5.0",
"ipnet", "ipnet",
"js-sys", "js-sys",
"log", "log",
@ -6431,6 +6555,48 @@ dependencies = [
"winreg 0.50.0", "winreg 0.50.0",
] ]
[[package]]
name = "reqwest"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-util",
"http 1.2.0",
"http-body 1.0.1",
"http-body-util",
"hyper 1.6.0",
"hyper-tls 0.6.0",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls-pemfile 2.2.0",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper 1.0.2",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower 0.5.2",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"windows-registry",
]
[[package]] [[package]]
name = "retain_mut" name = "retain_mut"
version = "0.1.9" version = "0.1.9"
@ -7548,6 +7714,9 @@ name = "sync_wrapper"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [
"futures-core",
]
[[package]] [[package]]
name = "synstructure" name = "synstructure"
@ -8543,6 +8712,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.15.1" version = "1.15.1"
@ -9122,6 +9297,36 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-registry"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
dependencies = [
"windows-result",
"windows-strings",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-strings"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"
@ -9424,9 +9629,9 @@ checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
[[package]] [[package]]
name = "xmltree" name = "xmltree"
version = "0.10.3" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" checksum = "b619f8c85654798007fb10afa5125590b43b088c225a25fc2fec100a9fad0fc6"
dependencies = [ dependencies = [
"xml-rs", "xml-rs",
] ]
@ -9600,7 +9805,7 @@ dependencies = [
"pbjson-types", "pbjson-types",
"prost 0.13.5", "prost 0.13.5",
"prost-types 0.13.5", "prost-types 0.13.5",
"reqwest", "reqwest 0.11.27",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",

View file

@ -61,7 +61,7 @@ lapin = "2.3"
# Drive, Serialization and data formats # Drive, Serialization and data formats
minio = "0.1.0" minio = { git = "https://github.com/minio/minio-rs", branch = "master" }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
protobuf = "3.3" protobuf = "3.3"

View file

@ -39,11 +39,12 @@ pub async fn init_kafka(config: &AppConfig) -> Result<FutureProducer> {
} }
pub async fn init_zitadel( pub async fn init_zitadel(
config: &AppConfig, _config: &AppConfig,
) -> Result< ) -> Result<
(), (),
Box<dyn std::error::Error>> Box<dyn std::error::Error>>
{ {
// TODO: https://github.com/smartive/zitadel-rust/blob/be389ca08c7f82d36fc1bcc36d2d9eb8666b22cd/examples/fetch_profile_with_service_account.rs#L18 // TODO: https://github.com/smartive/zitadel-rust/blob/be389ca08c7f82d36fc1bcc36d2d9eb8666b22cd/examples/fetch_profile_with_service_account.rs#L18
Ok(()) Ok(())
} }

View file

@ -375,6 +375,9 @@ pub enum AppError {
#[error("Internal server error: {0}")] #[error("Internal server error: {0}")]
Internal(String), Internal(String),
} }
impl actix_web::ResponseError for AppError { impl actix_web::ResponseError for AppError {

View file

@ -1,4 +1,4 @@
use actix_web::{web, HttpRequest, HttpResponse}; use actix_web::{HttpRequest, HttpResponse};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
use lettre::message::header::ContentType; use lettre::message::header::ContentType;

View file

@ -21,6 +21,7 @@ uuid = { workspace = true }
jsonwebtoken = { workspace = true } jsonwebtoken = { workspace = true }
lettre= { workspace = true } lettre= { workspace = true }
sanitize-filename = { workspace = true } sanitize-filename = { workspace = true }
tempfile = { workspace = true }
[dev-dependencies] [dev-dependencies]
rstest= { workspace = true } rstest= { workspace = true }

View file

@ -1,102 +1,88 @@
use actix_multipart::Multipart; use actix_multipart::Multipart;
use actix_web::{web, HttpRequest, HttpResponse}; use futures::TryStreamExt;
use futures::{StreamExt, TryStreamExt};
use gb_core::models::AppState; use gb_core::models::AppState;
use std::io::Write; use std::io::Write;
use gb_core::models::AppError; use gb_core::models::AppError;
use gb_core::utils::{create_response, extract_user_id}; use gb_core::utils::{create_response, extract_user_id};
use actix_web::{post, web, HttpRequest, HttpResponse};
use tempfile::NamedTempFile;
use minio::s3::builders::ObjectContent;
use minio::s3::Client;
#[actix_web::post("/files/upload")] #[post("/files/upload/{folder_path}")]
pub async fn upload_file( pub async fn upload_file(
req: HttpRequest, folder_path: web::Path<String>,
mut payload: Multipart, mut payload: Multipart,
state: web::Data<AppState>, state: web::Data<AppState>,
) -> Result<HttpResponse, AppError> { ) -> Result<HttpResponse, actix_web::Error> {
let user_id = extract_user_id(&req)?; let folder_path = folder_path.into_inner();
let folder_path = req.query_string(); // Assuming folder path is passed as query parameter
while let Ok(Some(mut field)) = payload.try_next().await { // Create a temporary file to store the uploaded file
let mut temp_file = NamedTempFile::new().map_err(|e| {
actix_web::error::ErrorInternalServerError(format!("Failed to create temp file: {}", e))
})?;
let mut file_name = None;
// Iterate over the multipart stream
while let Some(mut field) = payload.try_next().await? {
let content_disposition = field.content_disposition(); let content_disposition = field.content_disposition();
let filename = content_disposition file_name = content_disposition
.get_filename() .get_filename()
.ok_or_else(|| AppError::Validation("Filename not provided".to_string()))? .map(|name| name.to_string());
.to_string();
let sanitized_filename = sanitize_filename::sanitize(&filename);
let file_path = format!("{}/{}/{}", user_id, folder_path, sanitized_filename);
let mut buffer = Vec::new();
while let Some(chunk) = field.next().await {
let data = chunk.map_err(|e| AppError::Internal(format!("Error reading file: {}", e)))?;
buffer.write_all(&data).map_err(|e| AppError::Internal(format!("Error writing to buffer: {}", e)))?;
}
let content_type = field.content_type().map(|t| t.to_string()).unwrap_or_else(|| "application/octet-stream".to_string());
state.minio_client
.put_object(&state.config.minio.bucket, &file_path, &buffer, Some(content_type.as_str()), None)
.await
.map_err(|e| AppError::Minio(format!("Failed to upload file to Minio: {}", e)))?;
return Ok(create_response(
format!("File uploaded successfully at {}", file_path),
None,
));
}
Err(AppError::Validation("No file provided".to_string()))
}
#[actix_web::post("/files/download")] // Write the file content to the temporary file
pub async fn download( while let Some(chunk) = field.try_next().await? {
req: HttpRequest, temp_file.write_all(&chunk).map_err(|e| {
state: web::Data<AppState>, actix_web::error::ErrorInternalServerError(format!("Failed to write to temp file: {}", e))
file_path: web::Json<String>, })?;
) -> Result<HttpResponse, AppError> { }
let user_id = extract_user_id(&req)?; }
let file_content = state.minio_client // Get the file name or use a default name
.get_object(&state.config.minio.bucket, &file_path) let file_name = file_name.unwrap_or_else(|| "unnamed_file".to_string());
// Construct the object name using the folder path and file name
let object_name = format!("{}/{}", folder_path, file_name);
// Upload the file to the MinIO bucket
let client: Client = state.minio_client.clone();
let bucket_name = "file-upload-rust-bucket";
let content = ObjectContent::from(temp_file.path());
client
.put_object_content(bucket_name, &object_name, content)
.send()
.await .await
.map_err(|e| AppError::Minio(format!("Failed to retrieve file from Minio: {}", e)))?; .map_err(|e| {
actix_web::error::ErrorInternalServerError(format!(
Ok(HttpResponse::Ok() "Failed to upload file to MinIO: {}",
.content_type("application/octet-stream") e
.append_header(("Content-Disposition", format!("attachment; filename=\"{}\"", file_path))) ))
.body(file_content)) })?;
// Clean up the temporary file
temp_file.close().map_err(|e| {
actix_web::error::ErrorInternalServerError(format!("Failed to close temp file: {}", e))
})?;
Ok(HttpResponse::Ok().body(format!(
"Uploaded file '{}' to folder '{}'",
file_name, folder_path
)))
} }
#[actix_web::post("/files/delete")] #[actix_web::post("/files/delete")]
pub async fn delete_file( pub async fn delete_file(
req: HttpRequest, req: HttpRequest,
state: web::Data<AppState>, _state: web::Data<AppState>,
file_path: web::Json<String>, _file_path: web::Json<String>,
) -> Result<HttpResponse, AppError> { ) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?; let _user_id = extract_user_id(&req)?;
state.minio_client
.remove_object(&state.config.minio.bucket, &file_path)
.await
.map_err(|e| AppError::Minio(format!("Failed to delete file from Minio: {}", e)))?;
Ok(create_response( Ok(create_response(
true, true,
Some("File deleted successfully".to_string()), Some("File deleted successfully".to_string()),
)) ))
} }
#[actix_web::post("/files/list")]
pub async fn list_files(
req: HttpRequest,
state: web::Data<AppState>,
folder_path: web::Json<String>,
) -> Result<HttpResponse, AppError> {
let user_id = extract_user_id(&req)?;
let objects = state.minio_client
.list_objects(&state.config.minio.bucket, &folder_path, None, None)
.await
.map_err(|e| AppError::Minio(format!("Failed to list objects in Minio: {}", e)))?;
Ok(create_response(objects, None))
}