Skip to content
Snippets Groups Projects
Commit f698fd43 authored by Sebastian Mihalache's avatar Sebastian Mihalache :hammer_pick:
Browse files

Merge branch 'HIN-1120-Reviewers-Invited-Major-Revision' into 'develop'

feat(ReviewerInvitation): Reviewers now invited, not accepted on major revision

See merge request !208
parents 8c490953 21da7fb8
No related branches found
No related tags found
3 merge requests!222Sprint #26,!217Sprint #26,!208feat(ReviewerInvitation): Reviewers now invited, not accepted on major revision
...@@ -13,7 +13,7 @@ const getEmailCopy = ({ ...@@ -13,7 +13,7 @@ const getEmailCopy = ({
eicName = 'Editor in Chief', eicName = 'Editor in Chief',
expectedDate = new Date(), expectedDate = new Date(),
}) => { }) => {
let paragraph let upperContent, manuscriptText, subText, lowerContent, paragraph
let hasLink = true let hasLink = true
let hasIntro = true let hasIntro = true
let hasSignature = true let hasSignature = true
...@@ -155,11 +155,31 @@ const getEmailCopy = ({ ...@@ -155,11 +155,31 @@ const getEmailCopy = ({
${comments}<br/><br/> ${comments}<br/><br/>
For more information about what is required, please click the link below.<br/><br/>` For more information about what is required, please click the link below.<br/><br/>`
break break
case 'reviewer-invitation':
upperContent = `A new version of ${titleText}, has been submitted to ${journalName} for consideration.<div>&nbsp;</div>
As you reviewed the previous version of this manuscript, I would be delighted if you would agree to review the new version and let me know whether you feel it is suitable for publication.`
subText = `The manuscript's abstract and author information is below to help you decide. Once you have agreed to review, you will be able to download the full article PDF.`
lowerContent = `If a potential conflict of interest exists between yourself and either the authors or
the subject of the manuscript, please decline to handle the manuscript. If a conflict
becomes apparent during the review process, please let me know at the earliest possible
opportunity. For more information about our conflicts of interest policies, please
see:
<a style="color:#007e92; text-decoration: none;" href="https://www.hindawi.com/ethics/#coi">https://www.hindawi.com/ethics/#coi</a>.`
break
default: default:
throw new Error(`The ${emailType} email type is not defined.`) throw new Error(`The ${emailType} email type is not defined.`)
} }
return { paragraph, hasLink, hasIntro, hasSignature } return {
paragraph,
hasLink,
hasIntro,
hasSignature,
upperContent,
subText,
lowerContent,
manuscriptText,
}
} }
module.exports = { module.exports = {
......
const config = require('config') const config = require('config')
const { get, isEmpty, chain } = require('lodash') const { get, isEmpty, chain, find } = require('lodash')
const Email = require('@pubsweet/component-email-templating') const Email = require('@pubsweet/component-email-templating')
const { const {
User, User,
...@@ -13,6 +13,7 @@ const { getEmailCopy } = require('./emailCopy') ...@@ -13,6 +13,7 @@ const { getEmailCopy } = require('./emailCopy')
const { name: journalName, staffEmail } = config.get('journal') const { name: journalName, staffEmail } = config.get('journal')
const unsubscribeSlug = config.get('unsubscribe.url') const unsubscribeSlug = config.get('unsubscribe.url')
const inviteReviewerPath = config.get('invite-reviewer.url')
class Notification { class Notification {
constructor({ constructor({
...@@ -718,50 +719,87 @@ class Notification { ...@@ -718,50 +719,87 @@ class Notification {
}) })
} }
async notifyReviewersWhenAuthorSubmitsMajorRevision(newFragmentId) { async notifyReviewersWhenAuthorSubmitsMajorRevision(newFragment, baseUrl) {
const { fragmentHelper } = await this._getNotificationProperties() const { fragmentHelper } = await this._getNotificationProperties()
const { collection, UserModel } = this const { collection, UserModel } = this
const handlingEditor = get(collection, 'handlingEditor') const handlingEditor = get(collection, 'handlingEditor')
const parsedFragment = await fragmentHelper.getFragmentData({ const { title, abstract } = await fragmentHelper.getFragmentData({
handlingEditor, handlingEditor,
}) })
const {
activeAuthors: authors,
submittingAuthor,
} = await fragmentHelper.getAuthorData({
UserModel,
})
const reviewers = await fragmentHelper.getReviewers({ const reviewers = await fragmentHelper.getReviewers({
UserModel, UserModel,
type: 'submitted', type: 'submitted',
}) })
const { paragraph, ...bodyProps } = getEmailCopy({ const authorsList = authors
emailType: 'submitted-reviewers-after-revision', .map(author => `${author.firstName} ${author.lastName}`)
titleText: `the manuscript titled "${parsedFragment.title}"`, .join(', ')
expectedDate: services.getExpectedDate({ daysExpected: 14 }), const authorName = `${submittingAuthor.firstName} ${
}) submittingAuthor.lastName
}`
const detailsPath = `/projects/${collection.id}/versions/${
newFragment.id
}/details`
newFragment.invitations.forEach(invitation => {
const reviewer = find(reviewers, ['id', invitation.userId])
const declineLink = services.createUrl(baseUrl, inviteReviewerPath, {
invitationId: invitation.id,
agree: false,
fragmentId: newFragment.id,
collectionId: collection.id,
invitationToken: reviewer.accessTokens.invitation,
})
const agreeLink = services.createUrl(baseUrl, detailsPath, {
invitationId: invitation.id,
agree: true,
})
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'reviewer-invitation',
titleText: `the manuscript titled <strong>"${title}"</strong> by <strong>${authorName}</strong> et al.`,
expectedDate: services.getExpectedDate({ daysExpected: 14 }),
})
reviewers.forEach(reviewer => {
const email = new Email({ const email = new Email({
type: 'user', type: 'user',
templateType: 'invitation',
fromEmail: `${handlingEditor.name} <${staffEmail}>`, fromEmail: `${handlingEditor.name} <${staffEmail}>`,
toUser: { toUser: {
email: reviewer.email, email: reviewer.email,
name: `${reviewer.lastName}`, name: `${reviewer.lastName}`,
}, },
content: { content: {
subject: `${ subject: `${collection.customId}: Review invitation: New Version`,
collection.customId
}: A manuscript you reviewed has been revised`,
paragraph,
signatureName: handlingEditor.name,
signatureJournal: journalName,
ctaLink: services.createUrl( ctaLink: services.createUrl(
this.baseUrl, this.baseUrl,
`/projects/${collection.id}/versions/${newFragmentId}/details`, `/projects/${collection.id}/versions/${newFragment.id}/details`,
), ),
ctaText: 'MANUSCRIPT DETAILS', ctaText: 'MANUSCRIPT DETAILS',
title,
paragraph,
authorsList,
signatureName: handlingEditor.name,
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, { unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: reviewer.id, id: reviewer.id,
token: reviewer.accessTokens.unsubscribe, token: reviewer.accessTokens.unsubscribe,
}), }),
signatureJournal: journalName,
agreeLink,
declineLink,
abstract,
}, },
bodyProps, bodyProps,
}) })
......
...@@ -60,9 +60,12 @@ module.exports = models => async (req, res) => { ...@@ -60,9 +60,12 @@ module.exports = models => async (req, res) => {
baseUrl: services.getBaseUrl(req), baseUrl: services.getBaseUrl(req),
}) })
const baseUrl = services.getBaseUrl(req)
try { try {
const newFragment = await strategies[role].execute({ const newFragment = await strategies[role].execute({
models, models,
baseUrl,
userHelper, userHelper,
notification, notification,
fragmentHelper, fragmentHelper,
......
module.exports = { module.exports = {
execute: async ({ execute: async ({
models, models,
baseUrl,
userHelper, userHelper,
TeamHelper, TeamHelper,
notification, notification,
...@@ -30,6 +31,14 @@ module.exports = { ...@@ -30,6 +31,14 @@ module.exports = {
members: reviewerIds, members: reviewerIds,
objectType: 'fragment', objectType: 'fragment',
}) })
newFragment.invitations = newFragment.invitations.map(invitation => ({
...invitation,
hasAnswer: false,
invitedOn: Date.now(),
isAccepted: false,
respondedOn: null,
}))
await newFragment.save()
} else { } else {
delete newFragment.invitations delete newFragment.invitations
await newFragment.save() await newFragment.save()
...@@ -66,7 +75,8 @@ module.exports = { ...@@ -66,7 +75,8 @@ module.exports = {
if (heRequestToRevision.recommendation === 'major') { if (heRequestToRevision.recommendation === 'major') {
await notification.notifyReviewersWhenAuthorSubmitsMajorRevision( await notification.notifyReviewersWhenAuthorSubmitsMajorRevision(
newFragment.id, newFragment,
baseUrl,
) )
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment