diff --git a/apps/users/src/handlers/approvals.rs b/apps/users/src/handlers/approvals.rs index 297782a..9d12673 100644 --- a/apps/users/src/handlers/approvals.rs +++ b/apps/users/src/handlers/approvals.rs @@ -8,13 +8,18 @@ use axum::{ }; use contracts::auth_middleware::{require_admin, AuthUser}; use db::models::job::JobRepository; +use db::models::onboarding_state::OnboardingStateRepository; use db::models::requirement::RequirementRepository; +use db::models::role::RoleRepository; +use db::models::user::UserRepository; use serde::Deserialize; use uuid::Uuid; pub fn router() -> Router { Router::new() .route("/", get(list_pending)) + // Submission viewer: GET /api/admin/approvals/submission/{user_id}?roleKey=PHOTOGRAPHER + .route("/submission/{user_id}", get(get_submission)) .route("/profiles/company/{user_id}/approve", post(approve_company_profile)) .route("/profiles/company/{user_id}/reject", post(reject_company_profile)) .route("/profiles/customer/{user_id}/approve", post(approve_customer_profile)) @@ -27,6 +32,67 @@ pub fn router() -> Router { .route("/requirements/{id}/reject", post(reject_requirement)) } +#[derive(Deserialize)] +pub struct RoleKeyQuery { + #[serde(rename = "roleKey", alias = "role_key")] + pub role_key: Option, +} + +/// GET /api/admin/approvals/submission/{user_id}?roleKey=PHOTOGRAPHER +/// Returns the user info + their onboarding state (submitted form answers) for admin review. +async fn get_submission( + auth: AuthUser, + State(state): State, + Path(user_id): Path, + Query(q): Query, +) -> impl IntoResponse { + if let Err(e) = require_admin(&auth) { + return e.into_response(); + } + + // Fetch user + let user = match UserRepository::get_by_id(&state.pool, user_id).await { + Ok(u) => u, + Err(_) => return (StatusCode::NOT_FOUND, "User not found").into_response(), + }; + + // Fetch onboarding state (for the given roleKey, or the user's active role) + let role_key = q.role_key.filter(|k| !k.is_empty()); + let onboarding = if let Some(ref rk) = role_key { + match RoleRepository::get_by_key(&state.pool, rk).await { + Ok(role) => OnboardingStateRepository::get(&state.pool, user_id, role.id) + .await + .unwrap_or(None), + Err(_) => None, + } + } else { + None + }; + + ( + StatusCode::OK, + Json(serde_json::json!({ + "user": { + "id": user.id, + "name": user.full_name, + "email": user.email, + "phone": user.phone, + "status": user.status, + "email_verified": user.email_verified, + "created_at": user.created_at, + }, + "role_key": role_key, + "onboarding": onboarding.map(|s| serde_json::json!({ + "status": s.status, + "progress_json": s.progress_json, + "completed_at": s.completed_at, + "updated_at": s.updated_at, + })), + })), + ) + .into_response() +} + #[derive(Deserialize)] pub struct ListQuery { pub page: Option,