From 7d0e75e4f7c624984582d27de37af12c8b0dedfa Mon Sep 17 00:00:00 2001 From: Miguel Serrano Date: Thu, 13 Nov 2025 09:08:29 +0100 Subject: [PATCH] [web] Managed Group Audit Logs for project management (#29584) GitOrigin-RevId: 8edf4e580c001db3129c276d23e90ce9e82ac2ea --- .../Project/ProjectAuditLogHandler.mjs | 12 ++++- .../Features/Project/ProjectController.mjs | 44 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs b/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs index 8a594a7801..87f8bac857 100644 --- a/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs @@ -3,7 +3,17 @@ import { ProjectAuditLogEntry } from '../../models/ProjectAuditLogEntry.js' import { callbackify } from '@overleaf/promise-utils' import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs' -const MANAGED_GROUP_PROJECT_EVENTS = ['accept-invite', 'project-created'] +const MANAGED_GROUP_PROJECT_EVENTS = [ + 'accept-invite', + 'project-created', + 'project-deleted', + 'project-archived', + 'project-unarchived', + 'project-trashed', + 'project-untrashed', + 'project-restored', + 'project-cloned', +] export default { promises: { diff --git a/services/web/app/src/Features/Project/ProjectController.mjs b/services/web/app/src/Features/Project/ProjectController.mjs index 5d89b2c850..26c709b6d3 100644 --- a/services/web/app/src/Features/Project/ProjectController.mjs +++ b/services/web/app/src/Features/Project/ProjectController.mjs @@ -168,7 +168,12 @@ const _ProjectController = { deleterUser: user, ipAddress: req.ip, }) - + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-deleted', + user._id, + req.ip + ) res.sendStatus(200) }, @@ -176,6 +181,12 @@ const _ProjectController = { const projectId = req.params.Project_id const userId = SessionManager.getLoggedInUserId(req.session) await ProjectDeleter.promises.archiveProject(projectId, userId) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-archived', + userId, + req.ip + ) res.sendStatus(200) }, @@ -183,6 +194,12 @@ const _ProjectController = { const projectId = req.params.Project_id const userId = SessionManager.getLoggedInUserId(req.session) await ProjectDeleter.promises.unarchiveProject(projectId, userId) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-unarchived', + userId, + req.ip + ) res.sendStatus(200) }, @@ -190,6 +207,12 @@ const _ProjectController = { const projectId = req.params.project_id const userId = SessionManager.getLoggedInUserId(req.session) await ProjectDeleter.promises.trashProject(projectId, userId) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-trashed', + userId, + req.ip + ) res.sendStatus(200) }, @@ -197,6 +220,12 @@ const _ProjectController = { const projectId = req.params.project_id const userId = SessionManager.getLoggedInUserId(req.session) await ProjectDeleter.promises.untrashProject(projectId, userId) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-untrashed', + userId, + req.ip + ) res.sendStatus(200) }, @@ -212,8 +241,15 @@ const _ProjectController = { }, async restoreProject(req, res) { + const user = SessionManager.getLoggedInUserId(req.session) const projectId = req.params.Project_id await ProjectDeleter.promises.restoreProject(projectId) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-restored', + user._id, + req.ip + ) res.sendStatus(200) }, @@ -235,6 +271,12 @@ const _ProjectController = { projectName, tags ) + ProjectAuditLogHandler.addEntryIfManagedInBackground( + projectId, + 'project-cloned', + currentUser._id, + req.ip + ) res.json({ name: project.name, lastUpdated: project.lastUpdated,