Files
MoneyMgr/moneymgr_backend/src/extractors/file_extractor.rs
2025-04-09 21:13:25 +02:00

75 lines
2.0 KiB
Rust

use crate::constants;
use actix_multipart::form::MultipartForm;
use actix_multipart::form::tempfile::TempFile;
use actix_web::dev::Payload;
use actix_web::{Error, FromRequest, HttpRequest};
use mime_guess::Mime;
use std::io::Read;
use std::str::FromStr;
#[derive(Debug, MultipartForm)]
struct FileUploadForm {
#[multipart(rename = "file")]
file: TempFile,
}
pub struct FileExtractor {
pub buff: Vec<u8>,
pub mime: Mime,
pub name: Option<String>,
}
impl FileExtractor {
pub fn name(&self) -> String {
match &self.name {
None => {
let ext = self.mime.suffix().map(|s| s.as_str()).unwrap_or("bin");
format!("file.{ext}")
}
Some(f) => f.to_string(),
}
}
}
impl FromRequest for FileExtractor {
type Error = Error;
type Future = futures_util::future::LocalBoxFuture<'static, Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
let form = MultipartForm::<FileUploadForm>::from_request(req, payload);
Box::pin(async move {
let mut form = form.await?;
if form.file.size > constants::MAX_UPLOAD_FILE_SIZE {
return Err(actix_web::error::ErrorPayloadTooLarge(
"Uploaded file is too large!",
));
}
let mut buff = Vec::with_capacity(form.file.size);
form.file.file.read_to_end(&mut buff)?;
let mime = match form
.file
.content_type
.clone()
.or_else(|| Mime::from_str(form.file.file_name.as_deref().unwrap_or("")).ok())
{
Some(s) => s,
None => {
return Err(actix_web::error::ErrorBadRequest(
"Mimetype was not specified!!",
));
}
};
Ok(Self {
mime,
buff,
name: form.file.file_name.clone(),
})
})
}
}