2019-08-28 08:59:41 -04:00
|
|
|
const { callbackify } = require('util')
|
|
|
|
const logger = require('logger-sharelatex')
|
|
|
|
const moment = require('moment')
|
2019-05-29 05:21:06 -04:00
|
|
|
const { User } = require('../../models/User')
|
2019-07-18 10:18:56 -04:00
|
|
|
const { DeletedUser } = require('../../models/DeletedUser')
|
2019-05-29 05:21:06 -04:00
|
|
|
const NewsletterManager = require('../Newsletter/NewsletterManager')
|
2019-08-28 08:59:41 -04:00
|
|
|
const ProjectDeleter = require('../Project/ProjectDeleter')
|
2019-05-29 05:21:06 -04:00
|
|
|
const SubscriptionHandler = require('../Subscription/SubscriptionHandler')
|
|
|
|
const SubscriptionUpdater = require('../Subscription/SubscriptionUpdater')
|
|
|
|
const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
|
|
|
|
const UserMembershipsHandler = require('../UserMembership/UserMembershipsHandler')
|
2019-12-10 03:10:05 -05:00
|
|
|
const UserSessionsManager = require('./UserSessionsManager')
|
2019-05-29 05:21:06 -04:00
|
|
|
const InstitutionsAPI = require('../Institutions/InstitutionsAPI')
|
|
|
|
const Errors = require('../Errors/Errors')
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
module.exports = {
|
2019-07-18 10:18:56 -04:00
|
|
|
deleteUser: callbackify(deleteUser),
|
2020-09-01 08:37:09 -04:00
|
|
|
deleteMongoUser: callbackify(deleteMongoUser),
|
2019-07-18 10:18:56 -04:00
|
|
|
expireDeletedUser: callbackify(expireDeletedUser),
|
|
|
|
ensureCanDeleteUser: callbackify(ensureCanDeleteUser),
|
|
|
|
expireDeletedUsersAfterDuration: callbackify(expireDeletedUsersAfterDuration),
|
|
|
|
|
|
|
|
promises: {
|
|
|
|
deleteUser: deleteUser,
|
2020-09-01 08:37:09 -04:00
|
|
|
deleteMongoUser: deleteMongoUser,
|
2019-07-18 10:18:56 -04:00
|
|
|
expireDeletedUser: expireDeletedUser,
|
|
|
|
ensureCanDeleteUser: ensureCanDeleteUser,
|
|
|
|
expireDeletedUsersAfterDuration: expireDeletedUsersAfterDuration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function deleteUser(userId, options = {}) {
|
|
|
|
if (!userId) {
|
|
|
|
logger.warn('user_id is null when trying to delete user')
|
|
|
|
throw new Error('no user_id')
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
let user = await User.findById(userId).exec()
|
|
|
|
logger.log({ user }, 'deleting user')
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
await ensureCanDeleteUser(user)
|
2019-07-18 10:18:56 -04:00
|
|
|
await _cleanupUser(user)
|
2019-08-28 08:59:41 -04:00
|
|
|
await _createDeletedUser(user, options)
|
|
|
|
await ProjectDeleter.promises.deleteUsersProjects(user._id)
|
2020-09-01 08:37:09 -04:00
|
|
|
await deleteMongoUser(user._id)
|
2019-07-18 10:18:56 -04:00
|
|
|
} catch (error) {
|
|
|
|
logger.warn({ error, userId }, 'something went wrong deleting the user')
|
|
|
|
throw error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-01 08:37:09 -04:00
|
|
|
/**
|
|
|
|
* delete a user document only
|
|
|
|
*/
|
|
|
|
async function deleteMongoUser(userId) {
|
|
|
|
if (!userId) {
|
|
|
|
throw new Error('no user_id')
|
|
|
|
}
|
|
|
|
|
|
|
|
await User.deleteOne({ _id: userId }).exec()
|
|
|
|
}
|
|
|
|
|
2019-07-18 10:18:56 -04:00
|
|
|
async function expireDeletedUser(userId) {
|
|
|
|
let deletedUser = await DeletedUser.findOne({
|
|
|
|
'deleterData.deletedUserId': userId
|
|
|
|
}).exec()
|
|
|
|
|
|
|
|
deletedUser.user = undefined
|
|
|
|
deletedUser.deleterData.deleterIpAddress = undefined
|
|
|
|
await deletedUser.save()
|
|
|
|
}
|
|
|
|
|
|
|
|
async function expireDeletedUsersAfterDuration() {
|
|
|
|
const DURATION = 90
|
|
|
|
let deletedUsers = await DeletedUser.find({
|
|
|
|
'deleterData.deletedAt': {
|
|
|
|
$lt: new Date(moment().subtract(DURATION, 'days'))
|
|
|
|
},
|
|
|
|
user: {
|
|
|
|
$ne: null
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2019-07-18 10:18:56 -04:00
|
|
|
}).exec()
|
|
|
|
|
|
|
|
if (deletedUsers.length === 0) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let i = 0; i < deletedUsers.length; i++) {
|
2019-08-28 08:59:41 -04:00
|
|
|
await expireDeletedUser(deletedUsers[i].deleterData.deletedUserId)
|
2019-07-18 10:18:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureCanDeleteUser(user) {
|
2019-08-28 08:59:41 -04:00
|
|
|
const subscription = await SubscriptionLocator.promises.getUsersSubscription(
|
|
|
|
user
|
|
|
|
)
|
|
|
|
if (subscription) {
|
|
|
|
throw new Errors.SubscriptionAdminDeletionError({})
|
|
|
|
}
|
2019-07-18 10:18:56 -04:00
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2019-07-18 10:18:56 -04:00
|
|
|
async function _createDeletedUser(user, options) {
|
2020-02-12 10:14:57 -05:00
|
|
|
await DeletedUser.update(
|
|
|
|
{ 'deleterData.deletedUserId': user._id },
|
|
|
|
{
|
|
|
|
user: user,
|
|
|
|
deleterData: {
|
|
|
|
deletedAt: new Date(),
|
|
|
|
deleterId: options.deleterUser ? options.deleterUser._id : undefined,
|
|
|
|
deleterIpAddress: options.ipAddress,
|
|
|
|
deletedUserId: user._id,
|
|
|
|
deletedUserLastLoggedIn: user.lastLoggedIn,
|
|
|
|
deletedUserSignUpDate: user.signUpDate,
|
|
|
|
deletedUserLoginCount: user.loginCount,
|
|
|
|
deletedUserReferralId: user.referal_id,
|
|
|
|
deletedUserReferredUsers: user.refered_users,
|
|
|
|
deletedUserReferredUserCount: user.refered_user_count,
|
|
|
|
deletedUserOverleafId: user.overleaf ? user.overleaf.id : undefined
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ upsert: true }
|
|
|
|
)
|
2019-07-18 10:18:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
async function _cleanupUser(user) {
|
2019-12-10 03:10:05 -05:00
|
|
|
await UserSessionsManager.promises.revokeAllUserSessions(user._id, [])
|
2019-09-25 10:27:38 -04:00
|
|
|
await NewsletterManager.promises.unsubscribe(user, { delete: true })
|
2019-08-28 08:59:41 -04:00
|
|
|
await SubscriptionHandler.promises.cancelSubscription(user)
|
|
|
|
await InstitutionsAPI.promises.deleteAffiliations(user._id)
|
|
|
|
await SubscriptionUpdater.promises.removeUserFromAllGroups(user._id)
|
|
|
|
await UserMembershipsHandler.promises.removeUserFromAllEntities(user._id)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|