2020-08-11 05:35:08 -04:00
|
|
|
const OError = require('@overleaf/o-error')
|
2021-11-01 11:05:16 -04:00
|
|
|
const logger = require('@overleaf/logger')
|
2019-05-29 05:21:06 -04:00
|
|
|
const ProjectGetter = require('../Project/ProjectGetter')
|
|
|
|
const UserGetter = require('../User/UserGetter')
|
|
|
|
const SubscriptionLocator = require('./SubscriptionLocator')
|
2021-07-07 05:38:56 -04:00
|
|
|
const Settings = require('@overleaf/settings')
|
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')
|
2021-05-26 08:26:59 -04:00
|
|
|
const { promisifyAll } = require('../../util/promises')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-05-26 08:26:59 -04:00
|
|
|
const LimitationsManager = {
|
2021-05-05 09:40:27 -04:00
|
|
|
allowedNumberOfCollaboratorsInProject(projectId, callback) {
|
|
|
|
ProjectGetter.getProject(
|
|
|
|
projectId,
|
2019-05-29 05:21:06 -04:00
|
|
|
{ owner_ref: true },
|
|
|
|
(error, project) => {
|
2021-05-05 09:40:27 -04:00
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
this.allowedNumberOfCollaboratorsForUser(project.owner_ref, callback)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
2021-05-05 09:40:27 -04:00
|
|
|
allowedNumberOfCollaboratorsForUser(userId, callback) {
|
|
|
|
UserGetter.getUser(userId, { features: 1 }, function (error, user) {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
if (user.features && user.features.collaborators) {
|
|
|
|
callback(null, user.features.collaborators)
|
2019-05-29 05:21:06 -04:00
|
|
|
} else {
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(null, Settings.defaultFeatures.collaborators)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2021-05-05 09:40:27 -04:00
|
|
|
canAddXCollaborators(projectId, numberOfNewCollaborators, callback) {
|
|
|
|
this.allowedNumberOfCollaboratorsInProject(
|
|
|
|
projectId,
|
|
|
|
(error, allowedNumber) => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
CollaboratorsGetter.getInvitedCollaboratorCount(
|
|
|
|
projectId,
|
|
|
|
(error, currentNumber) => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
CollaboratorsInvitesHandler.getInviteCount(
|
|
|
|
projectId,
|
|
|
|
(error, inviteCount) => {
|
|
|
|
if (error) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(error)
|
|
|
|
}
|
|
|
|
if (
|
2021-05-05 09:40:27 -04:00
|
|
|
currentNumber + inviteCount + numberOfNewCollaborators <=
|
|
|
|
allowedNumber ||
|
|
|
|
allowedNumber < 0
|
2019-05-29 05:21:06 -04:00
|
|
|
) {
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(null, true)
|
2019-05-29 05:21:06 -04:00
|
|
|
} else {
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(null, false)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
hasPaidSubscription(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
this.userHasV2Subscription(user, (err, hasSubscription, subscription) => {
|
|
|
|
if (err) {
|
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
this.userIsMemberOfGroupSubscription(user, (err, isMember) => {
|
|
|
|
if (err) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
this.userHasV1Subscription(user, (err, hasV1Subscription) => {
|
|
|
|
if (err) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(
|
2021-05-05 09:40:27 -04:00
|
|
|
new V1ConnectionError(
|
|
|
|
'error getting subscription from v1'
|
|
|
|
).withCause(err)
|
2019-05-29 05:21:06 -04:00
|
|
|
)
|
2021-05-05 09:40:27 -04:00
|
|
|
}
|
|
|
|
callback(
|
|
|
|
err,
|
|
|
|
isMember || hasSubscription || hasV1Subscription,
|
|
|
|
subscription
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
2021-05-05 09:40:27 -04:00
|
|
|
})
|
|
|
|
})
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
// alias for backward-compatibility with modules. Use `haspaidsubscription` instead
|
|
|
|
userHasSubscriptionOrIsGroupMember(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
this.hasPaidSubscription(user, callback)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
userHasV2Subscription(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
SubscriptionLocator.getUsersSubscription(
|
2021-04-14 09:17:21 -04:00
|
|
|
user._id,
|
|
|
|
function (err, subscription) {
|
2021-05-05 09:40:27 -04:00
|
|
|
if (err) {
|
2021-04-14 09:17:21 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
let hasValidSubscription = false
|
|
|
|
if (subscription) {
|
|
|
|
if (
|
|
|
|
subscription.recurlySubscription_id ||
|
|
|
|
subscription.customAccount
|
|
|
|
) {
|
|
|
|
hasValidSubscription = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
callback(err, hasValidSubscription, subscription)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
userHasV1OrV2Subscription(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
this.userHasV2Subscription(user, (err, hasV2Subscription) => {
|
|
|
|
if (err) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (hasV2Subscription) {
|
|
|
|
return callback(null, true)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
this.userHasV1Subscription(user, (err, hasV1Subscription) => {
|
|
|
|
if (err) {
|
2019-05-29 05:21:06 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
|
|
|
if (hasV1Subscription) {
|
|
|
|
return callback(null, true)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(null, false)
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
userIsMemberOfGroupSubscription(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
SubscriptionLocator.getMemberSubscriptions(
|
2021-04-14 09:17:21 -04:00
|
|
|
user._id,
|
|
|
|
function (err, subscriptions) {
|
2021-05-05 09:40:27 -04:00
|
|
|
if (!subscriptions) {
|
2021-04-14 09:17:21 -04:00
|
|
|
subscriptions = []
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
if (err) {
|
2021-04-14 09:17:21 -04:00
|
|
|
return callback(err)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(err, subscriptions.length > 0, subscriptions)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
userHasV1Subscription(user, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
V1SubscriptionManager.getSubscriptionsFromV1(
|
2021-04-14 09:17:21 -04:00
|
|
|
user._id,
|
|
|
|
function (err, v1Subscription) {
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(
|
2021-04-14 09:17:21 -04:00
|
|
|
err,
|
2021-05-05 09:40:27 -04:00
|
|
|
!!(v1Subscription ? v1Subscription.has_subscription : undefined)
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
teamHasReachedMemberLimit(subscription) {
|
|
|
|
const currentTotal =
|
|
|
|
(subscription.member_ids || []).length +
|
|
|
|
(subscription.teamInvites || []).length +
|
|
|
|
(subscription.invited_emails || []).length
|
|
|
|
|
|
|
|
return currentTotal >= subscription.membersLimit
|
|
|
|
},
|
|
|
|
|
|
|
|
hasGroupMembersLimitReached(subscriptionId, callback) {
|
2021-05-05 09:40:27 -04:00
|
|
|
SubscriptionLocator.getSubscription(
|
2021-04-14 09:17:21 -04:00
|
|
|
subscriptionId,
|
|
|
|
function (err, subscription) {
|
2021-05-05 09:40:27 -04:00
|
|
|
if (err) {
|
2021-04-14 09:17:21 -04:00
|
|
|
OError.tag(err, 'error getting subscription', {
|
2021-04-27 03:52:58 -04:00
|
|
|
subscriptionId,
|
2021-04-14 09:17:21 -04:00
|
|
|
})
|
|
|
|
return callback(err)
|
|
|
|
}
|
2021-05-05 09:40:27 -04:00
|
|
|
if (!subscription) {
|
2021-04-14 09:17:21 -04:00
|
|
|
logger.warn({ subscriptionId }, 'no subscription found')
|
|
|
|
return callback(new Error('no subscription found'))
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-04-14 09:17:21 -04:00
|
|
|
const limitReached = LimitationsManager.teamHasReachedMemberLimit(
|
|
|
|
subscription
|
|
|
|
)
|
2021-05-05 09:40:27 -04:00
|
|
|
callback(err, limitReached, subscription)
|
2021-04-14 09:17:21 -04:00
|
|
|
}
|
|
|
|
)
|
2021-04-27 03:52:58 -04:00
|
|
|
},
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2021-05-26 08:26:59 -04:00
|
|
|
|
|
|
|
LimitationsManager.promises = promisifyAll(LimitationsManager, {
|
|
|
|
multiResult: {
|
|
|
|
userHasV2Subscription: ['hasSubscription', 'subscription'],
|
|
|
|
userIsMemberOfGroupSubscription: ['isMember', 'subscriptions'],
|
|
|
|
hasGroupMembersLimitReached: ['limitReached', 'subscription'],
|
|
|
|
},
|
|
|
|
})
|
|
|
|
module.exports = LimitationsManager
|