diff --git a/core/frontend/services/themes/middleware.js b/core/frontend/services/themes/middleware.js index 44c99bbf4a..90933fa74d 100644 --- a/core/frontend/services/themes/middleware.js +++ b/core/frontend/services/themes/middleware.js @@ -133,7 +133,9 @@ function updateLocalTemplateOptions(req, res, next) { firstname: req.member.name && req.member.name.split(' ')[0], avatar_image: req.member.avatar_image, subscriptions: req.member.stripe.subscriptions, - paid: req.member.stripe.subscriptions.length !== 0 + paid: req.member.stripe.subscriptions.filter((subscription) => { + return ['active', 'trialing', 'unpaid', 'past_due'].includes(subscription.status); + }).length !== 0 } : null; hbs.updateLocalTemplateOptions(res.locals, _.merge({}, localTemplateOptions, { diff --git a/core/server/models/member.js b/core/server/models/member.js index 829dc9fecd..f39bfb803f 100644 --- a/core/server/models/member.js +++ b/core/server/models/member.js @@ -45,7 +45,7 @@ const Member = ghostBookshelf.Model.extend({ 'customer_id', 'id', 'customer_id' - ).query('whereIn', 'status', ['active', 'trialing', 'past_due', 'unpaid']); + ); }, serialize(options) { diff --git a/core/server/services/members/content-gating.js b/core/server/services/members/content-gating.js index ef83a3ca43..33041a968b 100644 --- a/core/server/services/members/content-gating.js +++ b/core/server/services/members/content-gating.js @@ -23,7 +23,10 @@ function checkPostAccess(post, member) { return PERMIT_ACCESS; } - const memberHasPlan = member.stripe && member.stripe.subscriptions && member.stripe.subscriptions.length; + const activeSubscriptions = member.stripe && member.stripe.subscriptions && member.stripe.subscriptions.filter((subscription) => { + return ['active', 'trialing', 'unpaid', 'past_due'].includes(subscription.status); + }); + const memberHasPlan = activeSubscriptions && activeSubscriptions.length; if (post.visibility === 'paid' && memberHasPlan) { return PERMIT_ACCESS; diff --git a/core/server/services/members/utils.js b/core/server/services/members/utils.js index f90cab87d1..5b1aea6d14 100644 --- a/core/server/services/members/utils.js +++ b/core/server/services/members/utils.js @@ -10,6 +10,8 @@ module.exports.formattedMemberResponse = function formattedMemberResponse(member avatar_image: member.avatar_image, subscribed: !!member.subscribed, subscriptions: member.stripe ? member.stripe.subscriptions : [], - paid: member.stripe ? member.stripe.subscriptions.length !== 0 : false + paid: member.stripe && member.stripe.subscriptions && member.stripe.subscriptions.filter((subscription) => { + return ['active', 'trialing', 'unpaid', 'past_due'].includes(subscription.status); + }).length !== 0 }; }; diff --git a/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js b/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js index 63ba253ffa..40d7b5851a 100644 --- a/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js +++ b/test/unit/api/canary/utils/serializers/output/utils/post-gating_spec.js @@ -111,6 +111,34 @@ describe('Unit: canary/utils/serializers/output/utils/post-gating', function () attrs.html.should.eql(''); }); + it('should hide content attributes when visibility is "paid" and member has cancelled subscription', function () { + const attrs = { + visibility: 'paid', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; + + const frame = { + options: {}, + original: { + context: { + member: { + stripe: { + subscriptions: [{ + status: 'canceled' + }] + } + } + } + } + }; + + gating.forPost(attrs, frame); + + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); + it('should NOT hide content attributes when visibility is "paid" and member has a subscription', function () { const attrs = { visibility: 'paid', @@ -124,7 +152,9 @@ describe('Unit: canary/utils/serializers/output/utils/post-gating', function () context: { member: { stripe: { - subscriptions: ['I pay money dollaz'] + subscriptions: [{ + status: 'active' + }] } } } diff --git a/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js b/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js index f612f03fd5..0cd9b2c6ba 100644 --- a/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js +++ b/test/unit/api/v2/utils/serializers/output/utils/post-gating_spec.js @@ -107,6 +107,34 @@ describe('Unit: v2/utils/serializers/output/utils/post-gating', function () { attrs.html.should.eql(''); }); + it('should hide content attributes when visibility is "paid" and member has cancelled subscription', function () { + const attrs = { + visibility: 'paid', + plaintext: 'I see dead people', + html: '

What\'s the matter?

' + }; + + const frame = { + options: {}, + original: { + context: { + member: { + stripe: { + subscriptions: [{ + status: 'canceled' + }] + } + } + } + } + }; + + gating.forPost(attrs, frame); + + attrs.plaintext.should.eql(''); + attrs.html.should.eql(''); + }); + it('should NOT hide content attributes when visibility is "paid" and member has a subscription', function () { const attrs = { visibility: 'paid', @@ -115,11 +143,14 @@ describe('Unit: v2/utils/serializers/output/utils/post-gating', function () { }; const frame = { + options: {}, original: { context: { member: { stripe: { - subscriptions: ['I pay money dollaz'] + subscriptions: [{ + status: 'active' + }] } } }