use axum::{ extract::Query, http::StatusCode, response::{IntoResponse, Redirect}, routing::{get, post}, Form, Router, }; use axum_messages::{Message, Messages}; use serde::{Deserialize, Serialize}; use crate::models::{AuthSession, Credentials}; #[derive(Serialize)] pub struct LoginTemplate { messages: Vec, next: Option, } // This allows us to extract the "next" field from the query string. We use this // to redirect after log in. #[derive(Debug, Deserialize)] pub struct NextUrl { next: Option, } pub fn routes() -> Router where { Router::new() .route("/login", post(self::post::login)) .route("/login", get(self::get::login::)) .route("/logout", post(self::post::logout)) } mod post { use super::*; pub async fn login( mut auth_session: AuthSession, messages: Messages, Form(creds): Form, ) -> impl IntoResponse { let user = match auth_session.authenticate(creds.clone()).await { Ok(Some(user)) => user, Ok(None) => { messages.error("Invalid credentials"); let mut login_url = "/depot/login".to_string(); if let Some(next) = creds.next { login_url = format!("{}?next={}", login_url, next); }; return Redirect::to(&login_url).into_response(); } Err(_) => return StatusCode::INTERNAL_SERVER_ERROR.into_response(), }; if auth_session.login(&user).await.is_err() { return StatusCode::INTERNAL_SERVER_ERROR.into_response(); } messages.success(format!("Successfully logged in as {}", user.username)); if let Some(ref next) = creds.next { Redirect::to(next) } else { Redirect::to("/") } .into_response() } pub async fn logout(mut auth_session: AuthSession) -> impl IntoResponse { match auth_session.logout().await { Ok(_) => Redirect::to("/depot/login").into_response(), Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(), } } } mod get { use super::*; use axum::extract::State; pub async fn login( messages: Messages, admin: State, Query(NextUrl { next }): Query, ) -> impl IntoResponse { let templates = admin.get_templates(); let context = LoginTemplate { messages: messages.into_iter().collect(), next, }; templates.render_html("depot/login.html", context) } } // this was taken from the axum_login examples and modified. Redirection might need reverse-routing support.