| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- const SandboxedModule = require('sandboxed-module')
- const chai = require('chai')
- const sinon = require('sinon')
- const modulePath =
- '../../../../app/src/Features/Subscription/SubscriptionUpdater'
- const { assert } = require('chai')
- const { ObjectId } = require('mongodb')
- chai.should()
- describe('SubscriptionUpdater', function() {
- beforeEach(function() {
- this.recurlySubscription = {
- uuid: '1238uoijdasjhd',
- plan: {
- plan_code: 'kjhsakjds'
- }
- }
- this.adminUser = { _id: (this.adminuser_id = '5208dd34438843e2db000007') }
- this.otherUserId = '5208dd34438842e2db000005'
- this.allUserIds = ['13213', 'dsadas', 'djsaiud89']
- this.subscription = {
- _id: '111111111111111111111111',
- admin_id: this.adminUser._id,
- manager_ids: [this.adminUser._id],
- member_ids: [],
- save: sinon.stub().callsArgWith(0),
- planCode: 'student_or_something'
- }
- this.user_id = this.adminuser_id
- this.groupSubscription = {
- _id: '222222222222222222222222',
- admin_id: this.adminUser._id,
- manager_ids: [this.adminUser._id],
- member_ids: this.allUserIds,
- save: sinon.stub().callsArgWith(0),
- planCode: 'group_subscription'
- }
- this.updateStub = sinon.stub().callsArgWith(2, null)
- this.updateManyStub = sinon.stub().callsArgWith(2, null)
- this.findAndModifyStub = sinon
- .stub()
- .callsArgWith(2, null, this.subscription)
- this.findOneAndUpdateStub = sinon
- .stub()
- .callsArgWith(2, null, this.subscription)
- let subscription = this.subscription
- this.SubscriptionModel = class {
- constructor(opts) {
- // Always return our mock subscription when creating a new one
- subscription.admin_id = opts.admin_id
- subscription.manager_ids = [opts.admin_id]
- return subscription
- }
- }
- this.SubscriptionModel.remove = sinon.stub().yields()
- this.SubscriptionModel.update = this.updateStub
- this.SubscriptionModel.updateMany = this.updateManyStub
- this.SubscriptionModel.findAndModify = this.findAndModifyStub
- this.SubscriptionModel.findOneAndUpdate = this.findOneAndUpdateStub
- this.SubscriptionLocator = {
- getUsersSubscription: sinon.stub(),
- getGroupSubscriptionMemberOf: sinon.stub(),
- getMemberSubscriptions: sinon.stub().yields(null, [])
- }
- this.Settings = {
- defaultPlanCode: 'personal',
- defaultFeatures: { default: 'features' }
- }
- this.UserFeaturesUpdater = { updateFeatures: sinon.stub().yields() }
- this.PlansLocator = { findLocalPlanInSettings: sinon.stub().returns({}) }
- this.UserGetter = {
- getUsers(memberIds, projection, callback) {
- const users = memberIds.map(id => ({ _id: id }))
- callback(null, users)
- },
- getUser: sinon.stub()
- }
- this.ReferalFeatures = { getBonusFeatures: sinon.stub().callsArgWith(1) }
- this.Modules = { hooks: { fire: sinon.stub().callsArgWith(2, null, null) } }
- this.FeaturesUpdater = {
- refreshFeatures: sinon.stub().yields()
- }
- this.DeletedSubscription = {
- findOneAndUpdate: sinon.stub().yields()
- }
- this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
- globals: {
- console: console
- },
- requires: {
- mongodb: { ObjectId },
- '../../models/Subscription': {
- Subscription: this.SubscriptionModel
- },
- './UserFeaturesUpdater': this.UserFeaturesUpdater,
- './SubscriptionLocator': this.SubscriptionLocator,
- '../User/UserGetter': this.UserGetter,
- './PlansLocator': this.PlansLocator,
- 'logger-sharelatex': {
- log() {},
- warn() {}
- },
- 'settings-sharelatex': this.Settings,
- '../../infrastructure/mongodb': { db: {}, ObjectId },
- './FeaturesUpdater': this.FeaturesUpdater,
- '../../models/DeletedSubscription': {
- DeletedSubscription: this.DeletedSubscription
- }
- }
- })
- })
- describe('updateAdmin', function() {
- it('should update the subscription admin', function(done) {
- this.subscription.groupPlan = true
- this.SubscriptionUpdater.updateAdmin(
- this.subscription,
- this.otherUserId,
- err => {
- if (err != null) {
- return done(err)
- }
- const query = {
- _id: ObjectId(this.subscription._id),
- customAccount: true
- }
- const update = {
- $set: { admin_id: ObjectId(this.otherUserId) },
- $addToSet: { manager_ids: ObjectId(this.otherUserId) }
- }
- this.SubscriptionModel.update.should.have.been.calledOnce
- this.SubscriptionModel.update.should.have.been.calledWith(
- query,
- update
- )
- done()
- }
- )
- })
- it('should remove the manager for non-group subscriptions', function(done) {
- this.SubscriptionUpdater.updateAdmin(
- this.subscription,
- this.otherUserId,
- err => {
- if (err != null) {
- return done(err)
- }
- const query = {
- _id: ObjectId(this.subscription._id),
- customAccount: true
- }
- const update = {
- $set: {
- admin_id: ObjectId(this.otherUserId),
- manager_ids: [ObjectId(this.otherUserId)]
- }
- }
- this.SubscriptionModel.update.should.have.been.calledOnce
- this.SubscriptionModel.update.should.have.been.calledWith(
- query,
- update
- )
- done()
- }
- )
- })
- })
- describe('syncSubscription', function() {
- beforeEach(function() {
- this.SubscriptionLocator.getUsersSubscription.callsArgWith(
- 1,
- null,
- this.subscription
- )
- this.SubscriptionUpdater._updateSubscriptionFromRecurly = sinon
- .stub()
- .yields()
- })
- it('should update the subscription if the user already is admin of one', function(done) {
- this.SubscriptionUpdater._createNewSubscription = sinon.stub()
- this.SubscriptionUpdater.syncSubscription(
- this.recurlySubscription,
- this.adminUser._id,
- err => {
- if (err != null) {
- return done(err)
- }
- this.SubscriptionLocator.getUsersSubscription
- .calledWith(this.adminUser._id)
- .should.equal(true)
- this.SubscriptionUpdater._updateSubscriptionFromRecurly.called.should.equal(
- true
- )
- this.SubscriptionUpdater._updateSubscriptionFromRecurly
- .calledWith(this.recurlySubscription, this.subscription)
- .should.equal(true)
- done()
- }
- )
- })
- it('should not call updateFeatures with group subscription if recurly subscription is not expired', function(done) {
- this.SubscriptionUpdater.syncSubscription(
- this.recurlySubscription,
- this.adminUser._id,
- err => {
- if (err != null) {
- return done(err)
- }
- this.SubscriptionLocator.getUsersSubscription
- .calledWith(this.adminUser._id)
- .should.equal(true)
- this.SubscriptionUpdater._updateSubscriptionFromRecurly.called.should.equal(
- true
- )
- this.SubscriptionUpdater._updateSubscriptionFromRecurly
- .calledWith(this.recurlySubscription, this.subscription)
- .should.equal(true)
- this.UserFeaturesUpdater.updateFeatures.called.should.equal(false)
- done()
- }
- )
- })
- })
- describe('_updateSubscriptionFromRecurly', function() {
- beforeEach(function() {
- this.FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1)
- this.SubscriptionUpdater.deleteSubscription = sinon.stub().yields()
- })
- afterEach(function() {
- this.subscription.member_ids = []
- })
- it('should update the subscription with token etc when not expired', function(done) {
- this.SubscriptionUpdater._updateSubscriptionFromRecurly(
- this.recurlySubscription,
- this.subscription,
- {},
- err => {
- if (err != null) {
- return done(err)
- }
- this.subscription.recurlySubscription_id.should.equal(
- this.recurlySubscription.uuid
- )
- this.subscription.planCode.should.equal(
- this.recurlySubscription.plan.plan_code
- )
- this.subscription.save.called.should.equal(true)
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.adminUser._id)
- .should.equal(true)
- done()
- }
- )
- })
- it('should remove the subscription when expired', function(done) {
- this.recurlySubscription.state = 'expired'
- this.SubscriptionUpdater._updateSubscriptionFromRecurly(
- this.recurlySubscription,
- this.subscription,
- {},
- err => {
- if (err != null) {
- return done(err)
- }
- this.SubscriptionUpdater.deleteSubscription
- .calledWithMatch(this.subscription)
- .should.equal(true)
- done()
- }
- )
- })
- it('should update all the users features', function(done) {
- this.subscription.member_ids = this.allUserIds
- this.SubscriptionUpdater._updateSubscriptionFromRecurly(
- this.recurlySubscription,
- this.subscription,
- {},
- err => {
- if (err != null) {
- return done(err)
- }
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.adminUser._id)
- .should.equal(true)
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.allUserIds[0])
- .should.equal(true)
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.allUserIds[1])
- .should.equal(true)
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.allUserIds[2])
- .should.equal(true)
- done()
- }
- )
- })
- it('should set group to true and save how many members can be added to group', function(done) {
- this.PlansLocator.findLocalPlanInSettings
- .withArgs(this.recurlySubscription.plan.plan_code)
- .returns({ groupPlan: true, membersLimit: 5 })
- this.SubscriptionUpdater._updateSubscriptionFromRecurly(
- this.recurlySubscription,
- this.subscription,
- {},
- err => {
- if (err != null) {
- return done(err)
- }
- this.subscription.membersLimit.should.equal(5)
- this.subscription.groupPlan.should.equal(true)
- this.subscription.member_ids.should.deep.equal([
- this.subscription.admin_id
- ])
- done()
- }
- )
- })
- it('should not set group to true or set groupPlan', function(done) {
- this.SubscriptionUpdater._updateSubscriptionFromRecurly(
- this.recurlySubscription,
- this.subscription,
- {},
- err => {
- if (err != null) {
- return done(err)
- }
- assert.notEqual(this.subscription.membersLimit, 5)
- assert.notEqual(this.subscription.groupPlan, true)
- done()
- }
- )
- })
- })
- describe('_createNewSubscription', function() {
- it('should create a new subscription then update the subscription', function(done) {
- this.SubscriptionUpdater._createNewSubscription(
- this.adminUser._id,
- () => {
- this.subscription.admin_id.should.equal(this.adminUser._id)
- this.subscription.manager_ids.should.deep.equal([this.adminUser._id])
- this.subscription.save.called.should.equal(true)
- done()
- }
- )
- })
- })
- describe('addUserToGroup', function() {
- beforeEach(function() {
- this.SubscriptionUpdater.addUsersToGroup = sinon.stub().yields(null)
- })
- it('delegates to addUsersToGroup', function(done) {
- this.SubscriptionUpdater.addUserToGroup(
- this.subscription._id,
- this.otherUserId,
- () => {
- this.SubscriptionUpdater.addUsersToGroup
- .calledWith(this.subscription._id, [this.otherUserId])
- .should.equal(true)
- done()
- }
- )
- })
- })
- describe('addUsersToGroup', function() {
- beforeEach(function() {
- this.FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1)
- })
- it('should add the user ids to the group as a set', function(done) {
- this.SubscriptionUpdater.addUsersToGroup(
- this.subscription._id,
- [this.otherUserId],
- () => {
- const searchOps = { _id: this.subscription._id }
- const insertOperation = {
- $addToSet: { member_ids: { $each: [this.otherUserId] } }
- }
- this.findAndModifyStub
- .calledWith(searchOps, insertOperation)
- .should.equal(true)
- done()
- }
- )
- })
- it('should update the users features', function(done) {
- this.SubscriptionUpdater.addUserToGroup(
- this.subscription._id,
- this.otherUserId,
- () => {
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.otherUserId)
- .should.equal(true)
- done()
- }
- )
- })
- })
- describe('removeUserFromGroups', function() {
- beforeEach(function() {
- this.FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1)
- this.UserGetter.getUser.yields(null, {})
- this.fakeSubscriptions = [{ _id: 'fake-id-1' }, { _id: 'fake-id-2' }]
- this.SubscriptionLocator.getMemberSubscriptions.yields(
- null,
- this.fakeSubscriptions
- )
- })
- it('should pull the users id from the group', function(done) {
- this.SubscriptionUpdater.removeUserFromGroup(
- this.subscription._id,
- this.otherUserId,
- () => {
- const searchOps = { _id: this.subscription._id }
- const removeOperation = { $pull: { member_ids: this.otherUserId } }
- this.updateManyStub
- .calledWith(searchOps, removeOperation)
- .should.equal(true)
- done()
- }
- )
- })
- it('should pull the users id from all groups', function(done) {
- this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
- const filter = { _id: ['fake-id-1', 'fake-id-2'] }
- const removeOperation = { $pull: { member_ids: this.otherUserId } }
- sinon.assert.calledWith(this.updateManyStub, filter, removeOperation)
- done()
- })
- })
- it('should update the users features', function(done) {
- this.SubscriptionUpdater.removeUserFromGroup(
- this.subscription._id,
- this.otherUserId,
- () => {
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.otherUserId)
- .should.equal(true)
- done()
- }
- )
- })
- })
- describe('deleteSubscription', function() {
- beforeEach(function(done) {
- this.subscription = {
- _id: ObjectId().toString(),
- mock: 'subscription',
- admin_id: ObjectId(),
- member_ids: [ObjectId(), ObjectId(), ObjectId()]
- }
- this.SubscriptionLocator.getSubscription = sinon
- .stub()
- .yields(null, this.subscription)
- this.FeaturesUpdater.refreshFeatures = sinon.stub().yields()
- this.SubscriptionUpdater.deleteSubscription(this.subscription, {}, done)
- })
- it('should remove the subscription', function() {
- this.SubscriptionModel.remove
- .calledWith({ _id: this.subscription._id })
- .should.equal(true)
- })
- it('should downgrade the admin_id', function() {
- this.FeaturesUpdater.refreshFeatures
- .calledWith(this.subscription.admin_id)
- .should.equal(true)
- })
- it('should downgrade all of the members', function() {
- for (const userId of this.subscription.member_ids) {
- this.FeaturesUpdater.refreshFeatures
- .calledWith(userId)
- .should.equal(true)
- }
- })
- })
- })
|