//! AI model sync endpoint for admin. use actix_web::{HttpRequest, HttpResponse, Result, web}; use service::AppService; use crate::error::ApiError; use crate::ApiResponse; use service::error::AppError; /// Validate the `x-admin-api-key` header against ADMIN_API_SHARED_KEY env var. fn validate_admin_key(req: &HttpRequest) -> Result<(), ApiError> { let expected = std::env::var("ADMIN_API_SHARED_KEY").ok(); let Some(expected) = expected else { return Err(ApiError(AppError::InternalServerError( "ADMIN_API_SHARED_KEY not configured".into(), ))); }; let provided = req .headers() .get("x-admin-api-key") .and_then(|v| v.to_str().ok()) .ok_or(ApiError(AppError::Unauthorized))?; if provided != expected { return Err(ApiError(AppError::Unauthorized)); } Ok(()) } #[utoipa::path( post, path = "/api/admin/ai/sync", responses( (status = 200, description = "Sync result", body = ApiResponse), (status = 401, description = "Invalid or missing admin API key"), (status = 500, description = "Sync failed"), ), tag = "Admin" )] pub async fn admin_sync_models( req: HttpRequest, service: web::Data, ) -> Result { validate_admin_key(&req)?; let session = session::Session::no_op(); let resp = service.sync_upstream_models(&session).await?; Ok(ApiResponse::ok(resp).to_response()) }