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;">&nbsp;</div>
+                                      <p>&nbsp;</p>
 
-                                    <div style="text-align: center;">&nbsp;</div>
+                                      <p>You are no longer needed to review the article titled &quot;{{ title }}&quot; 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>&nbsp;</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