mod change_password; mod dashboard; mod logout; mod newsletters; mod posts; mod subscribers; use crate::{ authentication::{AuthenticatedUser, Role}, routes::{AppError, error_chain_fmt}, session_state::TypedSession, templates::{HtmlTemplate, MessageTemplate}, }; use anyhow::Context; use axum::{ extract::Request, middleware::Next, response::{IntoResponse, Response}, }; pub use change_password::*; pub use dashboard::*; pub use logout::*; pub use newsletters::*; pub use posts::*; pub use subscribers::*; #[derive(thiserror::Error)] pub enum AdminError { #[error("Something went wrong while performing an admin action.")] UnexpectedError(#[from] anyhow::Error), #[error("Trying to access admin dashboard without authentication.")] NotAuthenticated, #[error("Updating password failed.")] ChangePassword(anyhow::Error), #[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) } } pub async fn require_auth( session: TypedSession, mut request: Request, next: Next, ) -> Result { let user_id = session .get_user_id() .await .map_err(|e| AdminError::UnexpectedError(e.into()))? .ok_or(AdminError::NotAuthenticated)?; let username = session .get_username() .await .map_err(|e| AdminError::UnexpectedError(e.into()))? .ok_or(AdminError::UnexpectedError(anyhow::anyhow!( "Could not find username in session." )))?; let role = session .get_role() .await .context("Error retrieving user role in session.")? .ok_or(anyhow::anyhow!("Could not find user role in session."))?; request.extensions_mut().insert(AuthenticatedUser { user_id, username, role, }); Ok(next.run(request).await) } pub async fn require_admin( session: TypedSession, request: Request, next: Next, ) -> Result { if let Role::Admin = session .get_role() .await .context("Error retrieving user role in session.")? .ok_or(anyhow::anyhow!("Could not find user role in session."))? { Ok(next.run(request).await) } else { Ok(HtmlTemplate(MessageTemplate::error( "This action requires administrator privileges.".into(), )) .into_response()) } }