pub mod change_password; pub mod dashboard; pub mod newsletters; use crate::{routes::error_chain_fmt, session_state::TypedSession, templates::ErrorTemplate}; use askama::Template; use axum::{ Json, response::{Html, IntoResponse, Redirect, Response}, }; pub use change_password::*; pub use dashboard::*; pub use newsletters::*; use reqwest::StatusCode; #[derive(thiserror::Error)] pub enum AdminError { #[error("Something went wrong.")] UnexpectedError(#[from] anyhow::Error), #[error("Trying to access admin dashboard without authentication.")] NotAuthenticated, #[error("Updating password failed.")] ChangePassword(String), #[error("Could not publish newsletter.")] Publish(#[source] anyhow::Error), #[error("The idempotency key was invalid.")] Idempotency(String), } impl std::fmt::Debug for AdminError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { error_chain_fmt(self, f) } } impl IntoResponse for AdminError { fn into_response(self) -> Response { #[derive(serde::Serialize)] struct ErrorResponse<'a> { message: &'a str, } tracing::error!("{:?}", self); match &self { AdminError::UnexpectedError(_) => ( StatusCode::INTERNAL_SERVER_ERROR, Json(ErrorResponse { message: "An internal server error occured.", }), ) .into_response(), AdminError::NotAuthenticated => Redirect::to("/login").into_response(), AdminError::ChangePassword(e) => { let template = ErrorTemplate { error_message: e.to_owned(), }; Html(template.render().unwrap()).into_response() } AdminError::Publish(e) => { let template = ErrorTemplate { error_message: e.to_string(), }; Html(template.render().unwrap()).into_response() } AdminError::Idempotency(e) => { (StatusCode::BAD_REQUEST, Json(ErrorResponse { message: e })).into_response() } } } } #[tracing::instrument(name = "Logging out", skip(session))] pub async fn logout(session: TypedSession) -> Result { session.clear().await; Ok(Redirect::to("/login").into_response()) }