use std::collections::HashMap;
use axum::extract::Multipart;
use super::{FormError, upload::UploadedFile, upload::spool_field, urlencoded::UrlencodedFields};
#[derive(Default)]
pub struct MultipartParts {
pub text: UrlencodedFields,
pub files: HashMap<String, UploadedFile>,
pub file_lists: HashMap<String, Vec<UploadedFile>>,
}
pub async fn collect_multipart(
mut multipart: Multipart,
_file_names: &[&str],
multi_file_names: &[&str],
) -> Result<MultipartParts, FormError> {
let mut parts = MultipartParts::default();
while let Some(field) = multipart
.next_field()
.await
.map_err(|e| FormError::Multipart(e.to_string()))?
{
let name = field.name().unwrap_or("").to_string();
if name.is_empty() {
if let Err(e) = field.bytes().await {
tracing::warn!(error = %e, "failed discarding unnamed multipart field");
}
continue;
}
let has_filename = field.file_name().is_some_and(|n| !n.is_empty());
if has_filename {
let uploaded = spool_field(field).await?;
if multi_file_names.contains(&name.as_str()) {
parts.file_lists.entry(name).or_default().push(uploaded);
} else {
parts.files.insert(name, uploaded);
}
} else if field.file_name().is_some() {
if let Err(e) = field.bytes().await {
tracing::warn!(error = %e, field = %name, "failed discarding empty multipart file field");
}
} else {
let value = field
.text()
.await
.map_err(|e| FormError::Multipart(e.to_string()))?;
parts.text.push(name, value);
}
}
Ok(parts)
}