From bb503f3ce8f4d2092bd37fb789af9c88b9d75006 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 3 Jun 2026 00:00:45 +0200 Subject: [PATCH] feat: AdminApiUser extractor for Bearer-token admin endpoints --- crates/presentation/src/extractors.rs | 28 ++++++++++++++++++++++ crates/presentation/src/handlers/wrapup.rs | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/presentation/src/extractors.rs b/crates/presentation/src/extractors.rs index 9ba2a4d..e6209c0 100644 --- a/crates/presentation/src/extractors.rs +++ b/crates/presentation/src/extractors.rs @@ -98,6 +98,34 @@ where } } +pub struct AdminApiUser(pub UserId); + +impl FromRequestParts for AdminApiUser +where + AppState: FromRef, + S: Send + Sync, +{ + type Rejection = ApiError; + + async fn from_request_parts(parts: &mut Parts, state: &S) -> Result { + let AuthenticatedUser(user_id) = + AuthenticatedUser::from_request_parts(parts, state).await?; + let app_state = AppState::from_ref(state); + let user = app_state + .app_ctx + .repos + .user + .find_by_id(&user_id) + .await + .map_err(|e| ApiError(e))? + .ok_or_else(|| ApiError(DomainError::NotFound("user not found".into())))?; + match user.role() { + domain::models::UserRole::Admin => Ok(AdminApiUser(user_id)), + _ => Err(ApiError(DomainError::Forbidden("admin only".into()))), + } + } +} + pub struct AdminUser(pub UserId); impl FromRequestParts for AdminUser diff --git a/crates/presentation/src/handlers/wrapup.rs b/crates/presentation/src/handlers/wrapup.rs index 4b5ac2f..f087688 100644 --- a/crates/presentation/src/handlers/wrapup.rs +++ b/crates/presentation/src/handlers/wrapup.rs @@ -19,7 +19,7 @@ use domain::value_objects::WrapUpId; use crate::{ csrf::CsrfToken, errors::ApiError, - extractors::{AdminUser, AuthenticatedUser, OptionalCookieUser}, + extractors::{AdminApiUser, AuthenticatedUser, OptionalCookieUser}, render::render_page, state::AppState, }; @@ -53,7 +53,7 @@ fn record_to_dto(r: &WrapUpRecord) -> WrapUpStatusResponse { )] pub async fn post_generate( State(state): State, - _admin: AdminUser, + _admin: AdminApiUser, Json(req): Json, ) -> Result, ApiError> { let start = NaiveDate::parse_from_str(&req.start_date, "%Y-%m-%d")