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")