use crate::{ authentication::{Credentials, validate_credentials}, routes::AppError, session_state::TypedSession, startup::AppState, templates::LoginTemplate, }; use anyhow::Context; use askama::Template; use axum::{ Form, extract::State, http::HeaderMap, response::{Html, IntoResponse, Response}, }; use axum::{http::StatusCode, response::Redirect}; use secrecy::SecretString; #[derive(serde::Deserialize)] pub struct LoginFormData { username: String, password: SecretString, } pub async fn get_login(session: TypedSession) -> Result { if session .get_user_id() .await .context("Failed to retrieve user id from data store.")? .is_some() { Ok(Redirect::to("/admin/dashboard").into_response()) } else { Ok(Html(LoginTemplate.render().unwrap()).into_response()) } } #[tracing::instrument(name = "Authenticating user", skip_all, fields(name = %form.username))] pub async fn post_login( session: TypedSession, State(AppState { connection_pool, .. }): State, Form(form): Form, ) -> Result { let credentials = Credentials { username: form.username.clone(), password: form.password, }; tracing::Span::current().record("username", tracing::field::display(&credentials.username)); let (user_id, role) = validate_credentials(credentials, &connection_pool).await?; tracing::Span::current().record("user_id", tracing::field::display(&user_id)); session.renew().await.context("Failed to renew session.")?; session .insert_user_id(user_id) .await .context("Failed to insert user id in session data store.")?; session .insert_username(form.username) .await .context("Failed to insert username in session data store.")?; session .insert_role(role) .await .context("Failed to insert role in session data store.")?; let mut headers = HeaderMap::new(); headers.insert("HX-Redirect", "/admin/dashboard".parse().unwrap()); Ok((StatusCode::OK, headers).into_response()) }