You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.3 KiB
82 lines
2.3 KiB
use std::ops::{Deref, DerefMut};
|
|
use axum::extract::{FromRequest, FromRequestParts, Request};
|
|
use axum::http::StatusCode;
|
|
use axum::{async_trait, RequestPartsExt};
|
|
use axum::extract::rejection::FormRejection;
|
|
use axum::response::{IntoResponse, IntoResponseParts};
|
|
use crate::app::routes::AppState;
|
|
use crate::error::AppError;
|
|
use super::htmx_form_data::{HtmxFormData, HtmxFormDataError};
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
pub struct ValidatedForm<T>(pub T);
|
|
|
|
#[async_trait]
|
|
impl<T> FromRequest<AppState> for ValidatedForm<T>
|
|
where
|
|
T: HtmxFormData
|
|
{
|
|
type Rejection = ValidatedFormError<T::FormTemplate>;
|
|
|
|
async fn from_request(req: Request, state: &AppState) -> Result<Self, Self::Rejection> {
|
|
|
|
let raw_form_data = axum::Form::<T>::from_request(req, state)
|
|
.await
|
|
.map_err(|e| ValidatedFormError::FormError(e))?;
|
|
|
|
let value = raw_form_data.0
|
|
.validate(&state)
|
|
.await
|
|
.map_err(|e|
|
|
match e {
|
|
HtmxFormDataError::ValidationError(e) => ValidatedFormError::ValidationError(e),
|
|
HtmxFormDataError::InternalServerError(e) => ValidatedFormError::InternalServerError(e),
|
|
}
|
|
)?;
|
|
|
|
Ok(ValidatedForm(value))
|
|
}
|
|
}
|
|
|
|
impl<T> Deref for ValidatedForm<T> {
|
|
type Target = T;
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl<T> DerefMut for ValidatedForm<T> {
|
|
#[inline]
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
pub enum ValidatedFormError<T> {
|
|
ValidationError(T),
|
|
FormError(FormRejection),
|
|
InternalServerError(anyhow::Error)
|
|
}
|
|
|
|
|
|
impl<T> IntoResponse for ValidatedFormError<T>
|
|
where T: IntoResponse
|
|
{
|
|
fn into_response(self) -> axum::response::Response {
|
|
match self {
|
|
ValidatedFormError::FormError(err) => {
|
|
err.into_response()
|
|
},
|
|
ValidatedFormError::ValidationError(err) => {
|
|
let (mut parts, body) = err.into_response().into_parts();
|
|
parts.status = StatusCode::OK;
|
|
(parts, body).into_response()
|
|
}
|
|
ValidatedFormError::InternalServerError(err) => {
|
|
AppError::from(err).into_response()
|
|
}
|
|
}
|
|
}
|
|
} |