From d9587e8b0666e6441ceff9c90abe499e3699ff39 Mon Sep 17 00:00:00 2001 From: Tim Down <158919+timdown@users.noreply.github.com> Date: Fri, 2 May 2025 11:21:45 +0100 Subject: [PATCH] Merge pull request #25264 from overleaf/bg-td-account-deletion-logging Add logging for each stage of user deletion GitOrigin-RevId: 13f9575012fcd8f166c4b14eba2ee5910658072e --- .../Collaborators/CollaboratorsHandler.js | 17 +++++++++++ .../src/Features/Project/ProjectDeleter.js | 5 ++++ .../web/app/src/Features/User/UserDeleter.js | 28 +++++++++++++++---- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js index 05137a97f8..96b4cd6e37 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js @@ -122,9 +122,26 @@ async function removeUserFromAllProjects(userId) { .concat(readOnly) .concat(tokenReadAndWrite) .concat(tokenReadOnly) + logger.info( + { + userId, + readAndWriteCount: readAndWrite.length, + readOnlyCount: readOnly.length, + tokenReadAndWriteCount: tokenReadAndWrite.length, + tokenReadOnlyCount: tokenReadOnly.length, + }, + 'removing user from projects' + ) for (const project of allProjects) { await removeUserFromProject(project._id, userId) } + logger.info( + { + userId, + allProjectsCount: allProjects.length, + }, + 'removed user from all projects' + ) } async function addUserIdToProject( diff --git a/services/web/app/src/Features/Project/ProjectDeleter.js b/services/web/app/src/Features/Project/ProjectDeleter.js index 62d893dd0f..c5dcafd335 100644 --- a/services/web/app/src/Features/Project/ProjectDeleter.js +++ b/services/web/app/src/Features/Project/ProjectDeleter.js @@ -80,7 +80,12 @@ async function unmarkAsDeletedByExternalSource(projectId) { async function deleteUsersProjects(userId) { const projects = await Project.find({ owner_ref: userId }).exec() + logger.info( + { userId, projectCount: projects.length }, + 'found user projects to delete' + ) await promiseMapWithLimit(5, projects, project => deleteProject(project._id)) + logger.info({ userId }, 'deleted all user projects') await CollaboratorsHandler.promises.removeUserFromAllProjects(userId) } diff --git a/services/web/app/src/Features/User/UserDeleter.js b/services/web/app/src/Features/User/UserDeleter.js index 4009419ffe..721943b163 100644 --- a/services/web/app/src/Features/User/UserDeleter.js +++ b/services/web/app/src/Features/User/UserDeleter.js @@ -43,21 +43,28 @@ async function deleteUser(userId, options) { try { const user = await User.findById(userId).exec() - logger.debug({ user }, 'deleting user') - + logger.info({ userId }, 'deleting user') await ensureCanDeleteUser(user) + logger.info({ userId }, 'cleaning up user') await _cleanupUser(user) + logger.info({ userId }, 'firing deleteUser hook') await Modules.promises.hooks.fire('deleteUser', userId) + logger.info({ userId }, 'adding delete-account audit log entry') await UserAuditLogHandler.promises.addEntry( userId, 'delete-account', options.deleterUser ? options.deleterUser._id : userId, options.ipAddress ) + logger.info({ userId }, 'creating deleted user record') await _createDeletedUser(user, options) + logger.info({ userId }, 'deleting user projects') await ProjectDeleter.promises.deleteUsersProjects(user._id) + logger.info({ userId }, 'sending deletion email to user') await _sendDeleteEmail(user, options.force) + logger.info({ userId }, 'deleting user record') await deleteMongoUser(user._id) + logger.info({ userId }, 'user deletion complete') } catch (error) { logger.warn({ error, userId }, 'something went wrong deleting the user') throw error @@ -161,13 +168,22 @@ async function _createDeletedUser(user, options) { } async function _cleanupUser(user) { + const userId = user._id + + logger.info({ userId }, '[cleanupUser] removing user sessions from Redis') await UserSessionsManager.promises.removeSessionsFromRedis(user) + logger.info({ userId }, '[cleanupUser] unsubscribing from newsletters') await NewsletterManager.promises.unsubscribe(user, { delete: true }) + logger.info({ userId }, '[cleanupUser] cancelling subscription') await SubscriptionHandler.promises.cancelSubscription(user) - await InstitutionsAPI.promises.deleteAffiliations(user._id) - await SubscriptionUpdater.promises.removeUserFromAllGroups(user._id) - await UserMembershipsHandler.promises.removeUserFromAllEntities(user._id) - await Modules.promises.hooks.fire('cleanupPersonalAccessTokens', user._id, [ + logger.info({ userId }, '[cleanupUser] deleting affiliations') + await InstitutionsAPI.promises.deleteAffiliations(userId) + logger.info({ userId }, '[cleanupUser] removing user from groups') + await SubscriptionUpdater.promises.removeUserFromAllGroups(userId) + logger.info({ userId }, '[cleanupUser] removing user from memberships') + await UserMembershipsHandler.promises.removeUserFromAllEntities(userId) + logger.info({ userId }, '[cleanupUser] removing personal access tokens') + await Modules.promises.hooks.fire('cleanupPersonalAccessTokens', userId, [ 'collabratec', 'git_bridge', ])