mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-06 07:39:02 +02:00
Merge pull request #25843 from overleaf/ii-managed-users-make-unmanaged-terminate-subscription
[web] Terminate subscription when joining a managed group GitOrigin-RevId: 2a4f2fd57e1319970780043a633fb8027593e5d4
This commit is contained in:
@@ -736,6 +736,21 @@ async function failInvoice(invoiceId) {
|
||||
await client.markInvoiceFailed(invoiceId)
|
||||
}
|
||||
|
||||
async function terminateSubscriptionByUuid(subscriptionUuid) {
|
||||
const subscription = await client.terminateSubscription(
|
||||
'uuid-' + subscriptionUuid,
|
||||
{
|
||||
body: {
|
||||
refund: 'none',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
logger.debug({ subscriptionUuid }, 'subscription terminated')
|
||||
|
||||
return subscription
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
errors: recurly.errors,
|
||||
|
||||
@@ -759,6 +774,7 @@ module.exports = {
|
||||
resumeSubscriptionByUuid: callbackify(resumeSubscriptionByUuid),
|
||||
getPastDueInvoices: callbackify(getPastDueInvoices),
|
||||
failInvoice: callbackify(failInvoice),
|
||||
terminateSubscriptionByUuid: callbackify(terminateSubscriptionByUuid),
|
||||
|
||||
promises: {
|
||||
getSubscription,
|
||||
@@ -781,5 +797,6 @@ module.exports = {
|
||||
getPlan,
|
||||
getPastDueInvoices,
|
||||
failInvoice,
|
||||
terminateSubscriptionByUuid,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ async function acceptInvite(req, res, next) {
|
||||
const subscription = await TeamInvitesHandler.promises.acceptInvite(
|
||||
token,
|
||||
userId,
|
||||
{ initiatorId: userId, ipAddress: req.ip }
|
||||
req.ip
|
||||
)
|
||||
const groupSSOActive = (
|
||||
await Modules.promises.hooks.fire('hasGroupSSOEnabled', subscription)
|
||||
|
||||
@@ -22,6 +22,7 @@ const {
|
||||
callbackifyMultiResult,
|
||||
} = require('@overleaf/promise-utils')
|
||||
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
|
||||
const RecurlyClient = require('./RecurlyClient')
|
||||
|
||||
async function getInvite(token) {
|
||||
const subscription = await Subscription.findOne({
|
||||
@@ -64,11 +65,50 @@ async function importInvite(subscription, inviterName, email, token, sentAt) {
|
||||
return subscription.save()
|
||||
}
|
||||
|
||||
async function acceptInvite(token, userId, auditLog) {
|
||||
async function _deleteUserSubscription(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'
|
||||
)
|
||||
|
||||
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'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function acceptInvite(token, userId, ipAddress) {
|
||||
const { invite, subscription } = await getInvite(token)
|
||||
if (!invite) {
|
||||
throw new Errors.NotFoundError('invite not found')
|
||||
}
|
||||
const auditLog = { initiatorId: userId, ipAddress }
|
||||
|
||||
await SubscriptionUpdater.promises.addUserToGroup(
|
||||
subscription._id,
|
||||
@@ -77,6 +117,7 @@ async function acceptInvite(token, userId, auditLog) {
|
||||
)
|
||||
|
||||
if (subscription.managedUsersEnabled) {
|
||||
await _deleteUserSubscription(userId, ipAddress)
|
||||
await Modules.promises.hooks.fire(
|
||||
'enrollInManagedSubscription',
|
||||
userId,
|
||||
|
||||
@@ -692,4 +692,20 @@ describe('RecurlyClient', function () {
|
||||
).to.be.rejectedWith(Error)
|
||||
})
|
||||
})
|
||||
|
||||
describe('terminateSubscriptionByUuid', function () {
|
||||
it('should attempt to terminate the subscription', async function () {
|
||||
this.client.terminateSubscription = sinon
|
||||
.stub()
|
||||
.resolves(this.recurlySubscription)
|
||||
const subscription =
|
||||
await this.RecurlyClient.promises.terminateSubscriptionByUuid(
|
||||
this.subscription.uuid
|
||||
)
|
||||
expect(subscription).to.deep.equal(this.recurlySubscription)
|
||||
expect(this.client.terminateSubscription).to.be.calledWith(
|
||||
'uuid-' + this.subscription.uuid
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -29,6 +29,7 @@ describe('TeamInvitesHandler', function () {
|
||||
this.subscription = {
|
||||
id: '55153a8014829a865bbf700d',
|
||||
_id: new ObjectId('55153a8014829a865bbf700d'),
|
||||
recurlySubscription_id: '1a2b3c4d5e6f7g',
|
||||
admin_id: this.manager._id,
|
||||
groupPlan: true,
|
||||
member_ids: [],
|
||||
@@ -54,6 +55,7 @@ describe('TeamInvitesHandler', function () {
|
||||
this.SubscriptionUpdater = {
|
||||
promises: {
|
||||
addUserToGroup: sinon.stub().resolves(),
|
||||
deleteSubscription: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -109,6 +111,12 @@ describe('TeamInvitesHandler', function () {
|
||||
|
||||
this.Subscription.findOne.resolves(this.subscription)
|
||||
|
||||
this.RecurlyClient = {
|
||||
promises: {
|
||||
terminateSubscriptionByUuid: sinon.stub().resolves(),
|
||||
},
|
||||
}
|
||||
|
||||
this.TeamInvitesHandler = SandboxedModule.require(modulePath, {
|
||||
requires: {
|
||||
'mongodb-legacy': { ObjectId },
|
||||
@@ -126,6 +134,7 @@ describe('TeamInvitesHandler', function () {
|
||||
'../../infrastructure/Modules': (this.Modules = {
|
||||
promises: { hooks: { fire: sinon.stub().resolves() } },
|
||||
}),
|
||||
'./RecurlyClient': this.RecurlyClient,
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -335,6 +344,8 @@ describe('TeamInvitesHandler', function () {
|
||||
email: 'tyrion@example.com',
|
||||
}
|
||||
|
||||
this.ipAddress = '127.0.0.1'
|
||||
|
||||
this.UserGetter.promises.getUserByAnyEmail
|
||||
.withArgs(this.user.email)
|
||||
.resolves(this.user)
|
||||
@@ -350,7 +361,8 @@ describe('TeamInvitesHandler', function () {
|
||||
it('adds the user to the team', async function () {
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
this.SubscriptionUpdater.promises.addUserToGroup
|
||||
.calledWith(this.subscription._id, this.user.id)
|
||||
@@ -360,7 +372,8 @@ describe('TeamInvitesHandler', function () {
|
||||
it('removes the invite from the subscription', async function () {
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
this.Subscription.updateOne
|
||||
.calledWith(
|
||||
@@ -375,7 +388,8 @@ describe('TeamInvitesHandler', function () {
|
||||
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
sinon.assert.called(
|
||||
this.NotificationsBuilder.promises.groupInvitation(
|
||||
@@ -389,7 +403,8 @@ describe('TeamInvitesHandler', function () {
|
||||
it('should not schedule an SSO invite reminder', async function () {
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
sinon.assert.notCalled(this.Modules.promises.hooks.fire)
|
||||
})
|
||||
@@ -401,7 +416,17 @@ describe('TeamInvitesHandler', function () {
|
||||
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.SubscriptionUpdater.promises.deleteSubscription,
|
||||
this.subscription,
|
||||
{ id: this.user.id, ip: this.ipAddress }
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.RecurlyClient.promises.terminateSubscriptionByUuid,
|
||||
this.subscription.recurlySubscription_id
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.Modules.promises.hooks.fire,
|
||||
@@ -421,7 +446,8 @@ describe('TeamInvitesHandler', function () {
|
||||
|
||||
await this.TeamInvitesHandler.promises.acceptInvite(
|
||||
'dddddddd',
|
||||
this.user.id
|
||||
this.user.id,
|
||||
this.ipAddress
|
||||
)
|
||||
sinon.assert.calledWith(
|
||||
this.Modules.promises.hooks.fire,
|
||||
|
||||
Reference in New Issue
Block a user