2019-05-29 05:21:06 -04:00
|
|
|
/* eslint-disable
|
|
|
|
camelcase,
|
2020-12-15 05:23:54 -05:00
|
|
|
node/handle-callback-err,
|
2019-05-29 05:21:06 -04:00
|
|
|
max-len,
|
|
|
|
*/
|
|
|
|
// TODO: This file was created by bulk-decaffeinate.
|
|
|
|
// Fix any style issues and re-enable lint.
|
|
|
|
/*
|
|
|
|
* decaffeinate suggestions:
|
|
|
|
* DS102: Remove unnecessary code created because of implicit returns
|
|
|
|
* DS207: Consider shorter variations of null checks
|
|
|
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
|
|
*/
|
|
|
|
let LimitationsManager
|
2020-08-11 05:35:08 -04:00
|
|
|
const OError = require('@overleaf/o-error')
|
2019-05-29 05:21:06 -04:00
|
|
|
const logger = require('logger-sharelatex')
|
|
|
|
const ProjectGetter = require('../Project/ProjectGetter')
|
|
|
|
const UserGetter = require('../User/UserGetter')
|
|
|
|
const SubscriptionLocator = require('./SubscriptionLocator')
|
|
|
|
const Settings = require('settings-sharelatex')
|
2019-10-07 04:30:51 -04:00
|
|
|
const CollaboratorsGetter = require('../Collaborators/CollaboratorsGetter')
|
2019-05-29 05:21:06 -04:00
|
|
|
const CollaboratorsInvitesHandler = require('../Collaborators/CollaboratorsInviteHandler')
|
|
|
|
const V1SubscriptionManager = require('./V1SubscriptionManager')
|
2019-10-30 11:42:37 -04:00
|
|
|
const { V1ConnectionError } = require('../Errors/Errors')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
|
|
|
module.exports = LimitationsManager = {
|
|
|
|
allowedNumberOfCollaboratorsInProject(project_id, callback) {
|
|
|
|
return ProjectGetter.getProject(
|
|
|
|
project_id,
|
|
|
|
{ owner_ref: true },
|
|
|
|
(error, project) => {
|
|
|
|
if (error != null) {
|
|
|
|
return callback(error)
|
|
|
|
}
|
|
|
|
return this.allowedNumberOfCollaboratorsForUser(
|
|
|
|
project.owner_ref,
|
|
|
|
callback
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
allowedNumberOfCollaboratorsForUser(user_id, callback) {
|
|
|
|
return UserGetter.getUser(user_id, { features: 1 }, function(error, user) {
|
|
|
|
if (error != null) {
|
|
|
|
return callback(error)
|
|
|
|
}
|
|
|
|
if (user.features != null && user.features.collaborators != null) {
|
|
|
|
return callback(null, user.features.collaborators)
|
|
|
|
} else {
|
|
|
|
return callback(null, Settings.defaultFeatures.collaborators)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
canAddXCollaborators(project_id, x_collaborators, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(error, allowed) {}
|
|
|
|
}
|
|
|
|
return this.allowedNumberOfCollaboratorsInProject(
|
|
|
|
project_id,
|
|
|
|
(error, allowed_number) => {
|
|
|
|
if (error != null) {
|
|
|
|
return callback(error)
|
|
|
|
}
|
2019-10-07 04:30:51 -04:00
|
|
|
return CollaboratorsGetter.getInvitedCollaboratorCount(
|
2019-05-29 05:21:06 -04:00
|
|
|
project_id,
|
|
|
|
(error, current_number) => {
|
|
|
|
if (error != null) {
|
|
|
|
return callback(error)
|
|
|
|
}
|
|
|
|
return CollaboratorsInvitesHandler.getInviteCount(
|
|
|
|
project_id,
|
|
|
|
(error, invite_count) => {
|
|
|
|
if (error != null) {
|
|
|
|
return callback(error)
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
current_number + invite_count + x_collaborators <=
|
|
|
|
allowed_number ||
|
|
|
|
allowed_number < 0
|
|
|
|
) {
|
|
|
|
return callback(null, true)
|
|
|
|
} else {
|
|
|
|
return callback(null, false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
hasPaidSubscription(user, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(err, hasSubscriptionOrIsMember) {}
|
|
|
|
}
|
|
|
|
return this.userHasV2Subscription(
|
|
|
|
user,
|
|
|
|
(err, hasSubscription, subscription) => {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
return this.userIsMemberOfGroupSubscription(user, (err, isMember) => {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
return this.userHasV1Subscription(user, (err, hasV1Subscription) => {
|
|
|
|
if (err != null) {
|
2019-10-30 11:42:37 -04:00
|
|
|
return callback(
|
|
|
|
new V1ConnectionError(
|
|
|
|
'error getting subscription from v1'
|
|
|
|
).withCause(err)
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
return callback(
|
|
|
|
err,
|
|
|
|
isMember || hasSubscription || hasV1Subscription,
|
|
|
|
subscription
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
// alias for backward-compatibility with modules. Use `haspaidsubscription` instead
|
|
|
|
userHasSubscriptionOrIsGroupMember(user, callback) {
|
|
|
|
return this.hasPaidSubscription(user, callback)
|
|
|
|
},
|
|
|
|
|
|
|
|
userHasV2Subscription(user, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(err, hasSubscription, subscription) {}
|
|
|
|
}
|
|
|
|
return SubscriptionLocator.getUsersSubscription(user._id, function(
|
|
|
|
err,
|
|
|
|
subscription
|
|
|
|
) {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
const hasValidSubscription =
|
|
|
|
subscription != null &&
|
|
|
|
(subscription.recurlySubscription_id != null ||
|
|
|
|
(subscription != null ? subscription.customAccount : undefined) ===
|
|
|
|
true)
|
|
|
|
return callback(err, hasValidSubscription, subscription)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
userHasV1OrV2Subscription(user, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(err, hasSubscription) {}
|
|
|
|
}
|
|
|
|
return this.userHasV2Subscription(user, (err, hasV2Subscription) => {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (hasV2Subscription) {
|
|
|
|
return callback(null, true)
|
|
|
|
}
|
|
|
|
return this.userHasV1Subscription(user, (err, hasV1Subscription) => {
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (hasV1Subscription) {
|
|
|
|
return callback(null, true)
|
|
|
|
}
|
|
|
|
return callback(null, false)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
userIsMemberOfGroupSubscription(user, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(error, isMember, subscriptions) {}
|
|
|
|
}
|
|
|
|
return SubscriptionLocator.getMemberSubscriptions(user._id, function(
|
|
|
|
err,
|
|
|
|
subscriptions
|
|
|
|
) {
|
|
|
|
if (subscriptions == null) {
|
|
|
|
subscriptions = []
|
|
|
|
}
|
|
|
|
if (err != null) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
return callback(err, subscriptions.length > 0, subscriptions)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
userHasV1Subscription(user, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(error, hasV1Subscription) {}
|
|
|
|
}
|
|
|
|
return V1SubscriptionManager.getSubscriptionsFromV1(user._id, function(
|
|
|
|
err,
|
|
|
|
v1Subscription
|
|
|
|
) {
|
|
|
|
return callback(
|
|
|
|
err,
|
|
|
|
!!(v1Subscription != null ? v1Subscription.has_subscription : undefined)
|
|
|
|
)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
teamHasReachedMemberLimit(subscription) {
|
|
|
|
const currentTotal =
|
|
|
|
(subscription.member_ids || []).length +
|
|
|
|
(subscription.teamInvites || []).length +
|
|
|
|
(subscription.invited_emails || []).length
|
|
|
|
|
|
|
|
return currentTotal >= subscription.membersLimit
|
|
|
|
},
|
|
|
|
|
|
|
|
hasGroupMembersLimitReached(subscriptionId, callback) {
|
|
|
|
if (callback == null) {
|
|
|
|
callback = function(err, limitReached, subscription) {}
|
|
|
|
}
|
|
|
|
return SubscriptionLocator.getSubscription(subscriptionId, function(
|
|
|
|
err,
|
|
|
|
subscription
|
|
|
|
) {
|
|
|
|
if (err != null) {
|
2020-08-11 05:35:08 -04:00
|
|
|
OError.tag(err, 'error getting subscription', {
|
|
|
|
subscriptionId
|
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (subscription == null) {
|
2019-07-01 09:48:09 -04:00
|
|
|
logger.warn({ subscriptionId }, 'no subscription found')
|
2019-07-01 09:54:23 -04:00
|
|
|
return callback(new Error('no subscription found'))
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const limitReached = LimitationsManager.teamHasReachedMemberLimit(
|
|
|
|
subscription
|
|
|
|
)
|
|
|
|
return callback(err, limitReached, subscription)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|