Fixed validation when tierId is missing during Stripe checkout (#20195)

refs https://linear.app/tryghost/issue/SLO-90
refs
https://www.notion.so/ghost/Decoupling-Members-from-Stripe-13b644d4dccb43ea83f683473c690b82

- the members API didn't support passing a Stripe Price ID directly
during checkout since end of 2022. However, we did not update the param
validation accordingly
This commit is contained in:
Sag 2024-05-13 14:47:39 +02:00 committed by GitHub
parent 534c8879f9
commit cb8213e7d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 92 additions and 14 deletions

View File

@ -204,7 +204,6 @@ module.exports = class RouterController {
* @returns
*/
async _getSubscriptionCheckoutData(body) {
const ghostPriceId = body.priceId;
const tierId = body.tierId;
const offerId = body.offerId;
@ -213,33 +212,35 @@ module.exports = class RouterController {
let offer;
// Validate basic input
if (!ghostPriceId && !offerId && !tierId && !cadence) {
if (!offerId && !tierId) {
logging.error('[RouterController._getSubscriptionCheckoutData] Expected offerId or tierId, received none');
throw new BadRequestError({
message: tpl(messages.badRequest)
message: tpl(messages.badRequest),
context: 'Expected offerId or tierId, received none'
});
}
if (offerId && (ghostPriceId || (tierId && cadence))) {
if (offerId && tierId) {
logging.error('[RouterController._getSubscriptionCheckoutData] Expected offerId or tierId, received both');
throw new BadRequestError({
message: tpl(messages.badRequest)
});
}
if (ghostPriceId && tierId && cadence) {
throw new BadRequestError({
message: tpl(messages.badRequest)
message: tpl(messages.badRequest),
context: 'Expected offerId or tierId, received both'
});
}
if (tierId && !cadence) {
logging.error('[RouterController._getSubscriptionCheckoutData] Expected cadence to be "month" or "year", received ', cadence);
throw new BadRequestError({
message: tpl(messages.badRequest)
message: tpl(messages.badRequest),
context: 'Expected cadence to be "month" or "year", received ' + cadence
});
}
if (cadence && cadence !== 'month' && cadence !== 'year') {
if (tierId && cadence && cadence !== 'month' && cadence !== 'year') {
logging.error('[RouterController._getSubscriptionCheckoutData] Expected cadence to be "month" or "year", received ', cadence);
throw new BadRequestError({
message: tpl(messages.badRequest)
message: tpl(messages.badRequest),
context: 'Expected cadence to be "month" or "year", received "' + cadence + '"'
});
}

View File

@ -1,4 +1,7 @@
const sinon = require('sinon');
const assert = require('assert').strict;
const errors = require('@tryghost/errors');
const RouterController = require('../../../../lib/controllers/RouterController');
describe('RouterController', function () {
@ -86,6 +89,80 @@ describe('RouterController', function () {
})).should.be.true();
});
describe('_getSubscriptionCheckoutData', function () {
it('returns a BadRequestError if both offerId and tierId are missing', async function () {
const routerController = new RouterController({
tiersService,
paymentsService,
offersAPI,
stripeAPIService,
labsService
});
try {
await routerController._getSubscriptionCheckoutData({body: {}});
assert.fail('Expected function to throw BadRequestError');
} catch (error) {
assert(error instanceof errors.BadRequestError, 'Error should be an instance of BadRequestError');
assert.equal(error.context, 'Expected offerId or tierId, received none');
}
});
it('returns a BadRequestError if both offerId and tierId are provided', async function () {
const routerController = new RouterController({
tiersService,
paymentsService,
offersAPI,
stripeAPIService,
labsService
});
try {
await routerController._getSubscriptionCheckoutData({tierId: 'tier_123', offerId: 'offer_123'});
assert.fail('Expected function to throw BadRequestError');
} catch (error) {
assert(error instanceof errors.BadRequestError, 'Error should be an instance of BadRequestError');
assert.equal(error.context, 'Expected offerId or tierId, received both');
}
});
it('returns a BadRequestError if tierId is provided wihout a cadence', async function () {
const routerController = new RouterController({
tiersService,
paymentsService,
offersAPI,
stripeAPIService,
labsService
});
try {
await routerController._getSubscriptionCheckoutData({tierId: 'tier_123'});
assert.fail('Expected function to throw BadRequestError');
} catch (error) {
assert(error instanceof errors.BadRequestError, 'Error should be an instance of BadRequestError');
assert.equal(error.context, 'Expected cadence to be "month" or "year", received undefined');
}
});
it('returns a BadRequestError if tierId is provided wihout a valid cadence', async function () {
const routerController = new RouterController({
tiersService,
paymentsService,
offersAPI,
stripeAPIService,
labsService
});
try {
await routerController._getSubscriptionCheckoutData({tierId: 'tier_123', cadence: 'day'});
assert.fail('Expected function to throw BadRequestError');
} catch (error) {
assert(error instanceof errors.BadRequestError, 'Error should be an instance of BadRequestError');
assert.equal(error.context, 'Expected cadence to be "month" or "year", received "day"');
}
});
});
afterEach(function () {
sinon.restore();
});