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 { let mut file_data: Option = None; let mut filename: Option = None; let mut target_path_id: Option = 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::() .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, }) } }