This repository has been archived by the owner on Aug 8, 2023. It is now read-only.
forked from RadoslavGatev/Ghost-Azure
-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
949 additions
and
721 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...dark-9b324af435542226a7626dd0b5376888.css → ...dark-26c50eb1ab27d41ebe60df1b24fd2d39.css
Large diffs are not rendered by default.
Oops, something went wrong.
202 changes: 104 additions & 98 deletions
202
...t.min-dff68da9a8ffbb4fff7171f51eba3bb8.js → ...t.min-29833669e636da872b13a32537b66d84.js
Large diffs are not rendered by default.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
....min-a6e7ba40bba8913647fbe4ee3009ad9b.css → ....min-413e594d416742155dfb6667f5f60b33.css
Large diffs are not rendered by default.
Oops, something went wrong.
87 changes: 46 additions & 41 deletions
87
...r.min-b50d677c001301c7dceff8443c6f1dd5.js → ...r.min-e2d6599ea34c2a6e135b5288648bf50d.js
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
const logging = require('../../../../../shared/logging'); | ||
|
||
module.exports = { | ||
config: { | ||
transaction: true | ||
}, | ||
|
||
async up({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
logging.warn('Skipping cleanup of duplicate subscriptions - database is not MySQL'); | ||
return; | ||
} | ||
|
||
const duplicates = await knex('members_stripe_customers_subscriptions') | ||
.select('subscription_id') | ||
.count('subscription_id as count') | ||
.groupBy('subscription_id') | ||
.having('count', '>', 1); | ||
|
||
if (!duplicates.length) { | ||
logging.info('No duplicate subscriptions found'); | ||
return; | ||
} | ||
|
||
logging.info(`Found ${duplicates.length} duplicate stripe subscriptions`); | ||
for (const duplicate of duplicates) { | ||
const subscriptions = await knex('members_stripe_customers_subscriptions') | ||
.select() | ||
.where('subscription_id', duplicate.subscription_id); | ||
|
||
const orderedSubscriptions = subscriptions.sort((subA, subB) => { | ||
return subB.updated_at - subA.updated_at; | ||
}); | ||
|
||
const [newestSubscription, ...olderSubscriptions] = orderedSubscriptions; | ||
|
||
logging.info(`Keeping newest subscription ${newestSubscription.id} - ${newestSubscription.subscription_id}, last updated at ${newestSubscription.updated_at}`); | ||
|
||
for (const subscriptionToDelete of olderSubscriptions) { | ||
logging.info(`Deleting duplicate subscription ${subscriptionToDelete.id} - ${subscriptionToDelete.subscription_id}, last updated at ${subscriptionToDelete.updated_at}`); | ||
await knex('members_stripe_customers_subscriptions') | ||
.where({id: subscriptionToDelete.id}) | ||
.del(); | ||
} | ||
} | ||
}, | ||
|
||
// noop for down | ||
async down() {} | ||
}; |
50 changes: 50 additions & 0 deletions
50
core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
const logging = require('../../../../../shared/logging'); | ||
|
||
module.exports = { | ||
config: { | ||
transaction: true | ||
}, | ||
|
||
async up({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
logging.warn('Skipping cleanup of duplicate customers - database is not MySQL'); | ||
return; | ||
} | ||
|
||
const duplicates = await knex('members_stripe_customers') | ||
.select('customer_id') | ||
.count('customer_id as count') | ||
.groupBy('customer_id') | ||
.having('count', '>', 1); | ||
|
||
if (!duplicates.length) { | ||
logging.info('No duplicate customers found'); | ||
return; | ||
} | ||
|
||
logging.info(`Found ${duplicates.length} duplicate stripe customers`); | ||
for (const duplicate of duplicates) { | ||
const customers = await knex('members_stripe_customers') | ||
.select() | ||
.where('customer_id', duplicate.customer_id); | ||
|
||
const orderedCustomers = customers.sort((subA, subB) => { | ||
return subB.updated_at - subA.updated_at; | ||
}); | ||
|
||
const [newestCustomer, ...olderCustomers] = orderedCustomers; | ||
|
||
logging.info(`Keeping newest customer ${newestCustomer.id} - ${newestCustomer.customer_id}, last updated at ${newestCustomer.updated_at}`); | ||
|
||
for (const customerToDelete of olderCustomers) { | ||
logging.info(`Deleting duplicate customer ${customerToDelete.id} - ${customerToDelete.customer_id}, last updated at ${customerToDelete.updated_at}`); | ||
await knex('members_stripe_customers') | ||
.where({id: customerToDelete.id}) | ||
.del(); | ||
} | ||
} | ||
}, | ||
|
||
// noop for down | ||
async down() {} | ||
}; |
34 changes: 34 additions & 0 deletions
34
core/server/data/migrations/versions/3.29/03-remove-orphaned-customers.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
const logging = require('../../../../../shared/logging'); | ||
|
||
module.exports = { | ||
config: { | ||
transaction: true | ||
}, | ||
|
||
async up({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
logging.warn('Skipping cleanup of orphaned customers - database is not MySQL'); | ||
return; | ||
} | ||
|
||
const orphanedCustomers = await knex('members_stripe_customers') | ||
.select('id') | ||
.whereNotIn( | ||
'member_id', | ||
knex('members') | ||
.select('id') | ||
); | ||
|
||
if (!orphanedCustomers || !orphanedCustomers.length) { | ||
logging.info('No orphaned customer records found'); | ||
return; | ||
} | ||
|
||
logging.info(`Deleting ${orphanedCustomers.length} orphaned customers`); | ||
await knex('members_stripe_customers') | ||
.whereIn('id', orphanedCustomers.map(customer => customer.id)) | ||
.del(); | ||
}, | ||
|
||
async down() {} | ||
}; |
34 changes: 34 additions & 0 deletions
34
core/server/data/migrations/versions/3.29/04-remove-orphaned-subscriptions.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
const logging = require('../../../../../shared/logging'); | ||
|
||
module.exports = { | ||
config: { | ||
transaction: true | ||
}, | ||
|
||
async up({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
logging.warn('Skipping cleanup of orphaned subscriptions - database is not MySQL'); | ||
return; | ||
} | ||
|
||
const orphanedSubscriptions = await knex('members_stripe_customers_subscriptions') | ||
.select('id') | ||
.whereNotIn( | ||
'customer_id', | ||
knex('members_stripe_customers') | ||
.select('customer_id') | ||
); | ||
|
||
if (!orphanedSubscriptions || !orphanedSubscriptions.length) { | ||
logging.info('No orphaned subscription records found'); | ||
return; | ||
} | ||
|
||
logging.info(`Deleting ${orphanedSubscriptions.length} orphaned subscriptions`); | ||
await knex('members_stripe_customers_subscriptions') | ||
.whereIn('id', orphanedSubscriptions.map(subscription => subscription.id)) | ||
.del(); | ||
}, | ||
|
||
async down() {} | ||
}; |
174 changes: 174 additions & 0 deletions
174
core/server/data/migrations/versions/3.29/05-add-member-constraints.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
const logging = require('../../../../../shared/logging'); | ||
|
||
module.exports = { | ||
config: { | ||
transaction: true | ||
}, | ||
|
||
async up({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
return logging.warn('Skipping member tables index creation - database is not MySQL'); | ||
} | ||
|
||
// member_labels already has a foreign key constraint, we want to add ON DELETE CASCADE | ||
|
||
const dbName = knex.client.config.connection.database; | ||
const [dbConstraints] = await knex.raw('SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=?', [dbName]); | ||
|
||
const memberIdConstraint = dbConstraints.find(constraint => constraint.CONSTRAINT_NAME === 'members_labels_member_id_foreign'); | ||
if (memberIdConstraint && memberIdConstraint.DELETE_RULE === 'CASCADE') { | ||
logging.warn('Skipping ON DELETE CASCADE for "members_labels_member_id_foreign" constraint - already set'); | ||
} else if (memberIdConstraint) { | ||
logging.info('Adding ON DELETE CASCADE to "members_labels_member_id_foreign" constraint'); | ||
// first drop the key | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.dropForeign('member_id'); | ||
table.dropIndex('member_id', 'members_labels_member_id_foreign'); | ||
}); | ||
// then re-add with ON DELETE CASCADE | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.foreign('member_id').references('members.id').onDelete('CASCADE'); | ||
}); | ||
} | ||
|
||
const labelIdConstraint = dbConstraints.find(constraint => constraint.CONSTRAINT_NAME === 'members_labels_label_id_foreign'); | ||
if (labelIdConstraint && labelIdConstraint.DELETE_RULE === 'CASCADE') { | ||
logging.warn('Skipping ON DELETE CASCADE for "members_labels_label_id_foreign" constraint - already set'); | ||
} else if (labelIdConstraint) { | ||
logging.info('Adding ON DELETE CASCADE to "members_labels_label_id_foreign" constraint'); | ||
// first drop the key | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.dropForeign('label_id'); | ||
table.dropIndex('label_id', 'members_labels_label_id_foreign'); | ||
}); | ||
// then re-add with ON DELETE CASCADE | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.foreign('label_id').references('labels.id').onDelete('CASCADE'); | ||
}); | ||
} | ||
|
||
// stripe tables have not had any indexes/constraints in the past, add them now with ON DELETE CASCADE | ||
|
||
const [membersStripeCustomersIndexes] = await knex.raw('SHOW INDEXES FROM members_stripe_customers'); | ||
const [membersStripeCustomersSubscriptionsIndexes] = await knex.raw('SHOW INDEXES from members_stripe_customers_subscriptions'); | ||
|
||
if (membersStripeCustomersIndexes.find(index => index.Key_name === 'members_stripe_customers_member_id_foreign')) { | ||
logging.warn('Skipping "members_stripe_customers_member_id_foreign" foreign key constraint creation - already exists'); | ||
} else { | ||
logging.info('Adding "members_stripe_customers_member_id_foreign" foreign key constraint'); | ||
await knex.schema.alterTable('members_stripe_customers', (table) => { | ||
table.foreign('member_id').references('members.id').onDelete('CASCADE'); | ||
}); | ||
} | ||
|
||
if (membersStripeCustomersIndexes.find(index => index.Key_name === 'members_stripe_customers_customer_id_unique')) { | ||
logging.warn('Skipping "members_stripe_customers_customer_id_unique" index creation - already exists'); | ||
} else { | ||
logging.info('Adding "members_stripe_customers_customer_id_unique" index'); | ||
await knex.schema.alterTable('members_stripe_customers', (table) => { | ||
table.unique('customer_id'); | ||
}); | ||
} | ||
|
||
if (membersStripeCustomersIndexes.find(index => index.Key_name === 'members_stripe_customers_subscriptions_subscription_id_unique')) { | ||
logging.warn('Skipping "members_stripe_customers_subscriptions_subscription_id_unique" index creation - already exists'); | ||
} else { | ||
logging.info('Adding "members_stripe_customers_subscriptions_subscription_id_unique" index'); | ||
await knex.schema.alterTable('members_stripe_customers_subscriptions', (table) => { | ||
table.unique('subscription_id'); | ||
}); | ||
} | ||
|
||
if (membersStripeCustomersSubscriptionsIndexes.find(index => index.Key_name === 'members_stripe_customers_subscriptions_customer_id_foreign')) { | ||
logging.warn('Skipping "members_stripe_customers_subscriptions_customer_id_foreign" foreign key constraint creation - already exists'); | ||
} else { | ||
logging.info('Adding "members_stripe_customers_subscriptions_customer_id_foreign" foreign key constraint'); | ||
await knex.schema.alterTable('members_stripe_customers_subscriptions', (table) => { | ||
table.foreign('customer_id').references('members_stripe_customers.customer_id').onDelete('CASCADE'); | ||
}); | ||
} | ||
}, | ||
|
||
async down({transacting: knex}) { | ||
if (knex.client.config.client !== 'mysql') { | ||
return logging.warn('Skipping member tables index removal - database is not MySQL'); | ||
} | ||
|
||
const [membersStripeCustomersIndexes] = await knex.raw('SHOW INDEXES FROM members_stripe_customers'); | ||
const [membersStripeCustomersSubscriptionsIndexes] = await knex.raw('SHOW INDEXES from members_stripe_customers_subscriptions'); | ||
|
||
if (!membersStripeCustomersSubscriptionsIndexes.find(index => index.Key_name === 'members_stripe_customers_subscriptions_customer_id_foreign')) { | ||
logging.warn('Skipping "members_stripe_customers_subscriptions_customer_id_foreign" foreign key constraint removal - does not exist'); | ||
} else { | ||
logging.info('Dropping "members_stripe_customers_subscriptions_customer_id_foreign" foreign key constraint'); | ||
await knex.schema.alterTable('members_stripe_customers_subscriptions', (table) => { | ||
table.dropForeign('customer_id'); | ||
// mysql automatically creates an index for the foreign key which will be left behind after dropping foreign key constraint | ||
table.dropIndex('customer_id', 'members_stripe_customers_subscriptions_customer_id_foreign'); | ||
}); | ||
} | ||
|
||
if (!membersStripeCustomersSubscriptionsIndexes.find(index => index.Key_name === 'members_stripe_customers_subscriptions_subscription_id_unique')) { | ||
logging.warn('Skipping "members_stripe_customers_subscriptions_subscription_id_unique" index removal - does not exist'); | ||
} else { | ||
logging.info('Dropping "members_stripe_customers_subscriptions_subscription_id_unique" index'); | ||
await knex.schema.alterTable('members_stripe_customers_subscriptions', (table) => { | ||
table.dropUnique('subscription_id'); | ||
}); | ||
} | ||
|
||
if (!membersStripeCustomersIndexes.find(index => index.Key_name === 'members_stripe_customers_customer_id_unique')) { | ||
logging.warn('Skipping "members_stripe_customers_customer_id_unique" index removal - does not exist'); | ||
} else { | ||
logging.info('Dropping "members_stripe_customers_customer_id_unique" index'); | ||
await knex.schema.alterTable('members_stripe_customers', (table) => { | ||
table.dropUnique('customer_id'); | ||
}); | ||
} | ||
|
||
if (!membersStripeCustomersIndexes.find(index => index.Key_name === 'members_stripe_customers_member_id_foreign')) { | ||
logging.warn('Skipping "members_stripe_customers_member_id_foreign" foreign key constraint removal - does not exist'); | ||
} else { | ||
logging.info('Dropping "members_stripe_customers_member_id_foreign" foreign key constraint'); | ||
await knex.schema.alterTable('members_stripe_customers', (table) => { | ||
table.dropForeign('member_id'); | ||
table.dropIndex('member_id', 'members_stripe_customers_member_id_foreign'); | ||
}); | ||
} | ||
|
||
const dbName = knex.client.config.connection.database; | ||
const [dbConstraints] = await knex.raw('SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=?', [dbName]); | ||
|
||
const memberIdConstraint = dbConstraints.find(constraint => constraint.CONSTRAINT_NAME === 'members_labels_member_id_foreign'); | ||
if (memberIdConstraint && memberIdConstraint.DELETE_RULE !== 'CASCADE') { | ||
logging.warn('Skipping removal of ON DELETE CASCADE for "members_labels_member_id_foreign" constraint - not set'); | ||
} else if (memberIdConstraint) { | ||
logging.info('Removing ON DELETE CASCADE from "members_labels_member_id_foreign" constraint'); | ||
// first drop the key | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.dropForeign('member_id'); | ||
table.dropIndex('member_id', 'members_labels_member_id_foreign'); | ||
}); | ||
// then re-add without ON DELETE CASCADE | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.foreign('member_id').references('members.id'); | ||
}); | ||
} | ||
|
||
const labelIdConstraint = dbConstraints.find(constraint => constraint.CONSTRAINT_NAME === 'members_labels_label_id_foreign'); | ||
if (labelIdConstraint && labelIdConstraint.DELETE_RULE !== 'CASCADE') { | ||
logging.warn('Skipping removal of ON DELETE CASCADE for "members_labels_label_id_foreign" constraint - not set'); | ||
} else if (labelIdConstraint) { | ||
logging.info('Removing ON DELETE CASCADE from "members_labels_label_id_foreign" constraint'); | ||
// first drop the key | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.dropForeign('label_id'); | ||
table.dropIndex('label_id', 'members_labels_label_id_foreign'); | ||
}); | ||
// then re-add without ON DELETE CASCADE | ||
await knex.schema.alterTable('members_labels', (table) => { | ||
table.foreign('label_id').references('labels.id'); | ||
}); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.