From 0533b5d471534275fc2643aca1f3cec4e08f6ca3 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sat, 11 Apr 2026 19:44:54 -0400 Subject: [PATCH] better error handling for billing endpoint --- .../web/storyteller_web/src/docs/api_doc.rs | 5 +- .../list_active_user_subscriptions_handler.rs | 83 ++++++------------- 2 files changed, 26 insertions(+), 62 deletions(-) diff --git a/crates/service/web/storyteller_web/src/docs/api_doc.rs b/crates/service/web/storyteller_web/src/docs/api_doc.rs index 99c80feb26..a81f23c0d7 100644 --- a/crates/service/web/storyteller_web/src/docs/api_doc.rs +++ b/crates/service/web/storyteller_web/src/docs/api_doc.rs @@ -154,7 +154,7 @@ use artcraft_api_defs::users::edit_email::{EditEmailRequest, EditEmailResponse}; use artcraft_api_defs::users::edit_username::{EditUsernameRequest, EditUsernameResponse}; use billing_component::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_error::CreateCheckoutSessionError; use billing_component::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_json_handler::*; -use billing_component::users::http_endpoints::list_active_user_subscriptions_handler::*; +use crate::http_server::endpoints::billing_fakeyou::list_active_user_subscriptions_handler::*; use crate::http_server::endpoints::service::status_alert_handler::*; use crate::http_server::endpoints::stats::get_unified_queue_stats_handler::*; use crate::http_server::endpoints::studio_gen2::enqueue_studio_gen2_handler::*; @@ -318,7 +318,7 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux #[openapi( paths( billing_component::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_json_handler::stripe_create_checkout_session_json_handler, - billing_component::users::http_endpoints::list_active_user_subscriptions_handler::list_active_user_subscriptions_handler, + crate::http_server::endpoints::billing_fakeyou::list_active_user_subscriptions_handler::list_active_user_subscriptions_handler, crate::http_server::deprecated_endpoints::conversion::enqueue_fbx_to_gltf_handler::enqueue_fbx_to_gltf_handler, crate::http_server::deprecated_endpoints::engine::create_scene_handler::create_scene_handler, crate::http_server::deprecated_endpoints::workflows::enqueue::enqueue_face_fusion_workflow_handler::enqueue_face_fusion_workflow_handler, @@ -871,7 +871,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux InferenceJobStatusResponsePayload, InferenceJobTokenType, LegacyQueueDetails, - ListActiveUserSubscriptionsError, ListActiveUserSubscriptionsResponse, ListAvailableWeightsQuery, ListAvailableWeightsSuccessResponse, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/billing_fakeyou/list_active_user_subscriptions_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/billing_fakeyou/list_active_user_subscriptions_handler.rs index 27c8bbacf6..7cf3fcdac9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/billing_fakeyou/list_active_user_subscriptions_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/billing_fakeyou/list_active_user_subscriptions_handler.rs @@ -1,12 +1,13 @@ -use actix_http::StatusCode; -use actix_web::{web, HttpRequest, HttpResponse, ResponseError}; +use actix_web::web::Json; +use actix_web::{web, HttpRequest}; use component_traits::traits::internal_user_lookup::InternalUserLookup; use enums::common::payments_namespace::PaymentsNamespace; -use http_server_common::response::serialize_as_json_error::serialize_as_json_error; -use log::error; +use log::warn; use utoipa::ToSchema; -// =============== Success Response =============== +use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError; + +// =============== Response =============== #[derive(Serialize, ToSchema)] pub struct ListActiveUserSubscriptionsResponse { @@ -24,78 +25,42 @@ pub struct SubscriptionProductKey { pub product_slug: String, } -// =============== Error Response =============== - -#[derive(Debug, Serialize, Eq, PartialEq, Copy, Clone, ToSchema)] -pub enum ListActiveUserSubscriptionsError { - InvalidSession, - ServerError, -} - -impl ResponseError for ListActiveUserSubscriptionsError { - fn status_code(&self) -> StatusCode { - match *self { - ListActiveUserSubscriptionsError::InvalidSession => StatusCode::UNAUTHORIZED, - ListActiveUserSubscriptionsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - serialize_as_json_error(self) - } -} - -// NB: Not using derive_more::Display since Clion doesn't understand it. -impl std::fmt::Display for ListActiveUserSubscriptionsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) - } -} - #[utoipa::path( get, tag = "Billing", path = "/v1/billing/active_subscriptions", responses( (status = 200, description = "Success response", body = ListActiveUserSubscriptionsResponse), - (status = 500, description = "Server error", body = ListActiveUserSubscriptionsError), + (status = 401, description = "Not authorized"), + (status = 500, description = "Server error"), ), )] pub async fn list_active_user_subscriptions_handler( http_request: HttpRequest, internal_user_lookup: web::Data, -) -> Result -{ +) -> Result, AdvancedCommonWebError> { let maybe_user_metadata = internal_user_lookup - .lookup_user_from_http_request(&http_request) - .await - .map_err(|err| { - error!("Error looking up user: {:?}", err); - ListActiveUserSubscriptionsError::ServerError // NB: This was probably *our* fault. - })?; + .lookup_user_from_http_request(&http_request) + .await + .map_err(|err| { + warn!("Error looking up user: {:?}", err); + AdvancedCommonWebError::from_error + })?; - // NB: Our integration relies on an internal user token being present. let user_metadata = match maybe_user_metadata { - None => return Err(ListActiveUserSubscriptionsError::InvalidSession), + None => return Err(AdvancedCommonWebError::NotAuthorized), Some(user_metadata) => user_metadata, }; - let response = ListActiveUserSubscriptionsResponse { + Ok(Json(ListActiveUserSubscriptionsResponse { success: true, maybe_loyalty_program: user_metadata.maybe_loyalty_program_key, active_subscriptions: user_metadata.existing_subscription_keys - .into_iter() - .map(|sub| SubscriptionProductKey { - namespace: sub.internal_subscription_namespace, - product_slug: sub.internal_subscription_product_slug, - }) - .collect(), - }; - - let body = serde_json::to_string(&response) - .map_err(|_e| ListActiveUserSubscriptionsError::ServerError)?; - - Ok(HttpResponse::Ok() - .content_type("application/json") - .body(body)) + .into_iter() + .map(|sub| SubscriptionProductKey { + namespace: sub.internal_subscription_namespace, + product_slug: sub.internal_subscription_product_slug, + }) + .collect(), + })) }