use axum::{ extract::{FromRequest, Form, Json, Query, State}, http::{self, Request, StatusCode}, response::{IntoResponse, Response}, RequestExt, }; use axum_typed_multipart::{TryFromMultipart, TypedMultipart}; use yunohost_api::{Username, Password}; use crate::state::RoutableAppState; #[derive(Debug, TryFromMultipart, Deserialize)] pub struct LoginForm { username: Username, #[allow(dead_code)] password: Password, } #[async_trait] impl FromRequest for LoginForm where Json: FromRequest<(), B>, Form: FromRequest<(), B>, TypedMultipart: FromRequest, B::Data: Into, B::Error: Into + Send + std::error::Error, B: Send + 'static + axum::body::HttpBody, S: Send { type Rejection = Response; async fn from_request(req: Request, _state: &S) -> Result { let headers = req.headers(); if let Some(mime) = headers.get(http::header::CONTENT_TYPE).and_then(|v| v.to_str().ok()) { if mime.starts_with("application/json") { let Json(login_form): Json = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } if mime.starts_with("application/x-www-form-urlencoded") { let Form(login_form) = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } if mime.starts_with("multipart/form-data") { let TypedMultipart(login_form): TypedMultipart = req.extract().await.map_err(IntoResponse::into_response)?; return Ok(login_form); } Err(StatusCode::UNSUPPORTED_MEDIA_TYPE.into_response()) } else { Err("No POST Content-Type".into_response()) } } } #[debug_handler] pub async fn route(state: State, form: LoginForm) -> String { if state.check_login(&form.username, &form.password).await.unwrap() { format!("Welcome {}", &form.username) } else { format!("Invalid login for {}", &form.username) } }