diff --git a/packages/component-invite/src/routes/collectionsInvitations/patch.js b/packages/component-invite/src/routes/collectionsInvitations/patch.js index 6850b04fe8756c965ffdf8e61d6db1e7f9e04098..19e95891cbedfb9e8ec0f0309986e78fe404803b 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/patch.js +++ b/packages/component-invite/src/routes/collectionsInvitations/patch.js @@ -27,19 +27,30 @@ module.exports = models => async (req, res) => { }) return } - - await collectionHelper.updateHandlingEditor(collection, isAccepted) + if (invitation.userId !== user.id) { + res.status(403).json({ + error: `User ${user.email} is not allowed to modify invitation ${ + invitation.id + }`, + }) + return + } + if (invitation.role === 'handlingEditor') + await collectionHelper.updateHandlingEditor(collection, isAccepted) invitation.timestamp = Date.now() invitation.hasAnswer = true const eic = await userHelper.getEditorInChief(models.User) if (isAccepted === true) { invitation.isAccepted = true + let toEmail = eic.email + if (invitation.role === 'reviewer') + toEmail = collection.handlingEditor.email await collection.save() try { - await mailService.setupHandlingEditorAgreedEmail( - eic.email, + await mailService.setupAgreeEmail( + toEmail, user, - 'handling-editor-agreed', + invitation.role, `${req.protocol}://${req.get('host')}`, collection.customId, ) diff --git a/packages/component-invite/src/tests/collectionsInvitations/patch.test.js b/packages/component-invite/src/tests/collectionsInvitations/patch.test.js index 3a1bec6bb8a6c41358a291ae60247143198db47d..62c4332bd2fbadaba33ceda8f3cfa2a98c6eed90 100644 --- a/packages/component-invite/src/tests/collectionsInvitations/patch.test.js +++ b/packages/component-invite/src/tests/collectionsInvitations/patch.test.js @@ -9,7 +9,7 @@ const cloneDeep = require('lodash/cloneDeep') const models = Model.build() jest.mock('pubsweet-component-mail-service', () => ({ setupAssignEmail: jest.fn(), - setupHandlingEditorAgreedEmail: jest.fn(), + setupAgreeEmail: jest.fn(), setupDeclineEmail: jest.fn(), })) @@ -32,7 +32,26 @@ describe('Patch collections invitations route handler', () => { }) req.user = handlingEditor.id req.params.collectionId = collection.id - req.params.invitationId = collection.invitations[0].id + const heInv = collection.invitations.find( + inv => inv.role === 'handlingEditor', + ) + req.params.invitationId = heInv.id + const res = httpMocks.createResponse() + await require(patchPath)(models)(req, res) + expect(res.statusCode).toBe(200) + }) + it('should return success when the reviewer agrees work on a collection', async () => { + const { reviewer } = testFixtures.users + const { collection } = testFixtures.collections + const req = httpMocks.createRequest({ + body, + }) + req.user = reviewer.id + req.params.collectionId = collection.id + const reviewerInv = collection.invitations.find( + inv => inv.role === 'reviewer', + ) + req.params.invitationId = reviewerInv.id const res = httpMocks.createResponse() await require(patchPath)(models)(req, res) expect(res.statusCode).toBe(200) @@ -99,4 +118,24 @@ describe('Patch collections invitations route handler', () => { const data = JSON.parse(res._getData()) expect(data.error).toEqual('Invitation invalid-id not found') }) + it("should return an error when a user tries to patch another user's invitation", async () => { + const { reviewer } = testFixtures.users + const { collection } = testFixtures.collections + const req = httpMocks.createRequest({ + body, + }) + req.user = reviewer.id + req.params.collectionId = collection.id + const inv = collection.invitations.find( + inv => inv.role === 'handlingEditor', + ) + req.params.invitationId = inv.id + const res = httpMocks.createResponse() + await require(patchPath)(models)(req, res) + expect(res.statusCode).toBe(403) + const data = JSON.parse(res._getData()) + expect(data.error).toEqual( + `User ${reviewer.email} is not allowed to modify invitation ${inv.id}`, + ) + }) }) diff --git a/packages/component-invite/src/tests/fixtures/collections.js b/packages/component-invite/src/tests/fixtures/collections.js index b0dba9b453dfd87051819890335cd5e82f0b1e8a..78920b4aa04df9a88ae59d850cf3daa0fb95d4bb 100644 --- a/packages/component-invite/src/tests/fixtures/collections.js +++ b/packages/component-invite/src/tests/fixtures/collections.js @@ -1,5 +1,5 @@ const Chance = require('chance') -const { user, handlingEditor, author } = require('./userData') +const { user, handlingEditor, author, reviewer } = require('./userData') const { fragment } = require('./fragments') const chance = new Chance() @@ -27,6 +27,14 @@ const collections = { userId: handlingEditor.id, timestamp: chance.timestamp(), }, + { + id: chance.guid(), + role: 'reviewer', + hasAnswer: false, + isAccepted: false, + userId: reviewer.id, + timestamp: chance.timestamp(), + }, ], handlingEditor: { id: handlingEditor.id, diff --git a/packages/component-invite/src/tests/fixtures/userData.js b/packages/component-invite/src/tests/fixtures/userData.js index de7459c0deabe1dc45b725d355bb609394fef0fc..a7046079c834babe37fbf2524fd9349b4368f04a 100644 --- a/packages/component-invite/src/tests/fixtures/userData.js +++ b/packages/component-invite/src/tests/fixtures/userData.js @@ -1,27 +1,17 @@ const Chance = require('chance') const chance = new Chance() +const generateUserData = () => ({ + id: chance.guid(), + email: chance.email(), + firstName: chance.first(), + lastName: chance.last(), +}) + module.exports = { - handlingEditor: { - id: chance.guid(), - email: chance.email(), - firstName: chance.first(), - lastName: chance.last(), - }, - user: { - id: chance.guid(), - email: chance.email(), - firstName: chance.first(), - lastName: chance.last(), - }, - admin: { - id: chance.guid(), - email: chance.email(), - }, - author: { - id: chance.guid(), - email: chance.email(), - firstName: chance.first(), - lastName: chance.last(), - }, + handlingEditor: generateUserData(), + user: generateUserData(), + admin: generateUserData(), + author: generateUserData(), + reviewer: generateUserData(), } diff --git a/packages/component-invite/src/tests/fixtures/users.js b/packages/component-invite/src/tests/fixtures/users.js index c36f0a74c4b33715e771c53c2798f3614b06fe99..c474cfc7ad10a44ef6d65e7d1b4665d42ce074d9 100644 --- a/packages/component-invite/src/tests/fixtures/users.js +++ b/packages/component-invite/src/tests/fixtures/users.js @@ -1,5 +1,5 @@ const { heTeamID } = require('./teamIDs') -const { handlingEditor, user, admin, author } = require('./userData') +const { handlingEditor, user, admin, author, reviewer } = require('./userData') const Chance = require('chance') const chance = new Chance() @@ -8,6 +8,8 @@ const users = { type: 'user', username: 'admin', email: admin.email, + firstName: admin.firstName, + lastName: admin.lastName, password: 'test', admin: true, id: admin.id, @@ -71,6 +73,20 @@ const users = { save: jest.fn(() => users.author), isConfirmed: true, }, + reviewer: { + type: 'user', + username: chance.word(), + email: reviewer.email, + password: 'password', + admin: false, + id: reviewer.id, + firstName: reviewer.firstName, + lastName: reviewer.lastName, + affiliation: chance.company(), + title: 'Mr', + save: jest.fn(() => users.reviewer), + isConfirmed: true, + }, } module.exports = users diff --git a/packages/component-mail-service/src/Mail.js b/packages/component-mail-service/src/Mail.js index 6e53819af265a36240a1878f8d369c1f2f868a04..3f051acb65a7ba87425e201c2b788ea1beca1021 100644 --- a/packages/component-mail-service/src/Mail.js +++ b/packages/component-mail-service/src/Mail.js @@ -91,22 +91,24 @@ module.exports = { } return Email.send(mailData) }, - setupHandlingEditorAgreedEmail: async ( - toEmail, - user, - emailType, - url, - collectionId, - ) => { - const { htmlBody, textBody } = getEmailBody(emailType, { + setupAgreeEmail: async (toEmail, user, invRole, url, collectionId) => { + let role = 'Handling Editor' + let subject = 'Handling Editor Agreed' + if (invRole === 'reviewer') { + subject = 'Reviewer Agreed' + role = 'Reviewer' + } + const { htmlBody, textBody } = getEmailBody('agree', { url, + role, name: `${user.firstName} ${user.lastName}`, collectionId, }) + const mailData = { from: config.get('mailer.from'), to: toEmail, - subject: 'Handling Editor Agreed', + subject, text: textBody, html: htmlBody, } @@ -152,6 +154,8 @@ module.exports = { agreeUrl = `${baseUrl}${resetPath}?${querystring.encode({ email: invitedUser.email, token: invitedUser.passwordResetToken, + collectionId: collection.id, + agree: true, })}` } diff --git a/packages/component-mail-service/src/templates/handling-editor-agreed.html b/packages/component-mail-service/src/templates/agree.html similarity index 98% rename from packages/component-mail-service/src/templates/handling-editor-agreed.html rename to packages/component-mail-service/src/templates/agree.html index 3f24b1f4216f3d8554def6a0bc63fc80fb4afa36..edf453b48652d2035e12eda8b4a8a64aea03868b 100644 --- a/packages/component-mail-service/src/templates/handling-editor-agreed.html +++ b/packages/component-mail-service/src/templates/agree.html @@ -145,7 +145,7 @@ width="100%" style="display: none !important; mso-hide: all; visibility: hidden; opacity: 0; color: transparent; height: 0; width: 0;"> <tr> <td role="module-content"> - <p>handling editor agreed</p> + <p>a user has agreed</p> </td> </tr> </table> @@ -163,7 +163,7 @@ <table class="module" role="module" data-type="text" border="0" cellpadding="0" cellspacing="0" width="100%" style="table-layout: fixed;"> <tr> <td style="padding:30px 23px 0px 23px;background-color:#ffffff;" height="100%" valign="top" bgcolor="#ffffff"> - <h1 style="text-align: center;">{{ name }} has agreed to be Handling Editor on manuscript {{ collectionId }}</h1> + <h1 style="text-align: center;">{{ name }} has agreed to be a {{ role }} on manuscript {{ collectionId }}.</h1> <div style="text-align: center;">Please click on the link below to access your dashboard.</div> diff --git a/packages/component-mail-service/src/templates/handling-editor-agreed.txt b/packages/component-mail-service/src/templates/agree.txt similarity index 68% rename from packages/component-mail-service/src/templates/handling-editor-agreed.txt rename to packages/component-mail-service/src/templates/agree.txt index 550581b4489de9dca0da675eb4c3da2db498d815..ea941f3dd075d300a0d769130ad7698e165508c2 100644 --- a/packages/component-mail-service/src/templates/handling-editor-agreed.txt +++ b/packages/component-mail-service/src/templates/agree.txt @@ -1,4 +1,4 @@ -{{ name }} has agreed to be Handling Editor on manuscript {{ collectionId }} +{{ name }} has agreed to be a {{ role }} on manuscript {{ collectionId }} Please click on the link below to access your dashboard {{ url }} VIEW DASHBOARD Hindawi Publishing Corporation