custom extractors rejection
This commit is contained in:
@@ -10,7 +10,8 @@ mod unsubscribe;
|
||||
pub use admin::*;
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
http::HeaderMap,
|
||||
extract::FromRequestParts,
|
||||
http::{HeaderMap, request::Parts},
|
||||
response::{Html, IntoResponse, Response},
|
||||
};
|
||||
pub use health_check::*;
|
||||
@@ -19,6 +20,7 @@ pub use login::*;
|
||||
pub use posts::*;
|
||||
use rand::{Rng, distr::Alphanumeric};
|
||||
use reqwest::StatusCode;
|
||||
use serde::de::DeserializeOwned;
|
||||
pub use subscriptions::*;
|
||||
pub use subscriptions_confirm::*;
|
||||
pub use unsubscribe::*;
|
||||
@@ -61,6 +63,8 @@ pub enum AppError {
|
||||
FormError(#[source] anyhow::Error),
|
||||
#[error("Authentication is required.")]
|
||||
NotAuthenticated,
|
||||
#[error("Handler extractor failed.")]
|
||||
Extractor(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for AppError {
|
||||
@@ -124,6 +128,7 @@ impl IntoResponse for AppError {
|
||||
headers.insert("HX-Redirect", "/login".parse().unwrap());
|
||||
(StatusCode::OK, headers).into_response()
|
||||
}
|
||||
AppError::Extractor(_) => not_found_html(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,6 +160,50 @@ impl From<AuthError> for AppError {
|
||||
}
|
||||
|
||||
pub async fn not_found() -> Response {
|
||||
let template = HtmlTemplate(NotFoundTemplate);
|
||||
(StatusCode::NOT_FOUND, template).into_response()
|
||||
(StatusCode::NOT_FOUND, not_found_html()).into_response()
|
||||
}
|
||||
|
||||
pub fn not_found_html() -> Response {
|
||||
let template = HtmlTemplate(NotFoundTemplate);
|
||||
template.into_response()
|
||||
}
|
||||
|
||||
pub struct Path<T>(T);
|
||||
|
||||
impl<T, S> FromRequestParts<S> for Path<T>
|
||||
where
|
||||
T: DeserializeOwned + Send,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = AppError;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
match axum::extract::Path::<T>::from_request_parts(parts, state).await {
|
||||
Ok(value) => Ok(Self(value.0)),
|
||||
Err(rejection) => Err(AppError::Extractor(anyhow::anyhow!(
|
||||
"Path rejection: {:?}",
|
||||
rejection
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Query<T>(pub T);
|
||||
|
||||
impl<T, S> FromRequestParts<S> for Query<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
S: Send + Sync,
|
||||
{
|
||||
type Rejection = AppError;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
match axum::extract::Query::<T>::from_request_parts(parts, state).await {
|
||||
Ok(value) => Ok(Self(value.0)),
|
||||
Err(rejection) => Err(AppError::Extractor(anyhow::anyhow!(
|
||||
"Query rejection: {:?}",
|
||||
rejection
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::{
|
||||
authentication::AuthenticatedUser,
|
||||
idempotency::{IdempotencyKey, save_response, try_processing},
|
||||
routes::{AdminError, AppError, EmailType, enqueue_delivery_tasks, insert_newsletter_issue},
|
||||
routes::{
|
||||
AdminError, AppError, EmailType, Path, enqueue_delivery_tasks, insert_newsletter_issue,
|
||||
},
|
||||
startup::AppState,
|
||||
templates::{MessageTemplate, NewPostEmailTemplate},
|
||||
};
|
||||
@@ -9,7 +11,7 @@ use anyhow::Context;
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
Extension, Form,
|
||||
extract::{Path, State},
|
||||
extract::State,
|
||||
response::{Html, IntoResponse, Response},
|
||||
};
|
||||
use chrono::Utc;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::{
|
||||
domain::SubscriberEntry,
|
||||
routes::AppError,
|
||||
routes::{AppError, Path, Query},
|
||||
startup::AppState,
|
||||
templates::{MessageTemplate, SubListTemplate},
|
||||
};
|
||||
use anyhow::Context;
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
extract::State,
|
||||
response::{Html, IntoResponse, Response},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use crate::{
|
||||
domain::PostEntry,
|
||||
routes::{AppError, not_found},
|
||||
routes::{AppError, Path, Query, not_found_html},
|
||||
startup::AppState,
|
||||
templates::{HtmlTemplate, PostListTemplate, PostTemplate, PostsTemplate},
|
||||
};
|
||||
use anyhow::Context;
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
extract::{Path, Query, State},
|
||||
extract::State,
|
||||
response::{Html, IntoResponse, Redirect, Response},
|
||||
};
|
||||
use sqlx::PgPool;
|
||||
@@ -90,7 +90,7 @@ pub async fn see_post(
|
||||
let template = HtmlTemplate(PostTemplate { post });
|
||||
Ok(template.into_response())
|
||||
} else {
|
||||
Ok(not_found().await)
|
||||
Ok(not_found_html())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use crate::{routes::generate_token, startup::AppState, templates::ConfirmTemplate};
|
||||
use crate::{
|
||||
routes::{Query, generate_token},
|
||||
startup::AppState,
|
||||
templates::ConfirmTemplate,
|
||||
};
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
extract::{Query, State},
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
response::{Html, IntoResponse, Response},
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<div class="text-sm text-amber-800">
|
||||
<p>You will receive an email with an confirmation link.</p>
|
||||
<p>You will receive an email with a confirmation link.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user