diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsController.js b/services/web/app/src/Features/Collaborators/CollaboratorsController.js index 94b5687322..4707d4413a 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsController.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsController.js @@ -12,6 +12,7 @@ const logger = require('@overleaf/logger') const { expressify } = require('../../util/promises') const { hasAdminAccess } = require('../Helpers/AdminAuthorizationHelper') const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler') +const ProjectAuditLogHandler = require('../Project/ProjectAuditLogHandler') module.exports = { removeUserFromProject: expressify(removeUserFromProject), @@ -25,10 +26,20 @@ module.exports = { async function removeUserFromProject(req, res, next) { const projectId = req.params.Project_id const userId = req.params.user_id + const sessionUserId = SessionManager.getLoggedInUserId(req.session) await _removeUserIdFromProject(projectId, userId) EditorRealTimeController.emitToRoom(projectId, 'project:membership:changed', { members: true, }) + + ProjectAuditLogHandler.addEntryInBackground( + projectId, + 'remove-collaborator', + sessionUserId, + req.ip, + { userId } + ) + res.sendStatus(204) } @@ -36,6 +47,14 @@ async function removeSelfFromProject(req, res, next) { const projectId = req.params.Project_id const userId = SessionManager.getLoggedInUserId(req.session) await _removeUserIdFromProject(projectId, userId) + + ProjectAuditLogHandler.addEntryInBackground( + projectId, + 'leave-project', + userId, + req.ip + ) + res.sendStatus(204) } diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js index 22c34a31a0..9eb99105b3 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsControllerTests.js @@ -54,6 +54,10 @@ describe('CollaboratorsController', function () { getRequestToken: sinon.stub().returns('access-token'), } + this.ProjectAuditLogHandler = { + addEntryInBackground: sinon.stub(), + } + this.CollaboratorsController = SandboxedModule.require(MODULE_PATH, { requires: { mongodb: { ObjectId }, @@ -65,6 +69,7 @@ describe('CollaboratorsController', function () { '../Tags/TagsHandler': this.TagsHandler, '../Authentication/SessionManager': this.SessionManager, '../TokenAccess/TokenAccessHandler': this.TokenAccessHandler, + '../Project/ProjectAuditLogHandler': this.ProjectAuditLogHandler, }, }) }) @@ -105,6 +110,16 @@ describe('CollaboratorsController', function () { 'project:membership:changed' ) }) + + it('should write a project audit log', function () { + this.ProjectAuditLogHandler.addEntryInBackground.should.have.been.calledWith( + this.projectId, + 'remove-collaborator', + this.user._id, + this.req.ip, + { userId: this.user._id } + ) + }) }) describe('removeSelfFromProject', function () { @@ -139,6 +154,15 @@ describe('CollaboratorsController', function () { it('should return a success code', function () { this.res.sendStatus.calledWith(204).should.equal(true) }) + + it('should write a project audit log', function () { + this.ProjectAuditLogHandler.addEntryInBackground.should.have.been.calledWith( + this.projectId, + 'leave-project', + this.user._id, + this.req.ip + ) + }) }) describe('getAllMembers', function () {