Merge pull request #2123 from overleaf/ta-subscription-restore

Restore Deleted Subscriptions

GitOrigin-RevId: 4df1d2116e5502235e06f47d7317d97ad458b75b
This commit is contained in:
Timothée Alby 2019-09-10 16:03:29 +02:00 committed by sharelatex
parent 911a2ded4d
commit 71060e8d57
5 changed files with 119 additions and 2 deletions

View file

@ -14,6 +14,7 @@
*/ */
const { promisify } = require('util') const { promisify } = require('util')
const { Subscription } = require('../../models/Subscription') const { Subscription } = require('../../models/Subscription')
const { DeletedSubscription } = require('../../models/DeletedSubscription')
const logger = require('logger-sharelatex') const logger = require('logger-sharelatex')
const { ObjectId } = require('mongoose').Types const { ObjectId } = require('mongoose').Types
@ -84,6 +85,20 @@ const SubscriptionLocator = {
return Subscription.findOne({ 'overleaf.id': v1TeamId }, callback) return Subscription.findOne({ 'overleaf.id': v1TeamId }, callback)
}, },
getUserDeletedSubscriptions(userId, callback) {
logger.log({ userId }, 'getting users deleted subscriptions')
DeletedSubscription.find({ 'subscription.admin_id': userId }, callback)
},
getDeletedSubscription(subscriptionId, callback) {
DeletedSubscription.findOne(
{
'subscription._id': subscriptionId
},
callback
)
},
_getUserId(user_or_id) { _getUserId(user_or_id) {
if (user_or_id != null && user_or_id._id != null) { if (user_or_id != null && user_or_id._id != null) {
return user_or_id._id return user_or_id._id
@ -112,6 +127,10 @@ SubscriptionLocator.promises = {
getGroupsWithEmailInvite: promisify( getGroupsWithEmailInvite: promisify(
SubscriptionLocator.getGroupsWithEmailInvite SubscriptionLocator.getGroupsWithEmailInvite
), ),
getGroupWithV1Id: promisify(SubscriptionLocator.getGroupWithV1Id) getGroupWithV1Id: promisify(SubscriptionLocator.getGroupWithV1Id),
getUserDeletedSubscriptions: promisify(
SubscriptionLocator.getUserDeletedSubscriptions
),
getDeletedSubscription: promisify(SubscriptionLocator.getDeletedSubscription)
} }
module.exports = SubscriptionLocator module.exports = SubscriptionLocator

View file

@ -1,3 +1,4 @@
const { db } = require('../../infrastructure/mongojs')
const async = require('async') const async = require('async')
const _ = require('underscore') const _ = require('underscore')
const { promisifyAll } = require('../../util/promises') const { promisifyAll } = require('../../util/promises')
@ -219,6 +220,47 @@ const SubscriptionUpdater = {
}) })
}, },
restoreSubscription(subscriptionId, callback) {
SubscriptionLocator.getDeletedSubscription(subscriptionId, function(
err,
deletedSubscription
) {
if (err) {
return callback(err)
}
let subscription = deletedSubscription.subscription
async.series(
[
cb =>
// 1. upsert subscription
db.subscriptions.update(
{ _id: subscription._id },
subscription,
{ upsert: true },
cb
),
cb =>
// 2. remove deleted subscription
DeletedSubscription.deleteOne(
{ 'subscription._id': subscription._id },
callback
),
cb =>
// 3. refresh users features
SubscriptionUpdater._refreshUsersFeature(subscription, cb)
],
callback
)
})
},
_refreshUsersFeature(subscription, callback) {
const userIds = [subscription.admin_id].concat(
subscription.member_ids || []
)
async.mapSeries(userIds, FeaturesUpdater.refreshFeatures, callback)
},
_createDeletedSubscription(subscription, deleterData, callback) { _createDeletedSubscription(subscription, deleterData, callback) {
subscription.teamInvites = [] subscription.teamInvites = []
subscription.invited_emails = [] subscription.invited_emails = []

View file

@ -0,0 +1,49 @@
const { expect } = require('chai')
const MockSubscription = require('./Subscription')
const SubscriptionUpdater = require('../../../../app/src/Features/Subscription/SubscriptionUpdater')
const SubscriptionModel = require('../../../../app/src/models/Subscription')
.Subscription
const DeletedSubscriptionModel = require(`../../../../app/src/models/DeletedSubscription`)
.DeletedSubscription
class DeletedSubscription {
constructor(options = {}) {
this.subscription = new MockSubscription(options)
}
ensureExists(callback) {
this.subscription.ensureExists(error => {
if (error) {
return callback(error)
}
SubscriptionUpdater.deleteSubscription(this.subscription, {}, callback)
})
}
expectRestored(callback) {
DeletedSubscriptionModel.findOne(
{ 'subscription._id': this.subscription._id },
(error, deletedSubscription) => {
if (error) {
return callback(error)
}
expect(deletedSubscription).to.be.null
SubscriptionModel.findById(
this.subscription._id,
(error, subscription) => {
expect(subscription).to.exists
expect(subscription._id.toString()).to.equal(
this.subscription._id.toString()
)
expect(subscription.admin_id.toString()).to.equal(
this.subscription.admin_id.toString()
)
callback(error)
}
)
}
)
}
}
module.exports = DeletedSubscription

View file

@ -22,7 +22,7 @@ class Subscription {
} }
const options = { upsert: true, new: true, setDefaultsOnInsert: true } const options = { upsert: true, new: true, setDefaultsOnInsert: true }
SubscriptionModel.findOneAndUpdate( SubscriptionModel.findOneAndUpdate(
{}, { admin_id: this.admin_id },
this, this,
options, options,
(error, subscription) => { (error, subscription) => {

View file

@ -27,6 +27,10 @@ describe('Subscription Locator Tests', function() {
findOne: sinon.stub(), findOne: sinon.stub(),
find: sinon.stub() find: sinon.stub()
} }
this.DeletedSubscription = {
findOne: sinon.stub().yields(),
find: sinon.stub().yields()
}
return (this.SubscriptionLocator = SandboxedModule.require(modulePath, { return (this.SubscriptionLocator = SandboxedModule.require(modulePath, {
globals: { globals: {
console: console console: console
@ -35,6 +39,9 @@ describe('Subscription Locator Tests', function() {
'../../models/Subscription': { '../../models/Subscription': {
Subscription: this.Subscription Subscription: this.Subscription
}, },
'../../models/DeletedSubscription': {
DeletedSubscription: this.DeletedSubscription
},
'logger-sharelatex': { 'logger-sharelatex': {
log() {} log() {}
} }