From f878e847077c0135cc9324a00b0d8035c8dda4df Mon Sep 17 00:00:00 2001 From: "Fabien \"egg\" O'Carroll" Date: Mon, 31 Oct 2022 16:49:10 +0700 Subject: [PATCH] Fixed Tiers importer not correctly mapping price data refs https://github.com/TryGhost/Toolbox/issues/464 Bceause the import does not use the API, any backwards compat code we put in the API does not get run for imports, this means we need to update the importer to map the stripe_prices data onto the products table so that we have valid data in the database. --- .../data/importer/importers/data/products.js | 47 ++++++++++++++ .../importer/importers/data/products.test.js | 64 +++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 ghost/core/test/unit/server/data/importer/importers/data/products.test.js diff --git a/ghost/core/core/server/data/importer/importers/data/products.js b/ghost/core/core/server/data/importer/importers/data/products.js index 2294aaf4ca..b0466f180c 100644 --- a/ghost/core/core/server/data/importer/importers/data/products.js +++ b/ghost/core/core/server/data/importer/importers/data/products.js @@ -29,6 +29,48 @@ class ProductsImporter extends BaseImporter { }; } + populatePriceData() { + const invalidRows = []; + _.each(this.dataToImport, (row) => { + if (row.slug === 'free') { + return; + } + if (row.currency && row.monthly_price && row.yearly_price) { + return; + } + if (!row.monthly_price || !row.currency) { + const monthlyStripePrice = _.find( + this.requiredFromFile.stripe_prices, + {id: row.monthly_price_id} + ) || _.find( + this.requiredExistingData.stripe_prices, + {id: row.monthly_price_id} + ); + if (!monthlyStripePrice) { + invalidRows.push(row.id); + return; + } + row.monthly_price = row.monthly_price || monthlyStripePrice.amount; + row.currency = monthlyStripePrice.currency; + } + if (!row.yearly_price) { + const yearlyStripePrice = _.find( + this.requiredFromFile.stripe_prices, + {id: row.yearly_price_id} + ) || _.find( + this.requiredExistingData.stripe_prices, + {id: row.yearly_price_id} + ); + if (!yearlyStripePrice) { + invalidRows.push(row.id); + return; + } + row.yearly_price = row.yearly_price || yearlyStripePrice.amount; + } + }); + this.dataToImport = this.dataToImport.filter(item => !invalidRows.includes(item.id)); + } + validateStripePrice() { // the stripe price either needs to exist in the current db, // or be imported as part of the same import @@ -84,6 +126,11 @@ class ProductsImporter extends BaseImporter { this.dataToImport = this.dataToImport.filter(item => !duplicateProducts.includes(item.id)); } + beforeImport() { + this.populatePriceData(); + return super.beforeImport(); + } + replaceIdentifiers() { // this has to be in replaceIdentifiers because it's after required* fields are set this.preventDuplicates(); diff --git a/ghost/core/test/unit/server/data/importer/importers/data/products.test.js b/ghost/core/test/unit/server/data/importer/importers/data/products.test.js new file mode 100644 index 0000000000..028c412bc4 --- /dev/null +++ b/ghost/core/test/unit/server/data/importer/importers/data/products.test.js @@ -0,0 +1,64 @@ +const assert = require('assert'); +const ProductsImporter = require('../../../../../../../core/server/data/importer/importers/data/products'); + +const fakeProducts = [{ + id: 'product_1', + name: 'New One', + slug: 'new-one', + active: 1, + welcome_page_url: null, + visibility: 'public', + trial_days: 0, + description: null, + type: 'paid', + created_at: '2022-10-20T11:11:32.000Z', + updated_at: '2022-10-21T04:47:42.000Z', + monthly_price_id: 'price_1', + yearly_price_id: 'price_2' +}]; + +const fakePrices = [{ + id: 'price_1', + stripe_price_id: 'price_YYYYYYYYYYYYYYYYYYYYYYYY', + stripe_product_id: 'prod_YYYYYYYYYYYYYY', + active: 1, + nickname: 'Monthly', + currency: 'usd', + amount: 500, + type: 'recurring', + interval: 'month', + description: null, + created_at: '2022-10-21T04:57:17.000Z', + updated_at: '2022-10-21T04:57:17.000Z' +}, +{ + id: 'price_2', + stripe_price_id: 'price_XXXXXXXXXXXXXXXXXXXXXXXX', + stripe_product_id: 'prod_XXXXXXXXXXXXXX', + active: 1, + nickname: 'Yearly', + currency: 'usd', + amount: 5000, + type: 'recurring', + interval: 'year', + description: null, + created_at: '2022-10-27T02:51:28.000Z', + updated_at: '2022-10-27T02:51:28.000Z' +}]; + +describe('ProductsImporter', function () { + describe('#beforeImport', function () { + it('Removes the sender_email column', function () { + const importer = new ProductsImporter({products: fakeProducts, stripe_prices: fakePrices}); + + importer.beforeImport(); + assert(importer.dataToImport.length === 1); + + const product = importer.dataToImport[0]; + + assert(product.currency === 'usd'); + assert(product.monthly_price === 500); + assert(product.yearly_price === 5000); + }); + }); +});