mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 01:18:34 +00:00
undo change
This commit is contained in:
1 parent
dffc831ce1
commit
6face4ab4f
5 files changed
+142
-45
No files matched your search
+140
-8
@@ -24,6 +24,7 @@ use user_traits_component::traits::internal_session_cache_purge::InternalSession
|
||||
|
||||
//use utoipa::ToSchema;
|
||||
|
||||
// /// Create a Stripe Checkout session and return the redirect URL in Json.
|
||||
// #[utoipa::path(
|
||||
// get,
|
||||
// tag = "Stripe (Artcraft)",
|
||||
@@ -35,10 +36,6 @@ use user_traits_component::traits::internal_session_cache_purge::InternalSession
|
||||
// (status = 200, description = "Success Delete", body = CreateCheckoutSessionSuccessResponse),
|
||||
// ),
|
||||
// )]
|
||||
|
||||
|
||||
/// Create a Stripe Checkout session *with* user signup and return the redirect URL in Json.
|
||||
/// If the user is already logged in, we just attach it to that record instead.
|
||||
pub async fn stripe_artcraft_create_subscription_session_handler(
|
||||
http_request: HttpRequest,
|
||||
request: Json<StripeArtcraftCreateSubscriptionCheckoutRequest>,
|
||||
@@ -85,10 +82,145 @@ pub async fn stripe_artcraft_create_subscription_session_handler(
|
||||
// NB: Our integration relies on an internal user token being present.
|
||||
let user_metadata = match maybe_user_metadata {
|
||||
None => return Err(CommonWebError::NotAuthorized),
|
||||
Some(user_metadata) => {
|
||||
|
||||
user_exists_case
|
||||
},
|
||||
Some(user_metadata) => user_metadata,
|
||||
};
|
||||
|
||||
// NB: Currently the stripe customer id field in the `users` table is only for FakeYou subscriptions,
|
||||
// so we need to look up any existing Artcraft subscription separately. This is needed to pre-fill
|
||||
// the Stripe billing form.
|
||||
let maybe_active_subscription = find_subscription_for_owner_user_using_connection(
|
||||
&user_metadata.user_token_typed,
|
||||
PaymentsNamespace::Artcraft,
|
||||
&mut mysql_connection
|
||||
).await.map_err(|err| {
|
||||
error!("Error looking up user's ({}) existing subscription: {:?}", &user_metadata.user_token_typed, err);
|
||||
CommonWebError::ServerError // NB: This was probably *our* fault.
|
||||
})?;
|
||||
|
||||
if maybe_active_subscription.is_some() {
|
||||
return Err(CommonWebError::BadInputWithSimpleMessage(
|
||||
"user already has an active subscription plan; use the portal to update the plan"
|
||||
.to_string()))
|
||||
}
|
||||
|
||||
// NB: This works, but it feels really weird to have the customer's old email shown in a
|
||||
// completely immutable state in the stripe checkout form.
|
||||
//
|
||||
// let maybe_inactive_subscription = find_possibly_inactive_first_subscription_for_owner_user_using_connection(
|
||||
// &user_metadata.user_token_typed,
|
||||
// PaymentsNamespace::Artcraft,
|
||||
// &mut mysql_connection
|
||||
// ).await.map_err(|err| {
|
||||
// error!("Error looking up user's ({}) possibly existing inactive subscription: {:?}",
|
||||
// &user_metadata.user_token_typed, err);
|
||||
// CommonWebError::ServerError // NB: This was probably *our* fault.
|
||||
// })?;
|
||||
// let maybe_existing_inactive_stripe_customer_id = maybe_inactive_subscription.as_ref()
|
||||
// .map(|sub| sub.stripe_customer_id.as_str());
|
||||
|
||||
let mut maybe_existing_stripe_customer_id = None;
|
||||
|
||||
let result = find_user_stripe_customer_link_using_connection(
|
||||
&user_metadata.user_token_typed,
|
||||
PaymentsNamespace::Artcraft,
|
||||
&mut mysql_connection
|
||||
).await;
|
||||
|
||||
// NB: Fail silently.
|
||||
if let Ok(Some(link)) = result {
|
||||
maybe_existing_stripe_customer_id = CustomerId::from_str(&link.stripe_customer_id).ok();
|
||||
} else if let Err(err) = result {
|
||||
warn!("Error looking up user's ({}) existing stripe customer link: {:?}", &user_metadata.user_token_typed, err);
|
||||
}
|
||||
|
||||
let success_url = stripe_config.checkout_success_url.clone();
|
||||
let cancel_url = stripe_config.checkout_cancel_url.clone();
|
||||
|
||||
let checkout_session = {
|
||||
// `client_reference_id`
|
||||
// Stripe Docs:
|
||||
// A unique string to reference the Checkout Session.
|
||||
// This can be a customer ID, a cart ID, or similar, and can be used to reconcile the session
|
||||
// with your internal systems.
|
||||
//
|
||||
// Our Notes:
|
||||
// This gets reported back in the Checkout Session (and related webhooks) as
|
||||
// `client_reference_id`. Passing the same ID on multiple checkouts does not unify or
|
||||
// cross-correlate customers and only seems to be metadata for the checkout session itself.
|
||||
// This is probably only useful for tracking checkout session engagement.
|
||||
//params.client_reference_id = Some("SOME_INTERNAL_ID");
|
||||
|
||||
// `customer_email`
|
||||
// Stripe Docs:
|
||||
// If provided, this value will be used when the Customer object is created. If not provided,
|
||||
// customers will be asked to enter their email address. Use this parameter to prefill
|
||||
// customer data if you already have an email on file. To access information about the
|
||||
// customer once a session is complete, use the customer field.
|
||||
//
|
||||
// Our Notes:
|
||||
// This does not look up previous customers with the same email and will not unify or
|
||||
// cross-correlate customers. By default the field will be un-editable in the checkout flow
|
||||
// if this is specified.
|
||||
//params.customer_email = Some("email@example.com");
|
||||
|
||||
let mut metadata = HashMap::new();
|
||||
|
||||
metadata.insert(STRIPE_ARTCRAFT_METADATA_USER_TOKEN.to_string(), user_metadata.user_token.to_string());
|
||||
|
||||
if let Some(username) = user_metadata.username.as_deref() {
|
||||
metadata.insert(STRIPE_ARTCRAFT_METADATA_USERNAME.to_string(), username.to_string());
|
||||
}
|
||||
|
||||
if let Some(user_email) = user_metadata.user_email.as_deref() {
|
||||
metadata.insert(STRIPE_ARTCRAFT_METADATA_EMAIL.to_string(), user_email.to_string());
|
||||
}
|
||||
|
||||
let mut checkout_builder = CreateCheckoutSession::new()
|
||||
.success_url(&success_url)
|
||||
.cancel_url(&cancel_url)
|
||||
.mode(CheckoutSessionMode::Subscription)
|
||||
.line_items(vec![
|
||||
CreateCheckoutSessionLineItems {
|
||||
price: Some(price_id.to_string()),
|
||||
quantity: Some(1),
|
||||
..Default::default()
|
||||
}
|
||||
])
|
||||
.saved_payment_method_options(CreateCheckoutSessionSavedPaymentMethodOptions {
|
||||
allow_redisplay_filters: Some(vec![
|
||||
CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Always,
|
||||
CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Limited,
|
||||
CreateCheckoutSessionSavedPaymentMethodOptionsAllowRedisplayFilters::Unspecified,
|
||||
]),
|
||||
// The user can choose to tick a checkbox that saves their card for redisplay later.
|
||||
payment_method_save: Some(CreateCheckoutSessionSavedPaymentMethodOptionsPaymentMethodSave::Enabled),
|
||||
})
|
||||
.allow_promotion_codes(true) // Allow promo codes / coupons
|
||||
.automatic_tax(CreateCheckoutSessionAutomaticTax {
|
||||
enabled: true, // This will ask for the customer's location
|
||||
liability: None,
|
||||
})
|
||||
.metadata(metadata.clone())
|
||||
.subscription_data(CreateCheckoutSessionSubscriptionData {
|
||||
metadata: Some(metadata),
|
||||
..Default::default()
|
||||
})
|
||||
;
|
||||
|
||||
if let Some(customer_id) = maybe_existing_stripe_customer_id {
|
||||
info!("Adding existing stripe customer id to checkout session: {}", customer_id.as_str());
|
||||
checkout_builder = checkout_builder.customer(customer_id);
|
||||
}
|
||||
|
||||
let checkout_session = checkout_builder
|
||||
.send(&stripe_config.client)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Stripe Error: {:?}", err);
|
||||
CommonWebError::ServerError
|
||||
})?;
|
||||
|
||||
checkout_session
|
||||
};
|
||||
|
||||
let url = checkout_session.url.ok_or(CommonWebError::ServerError)?;
|
||||
|
||||
+1
-1
@@ -12,7 +12,6 @@ use crate::http_server::session::http::http_user_session_manager::HttpUserSessio
|
||||
use crate::http_server::validations::is_reserved_username::is_reserved_username;
|
||||
use crate::http_server::validations::validate_passwords::validate_passwords;
|
||||
use crate::http_server::validations::validate_username::validate_username;
|
||||
use crate::util::email_to_gravatar::email_to_gravatar;
|
||||
use crate::util::enroll_in_studio::enroll_in_studio;
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
@@ -29,6 +28,7 @@ use password::bcrypt_hash_password::bcrypt_hash_password;
|
||||
use sqlx::MySqlPool;
|
||||
use tokens::tokens::user_sessions::UserSessionToken;
|
||||
use user_input_common::check_for_slurs::contains_slurs;
|
||||
use users::email::email_to_gravatar::email_to_gravatar;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
#[derive(ToSchema, Deserialize)]
|
||||
|
||||
+1
-1
@@ -2,7 +2,6 @@ use crate::http_server::endpoints::users::google_sso::google_sso_handler::Google
|
||||
use crate::http_server::endpoints::users::google_sso::handle_new_sso_account::NewSsoAccountInfo;
|
||||
use crate::http_server::requests::get_request_signup_source::{get_request_signup_source, get_request_signup_source_enum};
|
||||
use crate::http_server::session::lookup::user_session_feature_flags::UserSessionFeatureFlags;
|
||||
use crate::util::email_to_gravatar::email_to_gravatar;
|
||||
use actix_web::HttpRequest;
|
||||
use enums::by_table::users::user_feature_flag::UserFeatureFlag;
|
||||
use google_sign_in::claims::claims::Claims;
|
||||
@@ -14,6 +13,7 @@ use mysql_queries::queries::users::user::create::create_account_from_google_sso:
|
||||
use mysql_queries::utils::transactor::Transactor;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::{Acquire, MySql};
|
||||
use users::email::email_to_gravatar::email_to_gravatar;
|
||||
use users::username::generate_random_username::generate_random_username;
|
||||
|
||||
pub struct CreateArgs<'a> {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
use md5::{Digest, Md5};
|
||||
|
||||
pub fn email_to_gravatar(email_address: &str) -> String {
|
||||
let email = email_address.trim().to_lowercase();
|
||||
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(email);
|
||||
let hash = hasher.finalize();
|
||||
let gravatar_hash = format!("{:x}", hash);
|
||||
|
||||
gravatar_hash
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::util::email_to_gravatar::email_to_gravatar;
|
||||
|
||||
#[test]
|
||||
fn test_gravatar() {
|
||||
// Email 1
|
||||
assert_eq!(email_to_gravatar("example@example.com"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar("EXAMPLE@EXAMPLE.COM"), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
assert_eq!(email_to_gravatar(" example@example.com \n "), "23463b99b62a72f26ed677cc556c44e8".to_string());
|
||||
|
||||
// Email 2
|
||||
assert_eq!(email_to_gravatar("echelon@gmail.com"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar("ECHELON@GMAIL.COM"), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
assert_eq!(email_to_gravatar(" ECHELON@GMAIL.COM "), "37e7e18f19d8f654a1ace405c846a9de".to_string());
|
||||
|
||||
// Misc
|
||||
assert_eq!(email_to_gravatar(""), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
assert_eq!(email_to_gravatar(" "), "d41d8cd98f00b204e9800998ecf8427e".to_string());
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ pub mod canonicalize_email_for_users_table;
|
||||
pub mod check_creator_tokens;
|
||||
pub mod cleaners;
|
||||
pub mod delete_role_disambiguation;
|
||||
pub mod email_to_gravatar;
|
||||
pub mod encrypted_sort_id;
|
||||
pub mod enroll_in_studio;
|
||||
pub mod http_download_url_to_bytes;
|
||||
|
||||
Reference in new issue
Block a user