diff --git a/services/web/app/coffee/Features/Institutions/InstitutionsManager.coffee b/services/web/app/coffee/Features/Institutions/InstitutionsManager.coffee index 15233c8849..5de39aebf1 100644 --- a/services/web/app/coffee/Features/Institutions/InstitutionsManager.coffee +++ b/services/web/app/coffee/Features/Institutions/InstitutionsManager.coffee @@ -4,6 +4,7 @@ db = require("../../infrastructure/mongojs").db ObjectId = require("../../infrastructure/mongojs").ObjectId { getInstitutionAffiliations } = require('./InstitutionsAPI') FeaturesUpdater = require('../Subscription/FeaturesUpdater') +UserGetter = require('../User/UserGetter') ASYNC_LIMIT = 10 module.exports = InstitutionsManager = @@ -11,7 +12,31 @@ module.exports = InstitutionsManager = getInstitutionAffiliations institutionId, (error, affiliations) -> return callback(error) if error async.eachLimit affiliations, ASYNC_LIMIT, refreshFeatures, callback + checkInstitutionUsers: (institutionId, callback = (error) ->) -> + getInstitutionAffiliations institutionId, (error, affiliations) -> + UserGetter.getUsersByAnyConfirmedEmail( + affiliations.map((affiliation) -> affiliation.email), + { features: 1 }, + (error, users) -> + callback(error, checkFeatures(users)) + ) refreshFeatures = (affiliation, callback) -> userId = ObjectId(affiliation.user_id) FeaturesUpdater.refreshFeatures(userId, true, callback) + +checkFeatures = (users) -> + usersSummary = { + totalConfirmedUsers: users.length + totalConfirmedProUsers: 0 + totalConfirmedNonProUsers: 0 + confirmedNonProUsers: [] + } + users.forEach((user) -> + if user.features.collaborators == -1 and user.features.trackChanges + usersSummary.totalConfirmedProUsers += 1 + else + usersSummary.totalConfirmedNonProUsers += 1 + usersSummary.confirmedNonProUsers.push user._id + ) + return usersSummary \ No newline at end of file diff --git a/services/web/app/coffee/Features/User/UserGetter.coffee b/services/web/app/coffee/Features/User/UserGetter.coffee index 7eb1e4ba20..18fc798fae 100644 --- a/services/web/app/coffee/Features/User/UserGetter.coffee +++ b/services/web/app/coffee/Features/User/UserGetter.coffee @@ -58,6 +58,15 @@ module.exports = UserGetter = # well @getUserByMainEmail email, projection, callback + getUsersByAnyConfirmedEmail: (emails, projection, callback = (error, user) ->) -> + if arguments.length == 2 + callback = projection + projection = {} + # $exists: true MUST be set to use the partial index + query = emails: { emails: { $exists: true, $elemMatch: { email: { $in: emails }, confirmedAt: { $exists: true }}}} + db.users.find query, projection, (error, users) => + callback(error, users) + getUsersByHostname: (hostname, projection, callback = (error, users) ->) -> reversedHostname = hostname.trim().split('').reverse().join('') query = emails: { $exists: true }, 'emails.reversedHostname': reversedHostname diff --git a/services/web/scripts/check_institution_users.js b/services/web/scripts/check_institution_users.js new file mode 100644 index 0000000000..6fb1717974 --- /dev/null +++ b/services/web/scripts/check_institution_users.js @@ -0,0 +1,17 @@ +const InstitutionsManager = require('../app/js/Features/Institutions/InstitutionsManager') + +const institutionId = parseInt(process.argv[2]) +if (isNaN(institutionId)) throw new Error('No institution id') +console.log('Checking users of institution', institutionId) + +InstitutionsManager.checkInstitutionUsers(institutionId, function( + error, + usersSummary +) { + if (error) { + console.log(error) + } else { + console.log(usersSummary) + } + process.exit() +}) diff --git a/services/web/test/unit/coffee/Institutions/InstitutionsManagerTests.coffee b/services/web/test/unit/coffee/Institutions/InstitutionsManagerTests.coffee index acf0478ae2..a9d5bf829f 100644 --- a/services/web/test/unit/coffee/Institutions/InstitutionsManagerTests.coffee +++ b/services/web/test/unit/coffee/Institutions/InstitutionsManagerTests.coffee @@ -3,6 +3,7 @@ SandboxedModule = require('sandboxed-module') path = require('path') sinon = require('sinon') modulePath = path.join __dirname, "../../../../app/js/Features/Institutions/InstitutionsManager" +expect = require('chai').expect describe "InstitutionsManager", -> beforeEach -> @@ -10,12 +11,15 @@ describe "InstitutionsManager", -> @logger = log: -> @getInstitutionAffiliations = sinon.stub() @refreshFeatures = sinon.stub().yields() + @getUsersByAnyConfirmedEmail = sinon.stub().yields() @InstitutionsManager = SandboxedModule.require modulePath, requires: 'logger-sharelatex': @logger './InstitutionsAPI': getInstitutionAffiliations: @getInstitutionAffiliations '../Subscription/FeaturesUpdater': refreshFeatures: @refreshFeatures + '../User/UserGetter': + getUsersByAnyConfirmedEmail: @getUsersByAnyConfirmedEmail describe 'upgradeInstitutionUsers', -> it 'refresh all users Features', (done) -> @@ -28,3 +32,33 @@ describe "InstitutionsManager", -> should.not.exist(error) sinon.assert.calledTwice(@refreshFeatures) done() + + describe.only 'checkInstitutionUsers', -> + it 'check all users Features', (done) -> + affiliations = [ + { email: 'foo@bar.com' } + { email: 'baz@boo.edu' } + ] + stubbedUsers = [ + { + _id: '123abc123abc123abc123abc' + features: {collaborators: -1, trackChanges: true} + } + { + _id: '456def456def456def456def' + features: {collaborators: 10, trackChanges: false} + } + { + _id: '789def789def789def789def' + features: {collaborators: -1, trackChanges: false} + } + ] + @getInstitutionAffiliations.yields(null, affiliations) + @getUsersByAnyConfirmedEmail.yields(null, stubbedUsers) + @InstitutionsManager.checkInstitutionUsers @institutionId, (error, usersSummary) => + should.not.exist(error) + usersSummary.totalConfirmedUsers.should.equal 3 + usersSummary.totalConfirmedProUsers.should.equal 1 + usersSummary.totalConfirmedNonProUsers.should.equal 2 + expect(usersSummary.confirmedNonProUsers).to.deep.equal ['456def456def456def456def', '789def789def789def789def'] + done() \ No newline at end of file