diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs index afca4cf248..945c14034c 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.mjs @@ -7,6 +7,7 @@ import ContactManager from '../Contacts/ContactManager.mjs' import PrivilegeLevels from '../Authorization/PrivilegeLevels.mjs' import TpdsProjectFlusher from '../ThirdPartyDataStore/TpdsProjectFlusher.mjs' import CollaboratorsGetter from './CollaboratorsGetter.mjs' +import CollaboratorsInviteHelper from './CollaboratorsInviteHelper.mjs' import Errors from '../Errors/Errors.js' import TpdsUpdateSender from '../ThirdPartyDataStore/TpdsUpdateSender.mjs' import EditorRealTimeController from '../Editor/EditorRealTimeController.mjs' @@ -361,7 +362,7 @@ async function setCollaboratorPrivilegeLevel( auditInfo.ipAddress, { userId, - role: _privilegeLevelToRole(privilegeLevel), + role: CollaboratorsInviteHelper.privilegeLevelToRole(privilegeLevel), } ) @@ -374,19 +375,6 @@ async function setCollaboratorPrivilegeLevel( } } -function _privilegeLevelToRole(privilegeLevel) { - switch (privilegeLevel) { - case 'readOnly': - return 'Viewer' - case 'readAndWrite': - return 'Editor' - case 'review': - return 'Reviewer' - default: - return privilegeLevel - } -} - async function userIsTokenMember(userId, projectId) { if (!userId) { return false diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs index 28cd74e343..a10db10cbc 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteController.mjs @@ -4,6 +4,7 @@ import UserGetter from '../User/UserGetter.mjs' import CollaboratorsGetter from './CollaboratorsGetter.mjs' import CollaboratorsInviteHandler from './CollaboratorsInviteHandler.mjs' import CollaboratorsInviteGetter from './CollaboratorsInviteGetter.mjs' +import CollaboratorsInviteHelper from './CollaboratorsInviteHelper.mjs' import logger from '@overleaf/logger' import Settings from '@overleaf/settings' import EmailHelper from '../Helpers/EmailHelper.mjs' @@ -171,7 +172,7 @@ async function inviteToProject(req, res) { req.ip, { inviteId: invite._id, - privileges, + role: CollaboratorsInviteHelper.privilegeLevelToRole(invite.privileges), } ) @@ -202,7 +203,7 @@ async function revokeInvite(req, res) { req.ip, { inviteId: invite._id, - privileges: invite.privileges, + role: CollaboratorsInviteHelper.privilegeLevelToRole(invite.privileges), } ) EditorRealTimeController.emitToRoom( diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs index c10db1f9e9..bf8e74e97c 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs +++ b/services/web/app/src/Features/Collaborators/CollaboratorsInviteHelper.mjs @@ -11,7 +11,21 @@ function hashInviteToken(token) { .digest('hex') } +function privilegeLevelToRole(privilegeLevel) { + switch (privilegeLevel) { + case 'readOnly': + return 'Viewer' + case 'readAndWrite': + return 'Editor' + case 'review': + return 'Reviewer' + default: + return privilegeLevel + } +} + export default { generateToken, hashInviteToken, + privilegeLevelToRole, } diff --git a/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs b/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs index a9415a59d5..d4608d93f3 100644 --- a/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs +++ b/services/web/app/src/Features/Project/ProjectAuditLogHandler.mjs @@ -19,6 +19,9 @@ const MANAGED_GROUP_PROJECT_EVENTS = [ 'project-history-version-restored', 'project-history-version-downloaded', 'transfer-ownership', + 'remove-collaborator', + 'revoke-invite', + 'toggle-access-level', 'project-downloaded', ] diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs index 3c3be83b9b..edcf57f16c 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs +++ b/services/web/test/unit/src/Collaborators/CollaboratorsInviteController.test.mjs @@ -22,6 +22,7 @@ describe('CollaboratorsInviteController', function () { ctx.tokenHmac = 'some-hmac-token' ctx.targetEmail = 'user@example.com' ctx.privileges = 'readAndWrite' + ctx.role = 'Editor' ctx.projectOwner = { _id: 'project-owner-id', email: 'project-owner@example.com', @@ -366,7 +367,7 @@ describe('CollaboratorsInviteController', function () { ctx.req.ip, { inviteId: ctx.invite._id, - privileges: ctx.privileges, + role: ctx.role, } ) }) @@ -381,6 +382,7 @@ describe('CollaboratorsInviteController', function () { beforeEach(async function (ctx) { await new Promise(resolve => { ctx.privileges = 'readAndWrite' + ctx.role = 'Editor' ctx.CollaboratorsInviteController._checkShouldInviteEmail = sinon .stub() .resolves(true) @@ -421,10 +423,23 @@ describe('CollaboratorsInviteController', function () { describe('readOnly collaborator (always allowed)', function () { beforeEach(async function (ctx) { + ctx.privileges = 'readOnly' + ctx.role = 'Viewer' + // Update the invite data to reflect the new privileges + ctx.invite.privileges = ctx.privileges + ctx.inviteReducedData = _.pick(ctx.invite, [ + '_id', + 'email', + 'privileges', + ]) + ctx.CollaboratorsInviteHandler.promises.inviteToProject.resolves( + ctx.inviteReducedData + ) + await new Promise(resolve => { ctx.req.body = { email: ctx.targetEmail, - privileges: (ctx.privileges = 'readOnly'), + privileges: ctx.privileges, } ctx.CollaboratorsInviteController._checkShouldInviteEmail = sinon .stub() @@ -492,7 +507,7 @@ describe('CollaboratorsInviteController', function () { ctx.req.ip, { inviteId: ctx.invite._id, - privileges: ctx.privileges, + role: ctx.role, } ) }) @@ -1389,7 +1404,7 @@ describe('CollaboratorsInviteController', function () { ctx.req.ip, { inviteId: ctx.invite._id, - privileges: ctx.privileges, + role: ctx.role, } ) })