mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
fix billing pages (#1342)
This commit is contained in:
@@ -10,7 +10,6 @@ use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_sess
|
||||
use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_json_handler::stripe_create_customer_portal_session_json_handler;
|
||||
use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_redirect_handler::stripe_create_customer_portal_session_redirect_handler;
|
||||
use crate::stripe::http_endpoints::webhook::stripe_webhook_handler::stripe_webhook_handler;
|
||||
use crate::users::http_endpoints::list_active_user_subscriptions_handler::list_active_user_subscriptions_handler;
|
||||
|
||||
pub fn add_suggested_stripe_billing_routes<T, B> (app: App<T>) -> App<T>
|
||||
where
|
||||
@@ -23,13 +22,9 @@ pub fn add_suggested_stripe_billing_routes<T, B> (app: App<T>) -> App<T>
|
||||
InitError = (),
|
||||
>,
|
||||
{
|
||||
// NB: The /v1/billing/active_subscriptions route has been moved to
|
||||
// storyteller-web (billing_fakeyou_routes). Only Stripe routes remain here.
|
||||
app.service(web::scope("/v1")
|
||||
.service(web::scope("/billing")
|
||||
.service(web::resource("/active_subscriptions")
|
||||
.route(web::get().to(list_active_user_subscriptions_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::scope("/stripe")
|
||||
.service(web::resource("/webhook")
|
||||
.route(web::post().to(stripe_webhook_handler))
|
||||
|
||||
@@ -19,4 +19,3 @@
|
||||
pub mod default_routes;
|
||||
pub mod paypal;
|
||||
pub mod stripe;
|
||||
pub mod users;
|
||||
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{web, HttpRequest, HttpResponse, ResponseError};
|
||||
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 utoipa::ToSchema;
|
||||
|
||||
// =============== Success Response ===============
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ListActiveUserSubscriptionsResponse {
|
||||
pub success: bool,
|
||||
pub maybe_loyalty_program: Option<String>,
|
||||
pub active_subscriptions: Vec<SubscriptionProductKey>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct SubscriptionProductKey {
|
||||
/// This should always be "fakeyou".
|
||||
pub namespace: PaymentsNamespace,
|
||||
|
||||
/// Possible values: fakeyou_plus, fakeyou_pro, fakeyou_elite, etc.
|
||||
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),
|
||||
),
|
||||
)]
|
||||
pub async fn list_active_user_subscriptions_handler(
|
||||
http_request: HttpRequest,
|
||||
internal_user_lookup: web::Data<dyn InternalUserLookup>,
|
||||
) -> Result<HttpResponse, ListActiveUserSubscriptionsError>
|
||||
{
|
||||
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.
|
||||
})?;
|
||||
|
||||
// NB: Our integration relies on an internal user token being present.
|
||||
let user_metadata = match maybe_user_metadata {
|
||||
None => return Err(ListActiveUserSubscriptionsError::InvalidSession),
|
||||
Some(user_metadata) => user_metadata,
|
||||
};
|
||||
|
||||
let response = 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))
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod list_active_user_subscriptions_handler;
|
||||
@@ -1 +0,0 @@
|
||||
pub mod http_endpoints;
|
||||
@@ -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,
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
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 log::warn;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::http_server::common_responses::advanced_common_web_error::AdvancedCommonWebError;
|
||||
|
||||
// =============== Response ===============
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ListActiveUserSubscriptionsResponse {
|
||||
pub success: bool,
|
||||
pub maybe_loyalty_program: Option<String>,
|
||||
pub active_subscriptions: Vec<SubscriptionProductKey>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct SubscriptionProductKey {
|
||||
/// This should always be "fakeyou".
|
||||
pub namespace: PaymentsNamespace,
|
||||
|
||||
/// Possible values: fakeyou_plus, fakeyou_pro, fakeyou_elite, etc.
|
||||
pub product_slug: String,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Billing",
|
||||
path = "/v1/billing/active_subscriptions",
|
||||
responses(
|
||||
(status = 200, description = "Success response", body = ListActiveUserSubscriptionsResponse),
|
||||
(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<dyn InternalUserLookup>,
|
||||
) -> Result<Json<ListActiveUserSubscriptionsResponse>, AdvancedCommonWebError> {
|
||||
let maybe_user_metadata = internal_user_lookup
|
||||
.lookup_user_from_http_request(&http_request)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("Error looking up user: {:?}", err);
|
||||
AdvancedCommonWebError::from_error
|
||||
})?;
|
||||
|
||||
let user_metadata = match maybe_user_metadata {
|
||||
None => return Err(AdvancedCommonWebError::NotAuthorized),
|
||||
Some(user_metadata) => user_metadata,
|
||||
};
|
||||
|
||||
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(),
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod list_active_user_subscriptions_handler;
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod analytics;
|
||||
pub mod app_state;
|
||||
pub mod beta_keys;
|
||||
pub mod billing_fakeyou;
|
||||
pub mod characters;
|
||||
pub mod comments;
|
||||
pub mod credits;
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ mod tests {
|
||||
reference_image_media_tokens: None,
|
||||
reference_video_media_tokens: None,
|
||||
reference_audio_media_tokens: None,
|
||||
reference_character_tokens: None,
|
||||
resolution,
|
||||
aspect_ratio,
|
||||
quality: None,
|
||||
|
||||
+4
-2
@@ -1,4 +1,5 @@
|
||||
use crate::http_server::routes::application_routes::analytics_routes::add_analytics_routes;
|
||||
use crate::http_server::routes::application_routes::billing_fakeyou_routes::add_billing_fakeyou_routes;
|
||||
use crate::http_server::routes::application_routes::character_routes::add_character_routes;
|
||||
use crate::http_server::routes::application_routes::comments_routes::add_comments_routes;
|
||||
use crate::http_server::routes::application_routes::credits_routes::add_credits_routes;
|
||||
@@ -74,8 +75,9 @@ where
|
||||
app = add_stripe_artcraft_routes(app); // /v1/stripe_artcraft/...
|
||||
app = add_subscription_routes(app); // /v1/subscriptions/...
|
||||
|
||||
// FakeYou Billing component - still necessary for FakeYou monetization
|
||||
app = add_suggested_stripe_billing_routes(app); // /stripe, billing, webhooks, etc.
|
||||
// FakeYou Billing
|
||||
app = add_billing_fakeyou_routes(app); // /v1/billing/active_subscriptions
|
||||
app = add_suggested_stripe_billing_routes(app); // /stripe, webhooks, etc.
|
||||
|
||||
app
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
use crate::http_server::endpoints::billing_fakeyou::list_active_user_subscriptions_handler::list_active_user_subscriptions_handler;
|
||||
use actix_http::body::MessageBody;
|
||||
use actix_service::ServiceFactory;
|
||||
use actix_web::dev::{ServiceRequest, ServiceResponse};
|
||||
use actix_web::{web, App, Error, HttpResponse};
|
||||
|
||||
pub fn add_billing_fakeyou_routes<T, B>(app: App<T>) -> App<T>
|
||||
where
|
||||
B: MessageBody,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
>,
|
||||
{
|
||||
app.service(web::scope("/v1")
|
||||
.service(web::scope("/billing")
|
||||
.service(web::resource("/active_subscriptions")
|
||||
.route(web::get().to(list_active_user_subscriptions_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod analytics_routes;
|
||||
mod billing_fakeyou_routes;
|
||||
mod character_routes;
|
||||
mod comments_routes;
|
||||
mod credits_routes;
|
||||
|
||||
Reference in New Issue
Block a user