Fix login/signup redirection

HTMX needs special treatment for redirects on submit.
This commit is contained in:
Tyler Hallada 2023-09-26 01:48:05 -04:00
parent 6fd2f150a0
commit 81b4ef860e
4 changed files with 39 additions and 4 deletions

View File

@ -1,4 +1,4 @@
use axum::response::{IntoResponse, Redirect, Response}; use axum::response::{IntoResponse, Response};
use axum::{extract::State, Form}; use axum::{extract::State, Form};
use maud::html; use maud::html;
use serde::Deserialize; use serde::Deserialize;
@ -7,6 +7,7 @@ use sqlx::PgPool;
use crate::auth::verify_password; use crate::auth::verify_password;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::htmx::HXRedirect;
use crate::partials::login_form::{login_form, LoginFormProps}; use crate::partials::login_form::{login_form, LoginFormProps};
use crate::{ use crate::{
models::user::{AuthContext, User}, models::user::{AuthContext, User},
@ -65,5 +66,5 @@ pub async fn post(
auth.login(&user) auth.login(&user)
.await .await
.map_err(|_| Error::InternalServerError)?; .map_err(|_| Error::InternalServerError)?;
Ok(Redirect::to("/").into_response()) Ok(HXRedirect::to("/").into_response())
} }

View File

@ -1,4 +1,4 @@
use axum::response::{IntoResponse, Redirect, Response}; use axum::response::{IntoResponse, Response};
use axum::{extract::State, Form}; use axum::{extract::State, Form};
use maud::html; use maud::html;
use serde::Deserialize; use serde::Deserialize;
@ -6,6 +6,7 @@ use serde_with::{serde_as, NoneAsEmptyString};
use sqlx::PgPool; use sqlx::PgPool;
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::htmx::HXRedirect;
use crate::models::user::{AuthContext, CreateUser, User}; use crate::models::user::{AuthContext, CreateUser, User};
use crate::partials::layout::Layout; use crate::partials::layout::Layout;
use crate::partials::signup_form::{signup_form, SignupFormProps}; use crate::partials::signup_form::{signup_form, SignupFormProps};
@ -107,5 +108,5 @@ pub async fn post(
auth.login(&user) auth.login(&user)
.await .await
.map_err(|_| Error::InternalServerError)?; .map_err(|_| Error::InternalServerError)?;
Ok(Redirect::to("/").into_response()) Ok(HXRedirect::to("/").into_response())
} }

32
src/htmx.rs Normal file
View File

@ -0,0 +1,32 @@
use axum::response::{IntoResponse, Response};
use http::header::{HeaderName, HeaderValue};
use http::StatusCode;
#[allow(clippy::declare_interior_mutable_const)]
const HX_LOCATION: HeaderName = HeaderName::from_static("hx-location");
/// Sets the HX-Location header so that HTMX redirects to the given URI. Unlike
/// axum::response::Redirect this does not return a 300-level status code (instead, a 200 status
/// code) so that HTMX can see the HX-Location header before the browser handles the redirect.
#[derive(Debug, Clone)]
pub struct HXRedirect {
location: HeaderValue,
}
impl HXRedirect {
pub fn to(uri: &str) -> Self {
Self {
location: HeaderValue::try_from(uri).expect("URI isn't a valid header value"),
}
}
}
impl IntoResponse for HXRedirect {
fn into_response(self) -> Response {
(
StatusCode::OK,
[(HX_LOCATION, self.location)],
)
.into_response()
}
}

View File

@ -6,6 +6,7 @@ pub mod domain_locks;
pub mod error; pub mod error;
pub mod handlers; pub mod handlers;
pub mod headers; pub mod headers;
pub mod htmx;
pub mod log; pub mod log;
pub mod models; pub mod models;
pub mod partials; pub mod partials;