Administrator privileges to get and delete subscribers
Some checks failed
Rust / Test (push) Has been cancelled
Rust / Rustfmt (push) Has been cancelled
Rust / Clippy (push) Has been cancelled
Rust / Code coverage (push) Has been cancelled

This commit is contained in:
Alphonse Paix
2025-09-30 18:27:48 +02:00
parent b5b00152cd
commit 3e81c27ab3
12 changed files with 2790 additions and 54 deletions

View File

@@ -6,11 +6,17 @@ mod posts;
mod subscribers;
use crate::{
authentication::AuthenticatedUser,
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},
};
use axum::{extract::Request, middleware::Next, response::Response};
pub use change_password::*;
pub use dashboard::*;
pub use logout::*;
@@ -55,10 +61,37 @@ pub async fn require_auth(
.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 });
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<Response, AppError> {
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())
}
}

View File

@@ -20,7 +20,9 @@ pub struct PasswordFormData {
}
pub async fn change_password(
Extension(AuthenticatedUser { user_id, username }): Extension<AuthenticatedUser>,
Extension(AuthenticatedUser {
user_id, username, ..
}): Extension<AuthenticatedUser>,
State(AppState {
connection_pool, ..
}): State<AppState>,

View File

@@ -31,7 +31,7 @@ pub async fn admin_dashboard(
State(AppState {
connection_pool, ..
}): State<AppState>,
Extension(AuthenticatedUser { username, .. }): Extension<AuthenticatedUser>,
Extension(user): Extension<AuthenticatedUser>,
) -> Result<Response, AppError> {
let stats = get_stats(&connection_pool).await?;
let idempotency_key_1 = Uuid::new_v4().to_string();
@@ -46,7 +46,7 @@ pub async fn admin_dashboard(
.context("Could not fetch total subscribers count from the database.")?;
let max_page = get_max_page(count);
let template = DashboardTemplate {
username,
user,
idempotency_key_1,
idempotency_key_2,
stats,

View File

@@ -48,7 +48,7 @@ pub async fn post_login(
password: form.password,
};
tracing::Span::current().record("username", tracing::field::display(&credentials.username));
let user_id = validate_credentials(credentials, &connection_pool).await?;
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.")?;
@@ -60,6 +60,10 @@ pub async fn post_login(
.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());