use crate::ui::image;
use crate::ui::state::AppState;
use crate::ui::storage::ImageStore;
use axum::Json;
use axum::extract::{Multipart, State};
use axum::http::StatusCode;
use axum::response::IntoResponse;
use serde_json::json;
use std::sync::Arc;
pub async fn post_upload(
State(state): State<Arc<AppState>>,
mut multipart: Multipart,
) -> impl IntoResponse {
let field = match multipart.next_field().await {
Ok(Some(f)) => f,
Ok(None) => {
return (
StatusCode::BAD_REQUEST,
Json(json!({"error": "missing file field"})),
)
.into_response();
}
Err(e) => {
return (
StatusCode::BAD_REQUEST,
Json(json!({"error": format!("multipart error: {e}")})),
)
.into_response();
}
};
let filename = field.file_name().unwrap_or("upload.png").to_string();
let data = match field.bytes().await {
Ok(b) => b,
Err(e) => {
return (
StatusCode::BAD_REQUEST,
Json(json!({"error": format!("failed to read upload: {e}")})),
)
.into_response();
}
};
let format = match image::validate(&data) {
Ok(f) => f,
Err(e) => {
let status = if e.to_string().contains("too large") {
StatusCode::PAYLOAD_TOO_LARGE
} else {
StatusCode::UNSUPPORTED_MEDIA_TYPE
};
return (status, Json(json!({"error": e.to_string()}))).into_response();
}
};
let processed = match image::process(&data, format) {
Ok(p) => p,
Err(e) => {
return (
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({"error": format!("failed to process image: {e}")})),
)
.into_response();
}
};
match state.image_store.store(&filename, &processed).await {
Ok(meta) => Json(json!({
"id": meta.id,
"filename": meta.original_filename,
"size": meta.size_bytes,
}))
.into_response(),
Err(_) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"error": "failed to store image"})),
)
.into_response(),
}
}