UserDeleter.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. const { callbackify } = require('util')
  2. const logger = require('@overleaf/logger')
  3. const moment = require('moment')
  4. const { User } = require('../../models/User')
  5. const { DeletedUser } = require('../../models/DeletedUser')
  6. const { UserAuditLogEntry } = require('../../models/UserAuditLogEntry')
  7. const { Feedback } = require('../../models/Feedback')
  8. const NewsletterManager = require('../Newsletter/NewsletterManager')
  9. const ProjectDeleter = require('../Project/ProjectDeleter')
  10. const SubscriptionHandler = require('../Subscription/SubscriptionHandler')
  11. const SubscriptionUpdater = require('../Subscription/SubscriptionUpdater')
  12. const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
  13. const UserMembershipsHandler = require('../UserMembership/UserMembershipsHandler')
  14. const UserSessionsManager = require('./UserSessionsManager')
  15. const InstitutionsAPI = require('../Institutions/InstitutionsAPI')
  16. const Modules = require('../../infrastructure/Modules')
  17. const Errors = require('../Errors/Errors')
  18. const OnboardingDataCollectionManager = require('../OnboardingDataCollection/OnboardingDataCollectionManager')
  19. module.exports = {
  20. deleteUser: callbackify(deleteUser),
  21. deleteMongoUser: callbackify(deleteMongoUser),
  22. expireDeletedUser: callbackify(expireDeletedUser),
  23. ensureCanDeleteUser: callbackify(ensureCanDeleteUser),
  24. expireDeletedUsersAfterDuration: callbackify(expireDeletedUsersAfterDuration),
  25. promises: {
  26. deleteUser,
  27. deleteMongoUser,
  28. expireDeletedUser,
  29. ensureCanDeleteUser,
  30. expireDeletedUsersAfterDuration,
  31. },
  32. }
  33. async function deleteUser(userId, options = {}) {
  34. if (!userId) {
  35. logger.warn('user_id is null when trying to delete user')
  36. throw new Error('no user_id')
  37. }
  38. try {
  39. const user = await User.findById(userId).exec()
  40. logger.debug({ user }, 'deleting user')
  41. await ensureCanDeleteUser(user)
  42. await _cleanupUser(user)
  43. await Modules.promises.hooks.fire('deleteUser', userId)
  44. await _createDeletedUser(user, options)
  45. await ProjectDeleter.promises.deleteUsersProjects(user._id)
  46. await deleteMongoUser(user._id)
  47. } catch (error) {
  48. logger.warn({ error, userId }, 'something went wrong deleting the user')
  49. throw error
  50. }
  51. }
  52. /**
  53. * delete a user document only
  54. */
  55. async function deleteMongoUser(userId) {
  56. if (!userId) {
  57. throw new Error('no user_id')
  58. }
  59. await User.deleteOne({ _id: userId }).exec()
  60. }
  61. async function expireDeletedUser(userId) {
  62. await Modules.promises.hooks.fire('expireDeletedUser', userId)
  63. const deletedUser = await DeletedUser.findOne({
  64. 'deleterData.deletedUserId': userId,
  65. }).exec()
  66. await Feedback.deleteMany({ userId }).exec()
  67. await OnboardingDataCollectionManager.deleteOnboardingDataCollection(userId)
  68. deletedUser.user = undefined
  69. deletedUser.deleterData.deleterIpAddress = undefined
  70. await deletedUser.save()
  71. }
  72. async function expireDeletedUsersAfterDuration() {
  73. const DURATION = 90
  74. const deletedUsers = await DeletedUser.find({
  75. 'deleterData.deletedAt': {
  76. $lt: new Date(moment().subtract(DURATION, 'days')),
  77. },
  78. user: {
  79. $ne: null,
  80. },
  81. }).exec()
  82. if (deletedUsers.length === 0) {
  83. return
  84. }
  85. for (let i = 0; i < deletedUsers.length; i++) {
  86. const deletedUserId = deletedUsers[i].deleterData.deletedUserId
  87. await expireDeletedUser(deletedUserId)
  88. await UserAuditLogEntry.deleteMany({ userId: deletedUserId }).exec()
  89. }
  90. }
  91. async function ensureCanDeleteUser(user) {
  92. const subscription = await SubscriptionLocator.promises.getUsersSubscription(
  93. user
  94. )
  95. if (subscription) {
  96. throw new Errors.SubscriptionAdminDeletionError({})
  97. }
  98. }
  99. async function _createDeletedUser(user, options) {
  100. await DeletedUser.updateOne(
  101. { 'deleterData.deletedUserId': user._id },
  102. {
  103. user,
  104. deleterData: {
  105. deletedAt: new Date(),
  106. deleterId: options.deleterUser ? options.deleterUser._id : undefined,
  107. deleterIpAddress: options.ipAddress,
  108. deletedUserId: user._id,
  109. deletedUserLastLoggedIn: user.lastLoggedIn,
  110. deletedUserSignUpDate: user.signUpDate,
  111. deletedUserLoginCount: user.loginCount,
  112. deletedUserReferralId: user.referal_id,
  113. deletedUserReferredUsers: user.refered_users,
  114. deletedUserReferredUserCount: user.refered_user_count,
  115. deletedUserOverleafId: user.overleaf ? user.overleaf.id : undefined,
  116. },
  117. },
  118. { upsert: true }
  119. )
  120. }
  121. async function _cleanupUser(user) {
  122. await UserSessionsManager.promises.revokeAllUserSessions(user._id, [])
  123. await NewsletterManager.promises.unsubscribe(user, { delete: true })
  124. await SubscriptionHandler.promises.cancelSubscription(user)
  125. await InstitutionsAPI.promises.deleteAffiliations(user._id)
  126. await SubscriptionUpdater.promises.removeUserFromAllGroups(user._id)
  127. await UserMembershipsHandler.promises.removeUserFromAllEntities(user._id)
  128. }