mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-02 08:28:18 +00:00
Migrations to change/rename some columns
This commit is contained in:
1 parent
d4a7c06f72
commit
3efe1afa48
15 files changed
+291
-151
No files matched your search
@@ -14,16 +14,17 @@ CREATE TABLE user_subscriptions (
|
||||
-- The internal user associated with the subscription.
|
||||
-- This is nullable since it's possible we mess up and don't set it on the Stripe objects.
|
||||
-- We want the latitude to correct mistakes in the future. (Hopefully this doesn't bite me later.)
|
||||
-- **** NB/NOTE: THIS COLUMN WAS RENAMED TO `user_token` and made NON NULLABLE. ****
|
||||
maybe_user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we host multiple sites with distinct categories, this will enable us to segregate
|
||||
-- subscriptions. This is effectively a subscriptions namespace.
|
||||
-- TODO: Rename 'namespace'
|
||||
-- **** NB/NOTE: THIS COLUMN WAS RENAMED TO `subscription_namespace` ****
|
||||
subscription_category VARCHAR(32) NOT NULL,
|
||||
|
||||
-- This is the identifier for the actual type of subscription.
|
||||
-- These will not be defined in the database, but rather the source code.
|
||||
-- TODO: Rename 'slug'
|
||||
-- **** NB/NOTE: THIS COLUMN WAS RENAMED TO `subscription_product_slug` ****
|
||||
subscription_product_key VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== STRIPE DATA ==========
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE subscription_namespace subscription_category VARCHAR(32) NOT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE subscription_product_slug subscription_product_key VARCHAR(32) NOT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX index_subscription_namespace TO index_subscription_category;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX index_subscription_product_slug TO index_subscription_product_key;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE subscription_category subscription_namespace VARCHAR(32) NOT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE subscription_product_key subscription_product_slug VARCHAR(32) NOT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX index_subscription_category TO index_subscription_namespace;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX index_subscription_product_key TO index_subscription_product_slug;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE user_token maybe_user_token VARCHAR(255) DEFAULT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX fk_user_token TO fk_maybe_user_token;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
ALTER TABLE user_subscriptions CHANGE maybe_user_token user_token VARCHAR(255) NOT NULL;
|
||||
|
||||
ALTER TABLE user_subscriptions RENAME INDEX fk_maybe_user_token TO fk_user_token;
|
||||
@@ -0,0 +1,102 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
CREATE TABLE user_subscriptions (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
|
||||
-- Effective "primary key" (PUBLIC)
|
||||
token VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== INTERNAL SUBSCRIPTION DETAILS ==========
|
||||
|
||||
-- The internal user associated with the subscription.
|
||||
-- This is nullable since it's possible we mess up and don't set it on the Stripe objects.
|
||||
-- We want the latitude to correct mistakes in the future. (Hopefully this doesn't bite me later.)
|
||||
user_token VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- If we host multiple sites with distinct categories, this will enable us to segregate
|
||||
-- subscriptions. This is effectively a subscriptions namespace.
|
||||
subscription_namespace VARCHAR(32) NOT NULL,
|
||||
|
||||
-- This is the identifier for the actual type of subscription.
|
||||
-- These will not be defined in the database, but rather the source code.
|
||||
subscription_product_slug VARCHAR(32) NOT NULL,
|
||||
|
||||
-- ========== STRIPE DATA ==========
|
||||
|
||||
-- The stripe IDs (nullable in case we can't associate or if we use paypal)
|
||||
|
||||
-- You can safely assume object IDs we generate will never exceed 255 characters,
|
||||
-- but you should be able to handle IDs of up to that length. If for example you’re using MySQL,
|
||||
-- you should store IDs in a VARCHAR(255) COLLATE utf8_bin column (the COLLATE configuration ensures
|
||||
-- case-sensitivity in lookups).
|
||||
-- https://stackoverflow.com/a/61809494
|
||||
|
||||
-- When we receive a webhook update, we'll look it up by this key.
|
||||
-- This has a UNIQUE index.
|
||||
maybe_stripe_subscription_id VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
maybe_stripe_customer_id VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
maybe_stripe_product_id VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
maybe_stripe_price_id VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
-- How frequently the subscription is billed and updated
|
||||
maybe_stripe_recurring_interval VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- Subscription object status enum as string
|
||||
maybe_stripe_subscription_status VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
maybe_stripe_is_production BOOLEAN DEFAULT NULL,
|
||||
|
||||
-- ========== VECTOR CLOCK ==========
|
||||
|
||||
-- Incremented with every update.
|
||||
version INT NOT NULL DEFAULT 0,
|
||||
|
||||
-- ========== RECORD TIMESTAMPS ==========
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- ========== SUBSCRIPTION TIMESTAMPS ==========
|
||||
|
||||
-- When the subscription was first created (Stripe's subscription "start_date").
|
||||
-- This may predate the Stripe object `created` timestamp due to backdating.
|
||||
subscription_start_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- We'll use this to determine if the subscription is active.
|
||||
--
|
||||
-- Always compare against MySQL's clock rather than the app's clock so that we
|
||||
-- don't get weird clock skew behaviors across multiple requests.
|
||||
--
|
||||
-- Technically the user can have multiple active subscriptions of the same type, but we'll
|
||||
-- try to prevent creation of new subscriptions of the same type.
|
||||
subscription_expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Billing periods.
|
||||
-- Maybe useful for debugging.
|
||||
current_billing_period_start_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
current_billing_period_end_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Subscription cancellation (future and past)
|
||||
maybe_cancel_at TIMESTAMP DEFAULT NULL,
|
||||
maybe_canceled_at TIMESTAMP DEFAULT NULL,
|
||||
|
||||
-- ========== INDICES ==========
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY (token),
|
||||
UNIQUE KEY (maybe_stripe_subscription_id),
|
||||
KEY index_subscription_namespace (subscription_namespace),
|
||||
KEY index_subscription_product_slug (subscription_product_slug),
|
||||
KEY index_maybe_stripe_customer_id (maybe_stripe_customer_id),
|
||||
KEY index_maybe_stripe_product_id (maybe_stripe_product_id),
|
||||
KEY index_maybe_stripe_subscription_status (maybe_stripe_subscription_status),
|
||||
KEY fk_user_token (user_token),
|
||||
KEY index_subscription_expires_at (subscription_expires_at)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
|
||||
File renamed without changes.
+2
-2
@@ -1,8 +1,8 @@
|
||||
|
||||
/// Subscription categories are used to namespace subscriptions.
|
||||
/// Integrations should always provide a default even if this isn't used.
|
||||
pub const UNKNOWN_SUBSCRIPTION_CATEGORY : &'static str = "unknown";
|
||||
pub const UNKNOWN_SUBSCRIPTION_NAMESPACE: &'static str = "unknown";
|
||||
|
||||
/// The integrated system has internal unique string key identifiers for
|
||||
/// each subscription plan.
|
||||
pub const UNKNOWN_SUBSCRIPTION_PRODUCT_KEY : &'static str = "unknown";
|
||||
pub const UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG: &'static str = "unknown";
|
||||
+45
-43
@@ -1,5 +1,5 @@
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::calculate_subscription_end_date::calculate_subscription_end_date;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_CATEGORY, UNKNOWN_SUBSCRIPTION_PRODUCT_KEY};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_NAMESPACE, UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::subscription_event_extractor::subscription_summary_extractor;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_error::StripeWebhookError;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_summary::StripeWebhookSummary;
|
||||
@@ -56,57 +56,59 @@ pub async fn customer_subscription_created_handler(
|
||||
StripeWebhookError::ServerError // NB: This was probably *our* fault.
|
||||
})?;
|
||||
|
||||
let mut subscription_category = UNKNOWN_SUBSCRIPTION_CATEGORY;
|
||||
let mut subscription_product_key = UNKNOWN_SUBSCRIPTION_PRODUCT_KEY;
|
||||
let mut subscription_namespace = UNKNOWN_SUBSCRIPTION_NAMESPACE;
|
||||
let mut subscription_product_slug = UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG;
|
||||
|
||||
if let Some(ref internal_product) = maybe_internal_subscription_product {
|
||||
subscription_category = &internal_product.subscription_category;
|
||||
subscription_product_key = &internal_product.subscription_product_key;
|
||||
subscription_namespace = &internal_product.subscription_category;
|
||||
subscription_product_slug = &internal_product.subscription_product_key;
|
||||
}
|
||||
|
||||
// TODO: record cancel_at (future_cancel_at), canceled_at, ended_at (if subscription ended, when it ended), start_date
|
||||
if let Some(user_token) = summary.user_token.as_deref() {
|
||||
// TODO: record cancel_at (future_cancel_at), canceled_at, ended_at (if subscription ended, when it ended), start_date
|
||||
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
maybe_user_token: summary.user_token.as_deref(),
|
||||
subscription_category,
|
||||
subscription_product_key,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
|
||||
if let Some(user_token) = summary.user_token.as_deref() {
|
||||
// TODO: Should we care if a user accidentally gets two stripe customer IDs and this
|
||||
// overwrites one of them?
|
||||
update_user_record_with_new_stripe_customer_id(
|
||||
mysql_pool,
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
user_token,
|
||||
Some(&summary.stripe_customer_id))
|
||||
.await
|
||||
.map_err(|err| {
|
||||
subscription_namespace,
|
||||
subscription_product_slug,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
}
|
||||
})?;
|
||||
|
||||
|
||||
// TODO: Should we care if a user accidentally gets two stripe customer IDs and this
|
||||
// overwrites one of them?
|
||||
update_user_record_with_new_stripe_customer_id(
|
||||
mysql_pool,
|
||||
user_token,
|
||||
Some(&summary.stripe_customer_id))
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
|
||||
result.action_was_taken = true;
|
||||
}
|
||||
|
||||
result.action_was_taken = true;
|
||||
result.should_ignore_retry = true;
|
||||
|
||||
Ok(result)
|
||||
|
||||
+34
-30
@@ -1,5 +1,5 @@
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::calculate_subscription_end_date::calculate_subscription_end_date;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_CATEGORY, UNKNOWN_SUBSCRIPTION_PRODUCT_KEY};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_NAMESPACE, UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::subscription_event_extractor::subscription_summary_extractor;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_error::StripeWebhookError;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_summary::StripeWebhookSummary;
|
||||
@@ -36,12 +36,12 @@ pub async fn customer_subscription_deleted_handler(
|
||||
StripeWebhookError::ServerError // NB: This was probably *our* fault.
|
||||
})?;
|
||||
|
||||
let mut subscription_category = UNKNOWN_SUBSCRIPTION_CATEGORY;
|
||||
let mut subscription_product_key = UNKNOWN_SUBSCRIPTION_PRODUCT_KEY;
|
||||
let mut subscription_namespace = UNKNOWN_SUBSCRIPTION_NAMESPACE;
|
||||
let mut subscription_product_slug = UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG;
|
||||
|
||||
if let Some(ref internal_product) = maybe_internal_subscription_product {
|
||||
subscription_category = &internal_product.subscription_category;
|
||||
subscription_product_key = &internal_product.subscription_product_key;
|
||||
subscription_namespace = &internal_product.subscription_category;
|
||||
subscription_product_slug = &internal_product.subscription_product_key;
|
||||
}
|
||||
|
||||
// NB: It's possible to receive events out of order.
|
||||
@@ -66,33 +66,37 @@ pub async fn customer_subscription_deleted_handler(
|
||||
// NB: Even if we haven't received a record before, we should still be able to "tombstone" it
|
||||
// once we detect the deletion.
|
||||
if should_process_update {
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
maybe_user_token: summary.user_token.as_deref(),
|
||||
subscription_category,
|
||||
subscription_product_key,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
if let Some(user_token) = summary.user_token.as_deref() {
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
user_token,
|
||||
subscription_namespace,
|
||||
subscription_product_slug,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
|
||||
action_was_taken = true;
|
||||
}
|
||||
|
||||
action_was_taken = true;
|
||||
should_ignore_retry = true;
|
||||
}
|
||||
|
||||
|
||||
+36
-34
@@ -1,5 +1,5 @@
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::calculate_subscription_end_date::calculate_subscription_end_date;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_CATEGORY, UNKNOWN_SUBSCRIPTION_PRODUCT_KEY};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::common::{UNKNOWN_SUBSCRIPTION_NAMESPACE, UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG};
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::customer_subscription::subscription_event_extractor::subscription_summary_extractor;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_error::StripeWebhookError;
|
||||
use crate::stripe::http_endpoints::webhook::webhook_event_handlers::stripe_webhook_summary::StripeWebhookSummary;
|
||||
@@ -37,12 +37,12 @@ pub async fn customer_subscription_updated_handler(
|
||||
StripeWebhookError::ServerError // NB: This was probably *our* fault.
|
||||
})?;
|
||||
|
||||
let mut subscription_category = UNKNOWN_SUBSCRIPTION_CATEGORY;
|
||||
let mut subscription_product_key = UNKNOWN_SUBSCRIPTION_PRODUCT_KEY;
|
||||
let mut subscription_namespace = UNKNOWN_SUBSCRIPTION_NAMESPACE;
|
||||
let mut subscription_product_slug = UNKNOWN_SUBSCRIPTION_PRODUCT_SLUG;
|
||||
|
||||
if let Some(ref internal_product) = maybe_internal_subscription_product {
|
||||
subscription_category = &internal_product.subscription_category;
|
||||
subscription_product_key = &internal_product.subscription_product_key;
|
||||
subscription_namespace = &internal_product.subscription_category;
|
||||
subscription_product_slug = &internal_product.subscription_product_key;
|
||||
}
|
||||
|
||||
// NB: It's possible to receive events out of order.
|
||||
@@ -65,33 +65,34 @@ pub async fn customer_subscription_updated_handler(
|
||||
}
|
||||
|
||||
if should_process_update {
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
maybe_user_token: summary.user_token.as_deref(),
|
||||
subscription_category,
|
||||
subscription_product_key,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
|
||||
if let Some(user_token) = summary.user_token.as_deref() {
|
||||
|
||||
let upsert = UpsertUserSubscription {
|
||||
stripe_subscription_id: &summary.stripe_subscription_id,
|
||||
user_token: &user_token,
|
||||
subscription_namespace,
|
||||
subscription_product_slug,
|
||||
maybe_stripe_customer_id: Some(&summary.stripe_customer_id),
|
||||
maybe_stripe_product_id: Some(&summary.stripe_product_id),
|
||||
maybe_stripe_price_id: Some(&summary.stripe_price_id),
|
||||
maybe_stripe_recurring_interval: Some(summary.subscription_interval),
|
||||
maybe_stripe_subscription_status: Some(summary.stripe_subscription_status),
|
||||
maybe_stripe_is_production: Some(summary.stripe_is_production),
|
||||
subscription_start_at: summary.subscription_start_date,
|
||||
current_billing_period_start_at: summary.current_billing_period_start,
|
||||
current_billing_period_end_at: summary.current_billing_period_end,
|
||||
subscription_expires_at: calculate_subscription_end_date(&summary),
|
||||
maybe_cancel_at: summary.maybe_cancel_at,
|
||||
maybe_canceled_at: summary.maybe_canceled_at,
|
||||
};
|
||||
|
||||
let _r = upsert.upsert(mysql_pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
|
||||
// TODO: Should we care if a user accidentally gets two stripe customer IDs and this
|
||||
// overwrites one of them?
|
||||
update_user_record_with_new_stripe_customer_id(
|
||||
@@ -103,12 +104,13 @@ pub async fn customer_subscription_updated_handler(
|
||||
error!("Mysql error: {:?}", err);
|
||||
StripeWebhookError::ServerError
|
||||
})?;
|
||||
}
|
||||
|
||||
action_was_taken = true;
|
||||
should_ignore_retry = true;
|
||||
action_was_taken = true;
|
||||
}
|
||||
}
|
||||
|
||||
should_ignore_retry = true;
|
||||
|
||||
Ok(StripeWebhookSummary {
|
||||
maybe_user_token: summary.user_token,
|
||||
maybe_event_entity_id: Some(summary.stripe_subscription_id),
|
||||
|
||||
+2
-2
@@ -104,8 +104,8 @@ pub fn subscription_summary_extractor(subscription: &Subscription) -> AnyhowResu
|
||||
subscription_start_date: start_date,
|
||||
current_billing_period_start: period_start,
|
||||
current_billing_period_end: period_end,
|
||||
maybe_cancel_at: maybe_cancel_at,
|
||||
maybe_canceled_at: maybe_canceled_at,
|
||||
maybe_cancel_at,
|
||||
maybe_canceled_at,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -8,9 +8,9 @@ use sqlx::MySqlPool;
|
||||
|
||||
pub struct UserSubscription {
|
||||
pub token: String,
|
||||
pub maybe_user_token: Option<String>,
|
||||
pub subscription_category: String,
|
||||
pub subscription_product_key: String,
|
||||
pub user_token: String,
|
||||
pub subscription_namespace: String,
|
||||
pub subscription_product_slug: String,
|
||||
pub maybe_stripe_subscription_id: Option<String>,
|
||||
pub maybe_stripe_product_id: Option<String>,
|
||||
pub maybe_stripe_customer_id: Option<String>,
|
||||
@@ -36,9 +36,9 @@ pub async fn get_user_subscription_by_stripe_subscription_id(
|
||||
r#"
|
||||
SELECT
|
||||
token,
|
||||
maybe_user_token,
|
||||
subscription_category,
|
||||
subscription_product_key,
|
||||
user_token,
|
||||
subscription_namespace,
|
||||
subscription_product_slug,
|
||||
maybe_stripe_subscription_id,
|
||||
maybe_stripe_customer_id,
|
||||
maybe_stripe_product_id,
|
||||
@@ -65,9 +65,9 @@ WHERE
|
||||
Ok(r) => {
|
||||
Ok(Some(UserSubscription {
|
||||
token: r.token,
|
||||
maybe_user_token: r.maybe_user_token,
|
||||
subscription_category: r.subscription_category,
|
||||
subscription_product_key: r.subscription_product_key,
|
||||
user_token: r.user_token,
|
||||
subscription_namespace: r.subscription_namespace,
|
||||
subscription_product_slug: r.subscription_product_slug,
|
||||
maybe_stripe_subscription_id: r.maybe_stripe_subscription_id,
|
||||
maybe_stripe_product_id: r.maybe_stripe_product_id,
|
||||
maybe_stripe_customer_id: r.maybe_stripe_customer_id,
|
||||
@@ -84,9 +84,9 @@ WHERE
|
||||
|
||||
struct RawUserSubscriptionFromDb {
|
||||
pub token: String,
|
||||
pub maybe_user_token: Option<String>,
|
||||
pub subscription_category: String,
|
||||
pub subscription_product_key: String,
|
||||
pub user_token: String,
|
||||
pub subscription_namespace: String,
|
||||
pub subscription_product_slug: String,
|
||||
pub maybe_stripe_subscription_id: Option<String>,
|
||||
pub maybe_stripe_product_id: Option<String>,
|
||||
pub maybe_stripe_customer_id: Option<String>,
|
||||
|
||||
+6
-9
@@ -25,16 +25,15 @@ pub async fn list_active_user_subscriptions(
|
||||
RawActiveUserSubscription,
|
||||
r#"
|
||||
SELECT
|
||||
maybe_user_token as user_token,
|
||||
subscription_category as subscription_namespace,
|
||||
subscription_product_key as subscription_product_slug,
|
||||
user_token,
|
||||
subscription_namespace,
|
||||
subscription_product_slug,
|
||||
subscription_expires_at
|
||||
|
||||
FROM user_subscriptions
|
||||
|
||||
WHERE
|
||||
maybe_user_token IS NOT NULL
|
||||
AND maybe_user_token = ?
|
||||
user_token = ?
|
||||
AND subscription_expires_at > CURRENT_TIMESTAMP
|
||||
ORDER BY id ASC
|
||||
"#,
|
||||
@@ -46,9 +45,7 @@ WHERE
|
||||
let records = records.into_iter()
|
||||
.map(|record : RawActiveUserSubscription | {
|
||||
ActiveUserSubscription {
|
||||
user_token: record.user_token.unwrap_or("".to_string()),
|
||||
|
||||
|
||||
user_token: record.user_token,
|
||||
subscription_namespace: record.subscription_namespace,
|
||||
subscription_product_slug: record.subscription_product_slug,
|
||||
subscription_expires_at: record.subscription_expires_at,
|
||||
@@ -60,7 +57,7 @@ WHERE
|
||||
}
|
||||
|
||||
struct RawActiveUserSubscription {
|
||||
user_token: Option<String>,
|
||||
user_token: String,
|
||||
subscription_namespace: String,
|
||||
subscription_product_slug: String,
|
||||
subscription_expires_at: DateTime<Utc>,
|
||||
|
||||
+13
-17
@@ -14,13 +14,13 @@ pub struct UpsertUserSubscription<'a> {
|
||||
pub stripe_subscription_id: &'a str,
|
||||
|
||||
/// Internal user token
|
||||
pub maybe_user_token: Option<&'a str>,
|
||||
pub user_token: &'a str,
|
||||
|
||||
/// The platform key, eg. "fakeyou", "storyteller_stream", "symphonia", etc.
|
||||
pub subscription_category: &'a str,
|
||||
pub subscription_namespace: &'a str,
|
||||
|
||||
/// The name of the product the user is subscribing to within the category.
|
||||
pub subscription_product_key: &'a str,
|
||||
pub subscription_product_slug: &'a str,
|
||||
|
||||
pub maybe_stripe_customer_id: Option<&'a str>,
|
||||
|
||||
@@ -67,9 +67,9 @@ impl <'a> UpsertUserSubscription<'a> {
|
||||
INSERT INTO user_subscriptions
|
||||
SET
|
||||
token = ?,
|
||||
maybe_user_token = ?,
|
||||
subscription_category = ?,
|
||||
subscription_product_key = ?,
|
||||
user_token = ?,
|
||||
subscription_namespace = ?,
|
||||
subscription_product_slug = ?,
|
||||
|
||||
maybe_stripe_subscription_id = ?,
|
||||
maybe_stripe_customer_id = ?,
|
||||
@@ -91,10 +91,8 @@ SET
|
||||
version = version + 1
|
||||
|
||||
ON DUPLICATE KEY UPDATE
|
||||
maybe_user_token = COALESCE(NULLIF(?, ''), maybe_user_token),
|
||||
|
||||
subscription_category = ?,
|
||||
subscription_product_key = ?,
|
||||
subscription_namespace = ?,
|
||||
subscription_product_slug= ?,
|
||||
|
||||
maybe_stripe_product_id = ?,
|
||||
maybe_stripe_price_id = ?,
|
||||
@@ -112,9 +110,9 @@ ON DUPLICATE KEY UPDATE
|
||||
"#,
|
||||
// Insert
|
||||
token,
|
||||
self.maybe_user_token,
|
||||
self.subscription_category,
|
||||
self.subscription_product_key,
|
||||
self.user_token,
|
||||
self.subscription_namespace,
|
||||
self.subscription_product_slug,
|
||||
|
||||
self.stripe_subscription_id,
|
||||
self.maybe_stripe_customer_id,
|
||||
@@ -134,10 +132,8 @@ ON DUPLICATE KEY UPDATE
|
||||
self.maybe_canceled_at,
|
||||
|
||||
// Upsert
|
||||
self.maybe_user_token,
|
||||
|
||||
self.subscription_category,
|
||||
self.subscription_product_key,
|
||||
self.subscription_namespace,
|
||||
self.subscription_product_slug,
|
||||
|
||||
self.maybe_stripe_product_id,
|
||||
self.maybe_stripe_price_id,
|
||||
|
||||
Reference in new issue
Block a user