From 5c1de794d26b9e8f3046a20db2e553e312dd3fed Mon Sep 17 00:00:00 2001 From: Sebastian <sebastian.mihalache@thinslices.com> Date: Fri, 20 Apr 2018 14:52:07 +0300 Subject: [PATCH] feat(component-invite): add new decline route --- .../src/CollectionsInvitations.js | 22 ++++++ .../component-invite/src/helpers/helpers.js | 1 + .../routes/collectionsInvitations/decline.js | 70 +++++++++++++++++++ .../src/templates/unassign-reviewer.html | 20 ++++-- packages/xpub-faraday/config/validations.js | 1 + 5 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 packages/component-invite/src/routes/collectionsInvitations/decline.js diff --git a/packages/component-invite/src/CollectionsInvitations.js b/packages/component-invite/src/CollectionsInvitations.js index 808961f74..e9c0f3aa5 100644 --- a/packages/component-invite/src/CollectionsInvitations.js +++ b/packages/component-invite/src/CollectionsInvitations.js @@ -124,6 +124,28 @@ const CollectionsInvitations = app => { authBearer, require(`${routePath}/patch`)(app.locals.models), ) + /** + * @api {patch} /api/collections/:collectionId/invitations/:invitationId/decline Decline an invitation as a reviewer + * @apiGroup CollectionsInvitations + * @apiParam {collectionId} collectionId Collection id + * @apiParam {invitationId} invitationId Invitation id + * @apiParamExample {json} Body + * { + * "invitationToken": "f2d814f0-67a5-4590-ba4f-6a83565feb4f", + * } + * @apiSuccessExample {json} Success + * HTTP/1.1 200 OK + * {} + * @apiErrorExample {json} Update invitations errors + * HTTP/1.1 403 Forbidden + * HTTP/1.1 400 Bad Request + * HTTP/1.1 404 Not Found + * HTTP/1.1 500 Internal Server Error + */ + app.patch( + `${basePath}/:invitationId/decline`, + require(`${routePath}/decline`)(app.locals.models), + ) } module.exports = CollectionsInvitations diff --git a/packages/component-invite/src/helpers/helpers.js b/packages/component-invite/src/helpers/helpers.js index 0628217ee..429c91f29 100644 --- a/packages/component-invite/src/helpers/helpers.js +++ b/packages/component-invite/src/helpers/helpers.js @@ -99,6 +99,7 @@ const createNewUser = async ( editorInChief: role === 'editorInChief', admin: role === 'admin', handlingEditor: role === 'handlingEditor', + invitationToken: role === 'reviewer' ? uuid.v4() : '', } let newUser = new UserModel(userBody) diff --git a/packages/component-invite/src/routes/collectionsInvitations/decline.js b/packages/component-invite/src/routes/collectionsInvitations/decline.js new file mode 100644 index 000000000..5a955459b --- /dev/null +++ b/packages/component-invite/src/routes/collectionsInvitations/decline.js @@ -0,0 +1,70 @@ +const logger = require('@pubsweet/logger') +const helpers = require('../../helpers/helpers') +const teamHelper = require('../../helpers/Team') +const mailService = require('pubsweet-component-mail-service') + +module.exports = models => async (req, res) => { + const { collectionId, invitationId } = req.params + const { invitationToken } = req.body + + if (!helpers.checkForUndefinedParams(invitationToken)) + return res.status(400).json({ error: 'Token is required' }) + + try { + const user = await models.User.findOneByField( + 'invitationToken', + invitationToken, + ) + const collection = await models.Collection.find(collectionId) + const invitation = await collection.invitations.find( + invitation => invitation.id === invitationId, + ) + if (invitation === undefined) + return res.status(404).json({ + error: `Invitation ${invitationId} not found`, + }) + if (invitation.hasAnswer) + return res + .status(400) + .json({ error: `${invitation.id} has already been answered` }) + if (invitation.userId !== user.id) + return res.status(403).json({ + error: `User ${user.email} is not allowed to modify invitation ${ + invitation.id + }`, + }) + + invitation.timestamp = Date.now() + invitation.hasAnswer = true + const toEmail = collection.handlingEditor.email + invitation.isAccepted = false + const team = await teamHelper.getTeamByGroupAndCollection( + collectionId, + invitation.role, + models.Team, + ) + await collection.save() + await teamHelper.removeTeamMember(team.id, user.id, models.Team) + user.teams = user.teams.filter(userTeamId => team.id !== userTeamId) + try { + await mailService.setupDeclineEmail( + toEmail, + user, + 'decline', + collection.customId, + ) + } catch (e) { + logger.error(e) + return res.status(500).json({ error: 'Email could not be sent.' }) + } + + await user.save() + res.status(200).json({}) + return + } catch (e) { + const notFoundError = await helpers.handleNotFoundError(e, 'item') + return res.status(notFoundError.status).json({ + error: notFoundError.message, + }) + } +} diff --git a/packages/component-mail-service/src/templates/unassign-reviewer.html b/packages/component-mail-service/src/templates/unassign-reviewer.html index d733dcab1..46a6f82bf 100644 --- a/packages/component-mail-service/src/templates/unassign-reviewer.html +++ b/packages/component-mail-service/src/templates/unassign-reviewer.html @@ -1,4 +1,3 @@ - <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml"> @@ -164,17 +163,26 @@ <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;">Your Reviewer invitation to a manuscript has been revoked.</h1> + <div> + <p data-pm-slice="1 1 []">Dear {{ reivewerName }},</p> - <div style="text-align: center;"> </div> + <p> </p> - <div style="text-align: center;"> </div> + <p>You are no longer needed to review the article titled "{{ title }}" by {{ + authorName }}. If you have comments on this manuscript you believe the Editor should + see, please email them to {{ staffEmail }} as soon as possible. Thank you for your + time and I hope you will consider reviewing for Hindawi again.</p> + <p> </p> + <p>Best regards, + <br /> {{editorName}} + </p> + </div> </td> </tr> </table> - <div data-role="module-unsubscribe" class="module unsubscribe-css__unsubscribe___2CDlR" role="module" - data-type="unsubscribe" style="color:#444444;font-size:12px;line-height:20px;padding:16px 16px 16px 16px;text-align:center"> + <div data-role="module-unsubscribe" class="module unsubscribe-css__unsubscribe___2CDlR" role="module" data-type="unsubscribe" + style="color:#444444;font-size:12px;line-height:20px;padding:16px 16px 16px 16px;text-align:center"> <div class="Unsubscribe--addressLine"> <p class="Unsubscribe--senderName" style="font-family:Arial, Helvetica, sans-serif;font-size:12px;line-height:20px">Hindawi Publishing Corporation</p> <p style="font-family:Arial, Helvetica, sans-serif;font-size:12px;line-height:20px"> diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index d34c9ad53..64cbc2aea 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -101,6 +101,7 @@ module.exports = { teams: Joi.array(), editorInChief: Joi.boolean(), handlingEditor: Joi.boolean(), + invitationToken: Joi.string().allow(''), }, team: { group: Joi.string(), -- GitLab