diff --git a/services/web/app/src/Features/Subscription/SubscriptionUpdater.js b/services/web/app/src/Features/Subscription/SubscriptionUpdater.js
index 704335955e..fae13eec00 100644
--- a/services/web/app/src/Features/Subscription/SubscriptionUpdater.js
+++ b/services/web/app/src/Features/Subscription/SubscriptionUpdater.js
@@ -11,6 +11,8 @@ const logger = require('@overleaf/logger')
const Features = require('../../infrastructure/Features')
const UserAuditLogHandler = require('../User/UserAuditLogHandler')
const { SSOConfig } = require('../../models/SSOConfig')
+const Modules = require('../../infrastructure/Modules')
+const Settings = require('@overleaf/settings')
/**
* Change the admin of the given subscription.
@@ -249,6 +251,29 @@ async function _deleteAndReplaceSubscriptionFromRecurly(
)
}
+async function _notifySupportSubscriptionDeletionSkipped(
+ subscription,
+ recurlySubscription,
+ hasGroupSSOEnabled
+) {
+ const adminUrl = `${Settings.adminUrl + '/admin/user/' + subscription.admin_id}`
+ const groupUrl = `${Settings.adminUrl + '/admin/group/' + subscription._id}`
+ let message = `\n**Recurly account:** ${recurlySubscription?.account?.url}`
+ message += `\n**Group admin:** ${adminUrl}`
+ message += `\n**Group:** ${groupUrl}`
+ message += `\n**Managed users enabled:** ${subscription?.managedUsersEnabled}`
+ message += `\n**SSO enabled:** ${hasGroupSSOEnabled}`
+
+ const data = {
+ subject: 'Skipped deleting pro group subscription',
+ inbox: 'support',
+ tags: 'Group subscription',
+ message,
+ }
+
+ await Modules.promises.hooks.fire('sendSupportRequest', data)
+}
+
async function updateSubscriptionFromRecurly(
recurlySubscription,
subscription,
@@ -258,6 +283,18 @@ async function updateSubscriptionFromRecurly(
const hasManagedUsersFeature =
Features.hasFeature('saas') && subscription?.managedUsersEnabled
+ let hasGroupSSOEnabled = false
+ if (subscription?.ssoConfig) {
+ const ssoConfig = await SSOConfig.findOne({
+ _id: subscription.ssoConfig._id || subscription.ssoConfig,
+ })
+ .lean()
+ .exec()
+ if (ssoConfig.enabled) {
+ hasGroupSSOEnabled = true
+ }
+ }
+
// If a payment lapses and if the group is managed or has group SSO, as a temporary measure we need to
// make sure that the group continues as-is and no destructive actions are taken.
if (hasManagedUsersFeature) {
@@ -265,28 +302,39 @@ async function updateSubscriptionFromRecurly(
{ subscriptionId: subscription._id },
'expired subscription has managedUsers feature enabled, skipping deletion'
)
- } else {
- let hasGroupSSOEnabled = false
- if (subscription?.ssoConfig) {
- const ssoConfig = await SSOConfig.findOne({
- _id: subscription.ssoConfig._id || subscription.ssoConfig,
- })
- .lean()
- .exec()
- if (ssoConfig.enabled) {
- hasGroupSSOEnabled = true
- }
- }
-
- if (hasGroupSSOEnabled) {
+ try {
+ await _notifySupportSubscriptionDeletionSkipped(
+ subscription,
+ recurlySubscription,
+ hasGroupSSOEnabled
+ )
+ } catch (e) {
logger.warn(
{ subscriptionId: subscription._id },
- 'expired subscription has groupSSO feature enabled, skipping deletion'
+ 'unable to send notification to support that subscription deletion was skipped'
)
- } else {
- await deleteSubscription(subscription, requesterData)
}
+ } else if (hasGroupSSOEnabled) {
+ logger.warn(
+ { subscriptionId: subscription._id },
+ 'expired subscription has groupSSO feature enabled, skipping deletion'
+ )
+ try {
+ await _notifySupportSubscriptionDeletionSkipped(
+ subscription,
+ recurlySubscription,
+ hasGroupSSOEnabled
+ )
+ } catch (e) {
+ logger.warn(
+ { subscriptionId: subscription._id },
+ 'unable to send notification to support that subscription deletion was skipped'
+ )
+ }
+ } else {
+ await deleteSubscription(subscription, requesterData)
}
+
return
}
const updatedPlanCode = recurlySubscription.plan.plan_code
diff --git a/services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js b/services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js
index 3d8212201f..e0e8d666bf 100644
--- a/services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js
+++ b/services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js
@@ -13,6 +13,9 @@ describe('SubscriptionUpdater', function () {
plan: {
plan_code: this.recurlyPlan.planCode,
},
+ account: {
+ url: 'test_url',
+ },
}
this.adminUser = { _id: (this.adminuser_id = '5208dd34438843e2db000007') }
@@ -26,6 +29,7 @@ describe('SubscriptionUpdater', function () {
save: sinon.stub().resolves(),
planCode: 'student_or_something',
recurlySubscription_id: 'abc123def456fab789',
+ managedUsersEnabled: false,
}
this.user_id = this.adminuser_id
@@ -120,6 +124,7 @@ describe('SubscriptionUpdater', function () {
},
},
],
+ adminUrl: 'test_admin_url',
}
this.UserFeaturesUpdater = {
@@ -177,6 +182,13 @@ describe('SubscriptionUpdater', function () {
'../Analytics/AnalyticsManager': this.AnalyticsManager,
'../../infrastructure/Features': this.Features,
'../User/UserAuditLogHandler': this.UserAuditLogHandler,
+ '../../infrastructure/Modules': (this.Modules = {
+ promises: {
+ hooks: {
+ fire: sinon.stub().resolves(),
+ },
+ },
+ }),
},
})
})
@@ -316,6 +328,52 @@ describe('SubscriptionUpdater', function () {
{}
)
this.SubscriptionModel.deleteOne.should.not.have.been.called
+ const adminUrl = `${this.Settings.adminUrl + '/admin/user/' + this.subscription.admin_id}`
+ const groupUrl = `${this.Settings.adminUrl + '/admin/group/' + this.subscription._id}`
+ let message = `\n**Recurly account:** ${this.recurlySubscription.account?.url}`
+ message += `\n**Group admin:** ${adminUrl}`
+ message += `\n**Group:** ${groupUrl}`
+ message += `\n**Managed users enabled:** false`
+ message += `\n**SSO enabled:** true`
+ expect(this.Modules.promises.hooks.fire).to.have.been.calledOnce
+ expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
+ 'sendSupportRequest',
+ {
+ subject: 'Skipped deleting pro group subscription',
+ inbox: 'support',
+ tags: 'Group subscription',
+ message,
+ }
+ )
+ })
+
+ it('should not remove the subscription when expired if it has managed users is enabled', async function () {
+ this.Features.hasFeature.withArgs('saas').returns(true)
+ this.subscription.managedUsersEnabled = true
+
+ this.recurlySubscription.state = 'expired'
+ await this.SubscriptionUpdater.promises.updateSubscriptionFromRecurly(
+ this.recurlySubscription,
+ this.subscription,
+ {}
+ )
+ this.SubscriptionModel.deleteOne.should.not.have.been.called
+ const adminUrl = `${this.Settings.adminUrl + '/admin/user/' + this.subscription.admin_id}`
+ const groupUrl = `${this.Settings.adminUrl + '/admin/group/' + this.subscription._id}`
+ let message = `\n**Recurly account:** ${this.recurlySubscription.account?.url}`
+ message += `\n**Group admin:** ${adminUrl}`
+ message += `\n**Group:** ${groupUrl}`
+ message += `\n**Managed users enabled:** true`
+ message += `\n**SSO enabled:** false`
+ expect(this.Modules.promises.hooks.fire).to.have.been.calledWith(
+ 'sendSupportRequest',
+ {
+ subject: 'Skipped deleting pro group subscription',
+ inbox: 'support',
+ tags: 'Group subscription',
+ message,
+ }
+ )
})
it('should update all the users features', async function () {