diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js index 7247c9170d..5a70d2a621 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsHandler.js @@ -149,32 +149,12 @@ async function addUserIdToProject( } if (privilegeLevel === PrivilegeLevels.REVIEW) { - const trackChanges = - typeof project.track_changes === 'object' ? project.track_changes : {} - + const trackChanges = await convertTrackChangesToExplicitFormat( + projectId, + project.track_changes + ) trackChanges[userId] = true - if (project.track_changes === true) { - // track changes are enabled for all - // we need to convert it to explicit format - const members = - await CollaboratorsGetter.promises.getMemberIdsWithPrivilegeLevels( - project - ) - - for (const { id, privilegeLevel } of members) { - if ( - [ - PrivilegeLevels.OWNER, - PrivilegeLevels.READ_AND_WRITE, - PrivilegeLevels.REVIEW, - ].includes(privilegeLevel) - ) { - trackChanges[id] = true - } - } - } - await Project.updateOne( { _id: projectId }, { track_changes: trackChanges, $addToSet: level } @@ -312,6 +292,22 @@ async function setCollaboratorPrivilegeLevel( }, $addToSet: { reviewer_refs: userId }, } + + const project = await ProjectGetter.promises.getProject(projectId, { + track_changes: true, + }) + const newTrackChangesState = await convertTrackChangesToExplicitFormat( + projectId, + project.track_changes + ) + if (newTrackChangesState[userId] !== true) { + newTrackChangesState[userId] = true + } + if (typeof project.track_changes === 'object') { + update.$set = { [`track_changes.${userId}`]: true } + } else { + update.$set = { track_changes: newTrackChangesState } + } break } case PrivilegeLevels.READ_ONLY: { @@ -334,6 +330,14 @@ async function setCollaboratorPrivilegeLevel( if (mongoResponse.matchedCount === 0) { throw new Errors.NotFoundError('project or collaborator not found') } + + if (update.$set?.track_changes) { + EditorRealTimeController.emitToRoom( + projectId, + 'toggle-track-changes', + update.$set.track_changes + ) + } } async function userIsTokenMember(userId, projectId) { @@ -367,3 +371,37 @@ async function _flushProjects(projectIds) { await TpdsProjectFlusher.promises.flushProjectToTpds(projectId) } } + +async function convertTrackChangesToExplicitFormat( + projectId, + trackChangesState +) { + if (typeof trackChangesState === 'object') { + return { ...trackChangesState } + } + + if (trackChangesState === true) { + // track changes are enabled for all + const members = + await CollaboratorsGetter.promises.getMemberIdsWithPrivilegeLevels( + projectId + ) + + const newTrackChangesState = {} + for (const { id, privilegeLevel } of members) { + if ( + [ + PrivilegeLevels.OWNER, + PrivilegeLevels.READ_AND_WRITE, + PrivilegeLevels.REVIEW, + ].includes(privilegeLevel) + ) { + newTrackChangesState[id] = true + } + } + + return newTrackChangesState + } + + return {} +} diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js index 8e14590b0f..caca5b0145 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsHandlerTests.js @@ -640,33 +640,86 @@ describe('CollaboratorsHandler', function () { ) }) - it('sets a collaborator to reviewer', async function () { - this.ProjectMock.expects('updateOne') - .withArgs( - { - _id: this.projectId, - $or: [ - { collaberator_refs: this.userId }, - { readOnly_refs: this.userId }, - { reviewer_refs: this.userId }, - ], - }, - { - $addToSet: { reviewer_refs: this.userId }, - $pull: { - readOnly_refs: this.userId, - collaberator_refs: this.userId, - pendingEditor_refs: this.userId, + describe('sets a collaborator to reviewer when track changes is enabled for everyone', function () { + beforeEach(function () { + this.ProjectGetter.promises.getProject = sinon.stub().resolves({ + _id: new ObjectId(), + owner_ref: this.addingUserId, + name: 'Foo', + track_changes: true, + }) + }) + it('should correctly update the project', async function () { + this.ProjectMock.expects('updateOne') + .withArgs( + { + _id: this.projectId, + $or: [ + { collaberator_refs: this.userId }, + { readOnly_refs: this.userId }, + { reviewer_refs: this.userId }, + ], }, - } + { + $addToSet: { reviewer_refs: this.userId }, + $set: { track_changes: { [this.userId]: true } }, + $pull: { + readOnly_refs: this.userId, + collaberator_refs: this.userId, + pendingEditor_refs: this.userId, + }, + } + ) + .chain('exec') + .resolves({ matchedCount: 1 }) + await this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel( + this.projectId, + this.userId, + 'review' ) - .chain('exec') - .resolves({ matchedCount: 1 }) - await this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel( - this.projectId, - this.userId, - 'review' - ) + }) + }) + + describe('sets a collaborator to reviewer when track changes is not enabled for everyone', function () { + beforeEach(function () { + this.ProjectGetter.promises.getProject = sinon.stub().resolves({ + _id: new ObjectId(), + owner_ref: this.addingUserId, + name: 'Foo', + track_changes: { + [this.userId]: true, + }, + }) + }) + it('should correctly update the project', async function () { + this.ProjectMock.expects('updateOne') + .withArgs( + { + _id: this.projectId, + $or: [ + { collaberator_refs: this.userId }, + { readOnly_refs: this.userId }, + { reviewer_refs: this.userId }, + ], + }, + { + $addToSet: { reviewer_refs: this.userId }, + $set: { [`track_changes.${this.userId}`]: true }, + $pull: { + readOnly_refs: this.userId, + collaberator_refs: this.userId, + pendingEditor_refs: this.userId, + }, + } + ) + .chain('exec') + .resolves({ matchedCount: 1 }) + await this.CollaboratorsHandler.promises.setCollaboratorPrivilegeLevel( + this.projectId, + this.userId, + 'review' + ) + }) }) it('sets a collaborator to read-only as a pendingEditor', async function () {