diff --git a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js index f7a4908355..04036ce17b 100644 --- a/services/web/app/src/Features/Subscription/TeamInvitesHandler.js +++ b/services/web/app/src/Features/Subscription/TeamInvitesHandler.js @@ -65,40 +65,36 @@ async function importInvite(subscription, inviterName, email, token, sentAt) { return subscription.save() } -async function _deleteUserSubscription(userId, ipAddress) { +async function _deleteUserSubscription(subscription, userId, ipAddress) { // Delete released user subscription to make it on a free plan - const subscription = - await SubscriptionLocator.promises.getUsersSubscription(userId) - if (subscription) { - logger.debug( - { - subscriptionId: subscription._id, - }, - 'deleting user subscription' - ) + logger.debug( + { + subscriptionId: subscription._id, + }, + 'deleting user subscription' + ) - const deleterData = { - id: userId, - ip: ipAddress, - } - await SubscriptionUpdater.promises.deleteSubscription( - subscription, - deleterData - ) + const deleterData = { + id: userId, + ip: ipAddress, + } + await SubscriptionUpdater.promises.deleteSubscription( + subscription, + deleterData + ) - // Terminate the subscription in Recurly - if (subscription.recurlySubscription_id) { - try { - await RecurlyClient.promises.terminateSubscriptionByUuid( - subscription.recurlySubscription_id - ) - } catch (err) { - logger.error( - { err, subscriptionId: subscription._id }, - 'terminating subscription failed' - ) - } + // Terminate the subscription in Recurly + if (subscription.recurlySubscription_id) { + try { + await RecurlyClient.promises.terminateSubscriptionByUuid( + subscription.recurlySubscription_id + ) + } catch (err) { + logger.error( + { err, subscriptionId: subscription._id }, + 'terminating subscription failed' + ) } } } @@ -117,7 +113,17 @@ async function acceptInvite(token, userId, ipAddress) { ) if (subscription.managedUsersEnabled) { - await _deleteUserSubscription(userId, ipAddress) + // check if user has a personal subscription + const userSubscription = + await SubscriptionLocator.promises.getUsersSubscription(userId) + + if (userSubscription) { + // if user has a personal subscription and joins a managed group, delete their personal subscription + // but make sure that it's not the same subscription as the group one. + if (!userSubscription._id.equals(subscription._id)) { + await _deleteUserSubscription(userSubscription, userId, ipAddress) + } + } await Modules.promises.hooks.fire( 'enrollInManagedSubscription', userId, diff --git a/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js b/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js index b15232c822..eec4d0d7a1 100644 --- a/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js +++ b/services/web/test/unit/src/Subscription/TeamInvitesHandlerTests.js @@ -344,12 +344,27 @@ describe('TeamInvitesHandler', function () { email: 'tyrion@example.com', } + this.user_subscription = { + id: '66264b9125930b976cc0811e', + _id: new ObjectId('66264b9125930b976cc0811e'), + groupPlan: false, + recurlySubscription_id: 'fa1b2cfa156gh', + admin_id: '123456789', + member_ids: [], + teamInvites: [], + save: sinon.stub().resolves(), + } + this.ipAddress = '127.0.0.1' this.UserGetter.promises.getUserByAnyEmail .withArgs(this.user.email) .resolves(this.user) + this.SubscriptionLocator.promises.getUsersSubscription + .withArgs(this.user.id) + .resolves(this.user_subscription) + this.subscription.teamInvites.push({ email: 'john.snow@example.com', token: 'dddddddd', @@ -421,12 +436,12 @@ describe('TeamInvitesHandler', function () { ) sinon.assert.calledWith( this.SubscriptionUpdater.promises.deleteSubscription, - this.subscription, + this.user_subscription, { id: this.user.id, ip: this.ipAddress } ) sinon.assert.calledWith( this.RecurlyClient.promises.terminateSubscriptionByUuid, - this.subscription.recurlySubscription_id + this.user_subscription.recurlySubscription_id ) sinon.assert.calledWith( this.Modules.promises.hooks.fire, @@ -435,6 +450,23 @@ describe('TeamInvitesHandler', function () { this.subscription ) }) + + it('should not delete the users subscription if that subscription is also the join target', async function () { + this.subscription.managedUsersEnabled = true + this.SubscriptionLocator.promises.getUsersSubscription + .withArgs(this.user.id) + .resolves(this.subscription) + + await this.TeamInvitesHandler.promises.acceptInvite( + 'dddddddd', + this.user.id, + this.ipAddress + ) + + sinon.assert.notCalled( + this.SubscriptionUpdater.promises.deleteSubscription + ) + }) }) describe('with group SSO enabled', function () {