refactor: clean up presentation layer — AppState grouping, multipart extractor, thin handlers
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
pub mod auth;
|
||||
pub mod json;
|
||||
pub mod multipart_upload;
|
||||
|
||||
pub use auth::JwtClaims;
|
||||
pub use json::ValidatedJson;
|
||||
pub use multipart_upload::UploadedAsset;
|
||||
|
||||
74
crates/presentation/src/extractors/multipart_upload.rs
Normal file
74
crates/presentation/src/extractors/multipart_upload.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use axum::extract::Multipart;
|
||||
use bytes::Bytes;
|
||||
use domain::errors::DomainError;
|
||||
use domain::value_objects::SystemId;
|
||||
|
||||
use crate::constants::DEFAULT_DEVICE_ID;
|
||||
use crate::errors::AppError;
|
||||
|
||||
pub struct UploadedAsset {
|
||||
pub filename: String,
|
||||
pub data: Bytes,
|
||||
pub target_path_id: SystemId,
|
||||
pub client_device_id: String,
|
||||
}
|
||||
|
||||
impl UploadedAsset {
|
||||
pub async fn from_multipart(mut multipart: Multipart) -> Result<Self, AppError> {
|
||||
let mut file_data: Option<Bytes> = None;
|
||||
let mut filename: Option<String> = None;
|
||||
let mut target_path_id: Option<uuid::Uuid> = None;
|
||||
let mut client_device_id = DEFAULT_DEVICE_ID.to_string();
|
||||
|
||||
while let Some(field) = multipart
|
||||
.next_field()
|
||||
.await
|
||||
.map_err(|e| AppError::from(DomainError::Validation(e.to_string())))?
|
||||
{
|
||||
let name = field.name().unwrap_or("").to_string();
|
||||
match name.as_str() {
|
||||
"file" => {
|
||||
filename = field.file_name().map(|s| s.to_string());
|
||||
file_data = Some(
|
||||
field
|
||||
.bytes()
|
||||
.await
|
||||
.map_err(|e| AppError::from(DomainError::Internal(e.to_string())))?,
|
||||
);
|
||||
}
|
||||
"target_path_id" => {
|
||||
let text = field
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| AppError::from(DomainError::Validation(e.to_string())))?;
|
||||
target_path_id = Some(
|
||||
text.parse::<uuid::Uuid>()
|
||||
.map_err(|e| AppError::from(DomainError::Validation(e.to_string())))?,
|
||||
);
|
||||
}
|
||||
"client_device_id" => {
|
||||
client_device_id = field
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| AppError::from(DomainError::Validation(e.to_string())))?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let data = file_data
|
||||
.ok_or_else(|| AppError::from(DomainError::Validation("Missing file field".into())))?;
|
||||
let fname = filename
|
||||
.ok_or_else(|| AppError::from(DomainError::Validation("Missing filename".into())))?;
|
||||
let path_id = target_path_id.ok_or_else(|| {
|
||||
AppError::from(DomainError::Validation("Missing target_path_id".into()))
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
filename: fname,
|
||||
data,
|
||||
target_path_id: SystemId::from_uuid(path_id),
|
||||
client_device_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user