overleaf/services/web/app/src/Features/Institutions/InstitutionsManager.js
Simon Detheridge 6f46034b62 Merge pull request #3162 from overleaf/spd-upgrade-users-async-limit
Make ASYNC_LIMIT configurable when upgrading institution users

GitOrigin-RevId: 566dd7d1e742c196847196c98449becea264719e
2020-09-05 02:05:32 +00:00

187 lines
5.4 KiB
JavaScript

const async = require('async')
const _ = require('underscore')
const { ObjectId } = require('../../infrastructure/mongojs')
const { getInstitutionAffiliations } = require('./InstitutionsAPI')
const FeaturesUpdater = require('../Subscription/FeaturesUpdater')
const UserGetter = require('../User/UserGetter')
const SAMLIdentityManager = require('../User/SAMLIdentityManager')
const NotificationsBuilder = require('../Notifications/NotificationsBuilder')
const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
const { Institution } = require('../../models/Institution')
const { Subscription } = require('../../models/Subscription')
const ASYNC_LIMIT = parseInt(process.env.ASYNC_LIMIT, 10) || 5
module.exports = {
upgradeInstitutionUsers(institutionId, callback) {
async.waterfall(
[
cb => fetchInstitutionAndAffiliations(institutionId, cb),
function(institution, affiliations, cb) {
affiliations = _.map(affiliations, function(affiliation) {
affiliation.institutionName = institution.name
affiliation.institutionId = institutionId
return affiliation
})
async.eachLimit(affiliations, ASYNC_LIMIT, refreshFeatures, err =>
cb(err)
)
}
],
callback
)
},
checkInstitutionUsers(institutionId, callback) {
getInstitutionAffiliations(institutionId, (error, affiliations) => {
if (error) {
return callback(error)
}
UserGetter.getUsersByAnyConfirmedEmail(
affiliations.map(affiliation => affiliation.email),
{ features: 1, samlIdentifiers: 1 },
(error, users) => callback(error, checkFeatures(institutionId, users))
)
})
},
getInstitutionUsersSubscriptions(institutionId, callback) {
getInstitutionAffiliations(institutionId, function(error, affiliations) {
if (error) {
return callback(error)
}
const userIds = affiliations.map(affiliation =>
ObjectId(affiliation.user_id)
)
Subscription.find({
admin_id: userIds,
planCode: { $not: /trial/ }
})
.populate('admin_id', 'email')
.exec(callback)
})
}
}
var fetchInstitutionAndAffiliations = (institutionId, callback) =>
async.waterfall(
[
cb =>
Institution.findOne({ v1Id: institutionId }, (err, institution) =>
cb(err, institution)
),
(institution, cb) =>
institution.fetchV1Data((err, institution) => cb(err, institution)),
(institution, cb) =>
getInstitutionAffiliations(institutionId, (err, affiliations) =>
cb(err, institution, affiliations)
)
],
callback
)
var refreshFeatures = function(affiliation, callback) {
const userId = ObjectId(affiliation.user_id)
async.waterfall(
[
cb =>
FeaturesUpdater.refreshFeatures(
userId,
(err, features, featuresChanged) => cb(err, featuresChanged)
),
(featuresChanged, cb) =>
getUserInfo(userId, (error, user, subscription) =>
cb(error, user, subscription, featuresChanged)
),
(user, subscription, featuresChanged, cb) =>
notifyUser(user, affiliation, subscription, featuresChanged, cb)
],
callback
)
}
var getUserInfo = (userId, callback) =>
async.waterfall(
[
cb => UserGetter.getUser(userId, cb),
(user, cb) =>
SubscriptionLocator.getUsersSubscription(user, (err, subscription) =>
cb(err, user, subscription)
)
],
callback
)
var notifyUser = (user, affiliation, subscription, featuresChanged, callback) =>
async.parallel(
[
function(cb) {
if (featuresChanged) {
NotificationsBuilder.featuresUpgradedByAffiliation(
affiliation,
user
).create(cb)
} else {
cb()
}
},
function(cb) {
if (
subscription &&
!subscription.planCode.match(/(free|trial)/) &&
!subscription.groupPlan
) {
NotificationsBuilder.redundantPersonalSubscription(
affiliation,
user
).create(cb)
} else {
cb()
}
}
],
callback
)
var checkFeatures = function(institutionId, users) {
const usersSummary = {
confirmedEmailUsers: {
total: users.length, // all users are confirmed email users
totalProUsers: 0,
totalNonProUsers: 0,
nonProUsers: []
},
entitledSSOUsers: {
total: 0,
totalProUsers: 0,
totalNonProUsers: 0,
nonProUsers: []
}
}
users.forEach(function(user) {
let isSSOEntitled = SAMLIdentityManager.userHasEntitlement(
user,
institutionId
)
if (isSSOEntitled) {
usersSummary.entitledSSOUsers.total += 1
}
if (user.features.collaborators === -1 && user.features.trackChanges) {
// user is on Pro
usersSummary.confirmedEmailUsers.totalProUsers += 1
if (isSSOEntitled) {
usersSummary.entitledSSOUsers.totalProUsers += 1
}
} else {
// user is not on Pro
usersSummary.confirmedEmailUsers.totalNonProUsers += 1
usersSummary.confirmedEmailUsers.nonProUsers.push(user._id)
if (isSSOEntitled) {
usersSummary.entitledSSOUsers.totalNonProUsers += 1
usersSummary.entitledSSOUsers.nonProUsers.push(user._id)
}
}
})
return usersSummary
}