use axum::Json; use axum::body::Bytes; use axum::extract::State; use axum::response::IntoResponse; use axum_typed_multipart::{TryFromMultipart, TypedMultipart}; use validator::Validate; use crate::state::AppState; use crate::util::SerdeFieldData; use crate::{object_store, web}; #[derive(Debug, Validate, TryFromMultipart)] #[try_from_multipart(rename_all = "camelCase")] pub struct UploadPayload { #[form_data(limit = "50MB")] #[validate(length(min = 1, max = 16))] files: Vec>, } pub async fn upload( State(state): State, TypedMultipart(payload): TypedMultipart, ) -> web::Result { match payload.validate() { Ok(_) => {}, Err(e) => return Err(web::error::ClientError::ValidationFailed(e).into()), }; let mut file_ids = Vec::new(); for file in payload.files { let db_file = state .database .insert_file( file.metadata .file_name .as_deref() .unwrap_or_else(|| "unknown"), file.metadata.content_type.as_deref().unwrap_or_default(), file.contents.len(), ) .await?; state .object_store .put_object(&db_file.id.to_string(), &file.contents) .await .map_err(object_store::Error::from)?; file_ids.push(db_file.id); } Ok(Json(file_ids)) }