From febffb3f0774d279e411dadb714ed9a736ad2136 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 14:26:49 -0600 Subject: [PATCH 1/3] Revert "Fix double subscriptions, second attempt (#14345)" This reverts commit 1a5cba57b7e45cc14fa2a4bc752fa2826e21bc58. --- test/api/unit/libs/payments/apple.test.js | 3 -- test/api/unit/libs/payments/payments.test.js | 13 ------ website/server/libs/payments/subscriptions.js | 40 +++++++++++++++---- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/test/api/unit/libs/payments/apple.test.js b/test/api/unit/libs/payments/apple.test.js index a086677292..1aefe2cb51 100644 --- a/test/api/unit/libs/payments/apple.test.js +++ b/test/api/unit/libs/payments/apple.test.js @@ -326,12 +326,9 @@ describe('Apple Payments', () => { it('errors when a user is already subscribed', async () => { payments.createSubscription.restore(); user = new User(); - user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await user.save(); await applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing); - user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - await user.save(); await expect(applePayments.subscribe(sku, user, receipt, headers, nextPaymentProcessing)) .to.eventually.be.rejected.and.to.eql({ diff --git a/test/api/unit/libs/payments/payments.test.js b/test/api/unit/libs/payments/payments.test.js index 7e306f94fd..48d6325546 100644 --- a/test/api/unit/libs/payments/payments.test.js +++ b/test/api/unit/libs/payments/payments.test.js @@ -350,10 +350,6 @@ describe('payments/index', () => { }); context('Purchasing a subscription for self', () => { - beforeEach(() => { - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - }); - it('creates a subscription', async () => { expect(user.purchased.plan.planId).to.not.exist; @@ -380,7 +376,6 @@ describe('payments/index', () => { user.purchased.plan = plan; user.purchased.plan.dateTerminated = moment(new Date()).add(2, 'months'); expect(user.purchased.plan.extraMonths).to.eql(0); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -391,7 +386,6 @@ describe('payments/index', () => { user.purchased.plan = plan; user.purchased.plan.dateTerminated = moment(new Date()).subtract(2, 'months'); expect(user.purchased.plan.extraMonths).to.eql(0); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -401,7 +395,6 @@ describe('payments/index', () => { it('does not reset Gold-to-Gems cap on additional subscription', async () => { user.purchased.plan = plan; user.purchased.plan.gemsBought = 10; - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); @@ -455,10 +448,6 @@ describe('payments/index', () => { }); context('Block subscription perks', () => { - beforeEach(() => { - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); - }); - it('adds block months to plan.consecutive.offset', async () => { await api.createSubscription(data); @@ -497,7 +486,6 @@ describe('payments/index', () => { data.sub.key = 'basic_12mo'; await api.createSubscription(data); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); await api.createSubscription(data); expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25); @@ -536,7 +524,6 @@ describe('payments/index', () => { now: mayMysteryItemTimeframe, toFake: ['Date'], }); - data.user.purchased.plan.dateUpdated = moment().subtract(1, 'hours').toDate(); }); afterEach(() => { diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 1387d4b5c8..80401f21de 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -11,10 +11,10 @@ import { // eslint-disable-line import/no-cycle model as Group, basicFields as basicGroupFields, } from '../../models/group'; +import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle import { NotAuthorized, NotFound, - TooManyRequests, } from '../errors'; import shared from '../../../common'; import { sendNotification as sendPushNotification } from '../pushNotifications'; // eslint-disable-line import/no-cycle @@ -80,9 +80,19 @@ async function createSubscription (data) { let emailType = 'subscription-begins'; let recipientIsSubscribed = recipient.isSubscribed(); - if (data.user && !data.gift && !data.groupId && data.customerId !== 'group-plan') { - if (moment().diff(data.user.purchased.plan.dateUpdated, 'minutes') < 3) { - throw new TooManyRequests('Subscription already processed, likely duplicate request'); + if (data.user && !data.gift && !data.groupId) { + const unlockedUser = await User.findOneAndUpdate( + { + _id: data.user._id, + $or: [ + { _subSignature: 'NOT_RUNNING' }, + { _subSignature: { $exists: false } }, + ], + }, + { $set: { _subSignature: 'SUB_IN_PROGRESS' } }, + ); + if (!unlockedUser) { + throw new NotFound('User not found or subscription already processing.'); } } @@ -289,10 +299,6 @@ async function createSubscription (data) { } } - if (group) await group.save(); - if (data.user && data.user.isModified()) await data.user.save(); - if (data.gift) await data.gift.member.save(); - slack.sendSubscriptionNotification({ buyer: { id: data.user._id, @@ -309,6 +315,24 @@ async function createSubscription (data) { groupId, autoRenews, }); + + if (group) { + await group.save(); + } + if (data.user) { + if (data.user.isModified()) { + await data.user.save(); + } + if (!data.gift && !data.groupId) { + await User.findOneAndUpdate( + { _id: data.user._id }, + { $set: { _subSignature: 'NOT_RUNNING' } }, + ); + } + } + if (data.gift) { + await data.gift.member.save(); + } } // Cancels a subscription or group plan, setting termination to happen later From 15353eba8a179c2a25f0c3fa4189f63aa94fdd95 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 15:12:14 -0600 Subject: [PATCH 2/3] fix(subs): roll all the way back, didn't work :( --- website/server/libs/payments/subscriptions.js | 39 ++----------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/website/server/libs/payments/subscriptions.js b/website/server/libs/payments/subscriptions.js index 80401f21de..2052dc4c9a 100644 --- a/website/server/libs/payments/subscriptions.js +++ b/website/server/libs/payments/subscriptions.js @@ -11,7 +11,6 @@ import { // eslint-disable-line import/no-cycle model as Group, basicFields as basicGroupFields, } from '../../models/group'; -import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle import { NotAuthorized, NotFound, @@ -80,22 +79,6 @@ async function createSubscription (data) { let emailType = 'subscription-begins'; let recipientIsSubscribed = recipient.isSubscribed(); - if (data.user && !data.gift && !data.groupId) { - const unlockedUser = await User.findOneAndUpdate( - { - _id: data.user._id, - $or: [ - { _subSignature: 'NOT_RUNNING' }, - { _subSignature: { $exists: false } }, - ], - }, - { $set: { _subSignature: 'SUB_IN_PROGRESS' } }, - ); - if (!unlockedUser) { - throw new NotFound('User not found or subscription already processing.'); - } - } - // If we are buying a group subscription if (data.groupId) { const groupFields = basicGroupFields.concat(' purchased'); @@ -299,6 +282,10 @@ async function createSubscription (data) { } } + if (group) await group.save(); + if (data.user && data.user.isModified()) await data.user.save(); + if (data.gift) await data.gift.member.save(); + slack.sendSubscriptionNotification({ buyer: { id: data.user._id, @@ -315,24 +302,6 @@ async function createSubscription (data) { groupId, autoRenews, }); - - if (group) { - await group.save(); - } - if (data.user) { - if (data.user.isModified()) { - await data.user.save(); - } - if (!data.gift && !data.groupId) { - await User.findOneAndUpdate( - { _id: data.user._id }, - { $set: { _subSignature: 'NOT_RUNNING' } }, - ); - } - } - if (data.gift) { - await data.gift.member.save(); - } } // Cancels a subscription or group plan, setting termination to happen later From 06a8d2bbd76fae8af38d5d81ea0cd3e593c81c00 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Fri, 18 Nov 2022 15:12:32 -0600 Subject: [PATCH 3/3] 4.249.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f920e8ad51..ced5cdd9f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.249.3", + "version": "4.249.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index dc545955ac..1076507d4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.249.3", + "version": "4.249.4", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.19.6",