diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js index 84583485feff68c50c532e4a5f4a396147177df2..861f9ba93f6db900b543b559d822bbb95d342d7e 100644 --- a/packages/component-fixture-manager/src/fixtures/collections.js +++ b/packages/component-fixture-manager/src/fixtures/collections.js @@ -45,6 +45,7 @@ const collections = { token: chance.guid(), }, status: 'pendingApproval', + customId: chance.natural({ min: 999999, max: 9999999 }), }, } diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js index d1084b46b9d171abfcdf96df84e30f9783f6b333..4efbe9b38ed5e07754ecb38fe86f277cb73744d5 100644 --- a/packages/component-fixture-manager/src/fixtures/fragments.js +++ b/packages/component-fixture-manager/src/fixtures/fragments.js @@ -48,7 +48,7 @@ const fragments = { comments: [ { content: chance.paragraph(), - public: chance.bool(), + public: true, files: [ { id: chance.guid(), diff --git a/packages/component-helper-service/src/services/Collection.js b/packages/component-helper-service/src/services/Collection.js index 36b0e91b8a757548ead383879129e6413dd752f7..6cbaf601392a9a5e5ab76d4dc694a8c0bb0e3b01 100644 --- a/packages/component-helper-service/src/services/Collection.js +++ b/packages/component-helper-service/src/services/Collection.js @@ -99,7 +99,7 @@ class Collection { } getHELastName() { - const names = this.handlingEditor.name.split(' ') + const names = this.collection.handlingEditor.name.split(' ') return names[names.length - 1] } } diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js index f21a00aaa0788fdbc3c49827d2d1a1a61c20b332..85ca9f7a49a6057363cf5933c0d046dfddfe93a6 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js @@ -17,8 +17,8 @@ const getEmailCopy = ({ let hasSignature = true switch (emailType) { case 'author-request-to-revision': - paragraph = `After reviewing ${titleText}, I have requested further revisions to the manuscript. <br/> - ${comments}<br/> + paragraph = `After reviewing ${titleText}, I have requested further revisions to the manuscript. <br/><br/> + ${comments}<br/><br/> For more information about the requested changes and to submit your revised manuscript, please visit the manuscript details page.` break case 'author-manuscript-rejected': @@ -47,9 +47,9 @@ const getEmailCopy = ({ Thank you for handling this manuscript on behalf of ${journalName}.` break case 'he-manuscript-return-with-comments': - hasLink = false - paragraph = `Thank you for your recommendation for ${titleText} based on the reviews you received.<br/><br/> - ${comments}<br/><br/>` + paragraph = `${targetUserName} has responded with comments regarding your editorial recommendation on ${titleText}.<br/><br/> + ${comments}<br/><br/> + Please review these comments and take action on the manuscript details page.` break case 'accepted-reviewers-after-recommendation': hasLink = false @@ -64,9 +64,9 @@ const getEmailCopy = ({ Thank you for your interest and I hope you will consider reviewing for ${journalName} again.` break case 'submitted-reviewers-after-publish': - hasLink = false - paragraph = `Thank you for your review of ${titleText}. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article will now be published.<br/><br/> - If you have any queries about this decision, then please email them to Hindawi as soon as possible.` + paragraph = `Thank you for your review of ${titleText} for ${journalName}. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article will now be published.<br/><br/> + No further action is required at this time. To see more details about this decision please view the manuscript details page.<br/><br/> + If you have any questions about this decision, then please email them to ${staffEmail} as soon as possible. Thank you reviewing for ${journalName}.` break case 'submitted-reviewers-after-reject': paragraph = `Thank you for your review of ${titleText} for ${journalName}. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article has now been rejected.<br/><br/> @@ -98,10 +98,14 @@ const getEmailCopy = ({ No action is required at this time. To see the requested changes, please visit the manuscript details page.` break case 'eqa-manuscript-request-for-approval': + hasIntro = false + hasSignature = false paragraph = `Manuscript ID ${customId} has passed peer-review and is now ready for EQA. Please click on the link below to either approve or return the manuscript to the Editor in Chief:` break case 'eqa-manuscript-published': hasLink = false + hasIntro = false + hasSignature = false paragraph = `${titleText} has been accepted for publication by ${eicName}. <br/><br/> Please approve QA screening in MTS system, so that manuscript can be published in Hindawi on hindawi.com` break diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js index 5c85e7675d2a77c8d9ae7113d32859e1b7cf0427..813b50f59c642813a0abcb651853f5d0c0afd426 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js @@ -5,6 +5,7 @@ const { services } = require('pubsweet-component-helper-service') const { getEmailCopy } = require('./emailCopy') const unsubscribeSlug = config.get('unsubscribe.url') +const journalName = config.get('journal.name') module.exports = { sendReviewersEmail: async ({ email, baseUrl, reviewers }) => { @@ -21,7 +22,12 @@ module.exports = { }, ) const { html, text } = email.getBody({ - body: { paragraph: reviewer.paragraph }, + body: { + paragraph: reviewer.paragraph, + hasLink: reviewer.hasLink, + hasIntro: reviewer.hasIntro, + hasSignature: reviewer.hasSignature, + }, }) email.sendEmail({ html, text }) }) @@ -75,16 +81,23 @@ module.exports = { })) const reviewers = [...acceptedReviewers, ...pendingReviewers] + return reviewers }, updateEmailContentForReviewers: ({ email, - subject, customId, signatureName, + recommendation, }) => { + const subject = + recommendation === 'publish' + ? 'A manuscript you reviewed has been accepted' + : 'A manuscript you reviewed has been rejected' + email.content.subject = `${customId}: ${subject}` email.content.signatureName = signatureName + email.content.signatureJournal = journalName return email }, sendHandlingEditorEmail: ({ @@ -111,12 +124,23 @@ module.exports = { customId, heLastName, handlingEditor, + recommendation, recommendationType, }) => { if (recommendationType === 'review') { email.content.subject = `${customId}: A review has been submitted` } else { - email.content.subject = `${customId}: Editorial decision confirmed` + switch (recommendation) { + case 'return-to-handling-editor': + email.content.subject = `${customId}: Editorial decision returned with comments` + break + case 'publish': + case 'reject': + email.content.subject = `${customId}: Editorial decision confirmed` + break + default: + throw new Error(`Undefined recommendation: ${recommendation}`) + } } email.toUser = { @@ -221,7 +245,12 @@ module.exports = { name: `${eic.firstName} ${eic.lastName}`, } const { html, text } = email.getBody({ - body: { paragraph: eic.paragraph }, + body: { + paragraph: eic.paragraph, + hasLink: eic.hasLink, + hasIntro: eic.hasIntro, + hasSignature: eic.hasSignature, + }, }) email.sendEmail({ html, text }) }) @@ -242,6 +271,9 @@ module.exports = { const { html, text } = email.getBody({ body: { paragraph: author.paragraph, + hasLink: author.hasLink, + hasIntro: author.hasIntro, + hasSignature: author.hasSignature, }, }) email.sendEmail({ html, text }) @@ -274,12 +306,17 @@ module.exports = { updateEmailContentForSA: ({ email, customId, signatureName }) => { email.content.subject = `${customId}: Revision requested` email.content.signatureName = signatureName + email.content.signatureJournal = journalName + + return email }, getHEComments: ({ heRecommendation }) => { const heComments = get(heRecommendation, 'comments', []) + if (heComments.length === 0) return const publicComment = heComments.find(comm => comm.public) + const content = get(publicComment, 'content') if (!content) { throw new Error('a public comment cannot be without content') @@ -315,6 +352,9 @@ module.exports = { const { html, text } = email.getBody({ body: { paragraph: author.paragraph, + hasLink: author.hasLink, + hasIntro: author.hasIntro, + hasSignature: author.hasSignature, }, }) email.sendEmail({ html, text }) @@ -330,6 +370,7 @@ module.exports = { default: throw new Error(`Undefined recommendation: ${recommendation}`) } + email.content.signatureJournal = journalName return email }, diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js index bfcca73090c57a57d07d720dc1c67fd5e9940b8e..08b09ddd4b90db69ac7d5d903f0083841cee1b86 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js @@ -1,5 +1,5 @@ const config = require('config') -const { chain, get, isEmpty } = require('lodash') +const { get, isEmpty } = require('lodash') const { User, @@ -13,9 +13,7 @@ const { getEmailCopy } = require('./emailCopy') const helpers = require('./helpers') const editorialAssistantEmail = config.get('mailer.editorialAssistant') -const unsubscribeSlug = config.get('unsubscribe.url') const journalName = config.get('journal.name') - module.exports = { async sendNotifications({ hasEQA, @@ -75,129 +73,133 @@ module.exports = { const { customId } = collection const collHelper = new Collection({ collection }) + // send HE emails when a review is submitted + // or when the EiC makes a recommendation after peer review if ( (isEditorInChief || recommendationType === 'review') && - hasPeerReview(collection) + hasPeerReview(collection) && + (recommendation !== 'publish' || hasEQA) ) { - if (recommendation !== 'publish' || hasEQA) { - // the request came from either the Editor in Chief or a reviewer, so the HE needs to be notified - email = helpers.updateEmailContentForHE({ - email, - baseUrl, - eicName, - customId, - recommendationType, - heLastName: collHelper.getHELastName(), - handlingEditor: get(collection, 'handlingEditor', {}), - }) - const emailType = helpers.getEmailTypeByRecommendationForHE({ - recommendation, - recommendationType, - }) - const comments = helpers.getEiCCommentsForHE({ newRecommendation }) - helpers.sendHandlingEditorEmail({ - email, - comments, - emailType, - titleText, - targetUserName, - }) - } + email = helpers.updateEmailContentForHE({ + email, + baseUrl, + eicName, + customId, + recommendation, + recommendationType, + heLastName: collHelper.getHELastName(), + handlingEditor: get(collection, 'handlingEditor', {}), + }) + const emailType = helpers.getEmailTypeByRecommendationForHE({ + recommendation, + recommendationType, + }) + const comments = helpers.getEiCCommentsForHE({ newRecommendation }) + helpers.sendHandlingEditorEmail({ + email, + comments, + emailType, + titleText, + targetUserName, + }) } if ( - recommendationType !== 'review' && - recommendation !== 'return-to-handling-editor' + recommendationType === 'review' || + recommendation === 'return-to-handling-editor' ) { - if (isEditorInChief) { - if (recommendation !== 'publish' || hasEQA) { - // send all authors email - const emailType = helpers.getEmailTypeByRecommendationForAuthors({ - recommendation, - }) - const comments = helpers.getHEComments({ - heRecommendation: parsedFragment.heRecommendation, - }) - const authors = helpers.getAllAuthors({ - comments, - emailType, - title: parsedFragment.title, - fragmentAuthors: fragmentAuthors.activeAuthors, - }) - email = helpers.updateEmailContentForAllAuthors({ - email, - customId, - recommendation, - }) - helpers.sendAuthorsEmail({ email, authors, baseUrl }) - } - } + return + } - if (collection.status === 'revisionRequested') { - // send SA email - const authorNoteText = helpers.getPrivateNoteTextForAuthor({ - newRecommendation, - }) - const author = helpers.getSubmittingAuthor({ - authorNoteText, - journalName, - title: parsedFragment.title, - submittingAuthor: fragmentAuthors.submittingAuthor, - }) - email = helpers.updateEmailContentForSA({ + // when publishing, only send emails to authors if the manuscript has passed EQA + if (isEditorInChief && (recommendation !== 'publish' || hasEQA)) { + // send all authors email + const emailType = helpers.getEmailTypeByRecommendationForAuthors({ + recommendation, + }) + const comments = helpers.getHEComments({ + heRecommendation: parsedFragment.heRecommendation, + }) + const authors = helpers.getAllAuthors({ + comments, + emailType, + title: parsedFragment.title, + fragmentAuthors: fragmentAuthors.activeAuthors, + }) + email = helpers.updateEmailContentForAllAuthors({ + email, + customId, + recommendation, + }) + helpers.sendAuthorsEmail({ email, authors, baseUrl }) + } + + // send email to SA when the HE requests a revision + if (collection.status === 'revisionRequested') { + const authorNoteText = helpers.getPrivateNoteTextForAuthor({ + newRecommendation, + }) + const author = helpers.getSubmittingAuthor({ + authorNoteText, + journalName, + title: parsedFragment.title, + submittingAuthor: fragmentAuthors.submittingAuthor, + }) + email = helpers.updateEmailContentForSA({ + email, + customId, + signatureName: get(collection, 'handlingEditor.name', eicName), + }) + + helpers.sendSubmittingAuthorEmail({ email, author, baseUrl }) + } + + if (!hasPeerReview(collection)) { + return + } + + let reviewers = [] + if (isEditorInChief) { + if (recommendation !== 'publish' || hasEQA) { + email = helpers.updateEmailContentForReviewers({ email, customId, - signatureName: get(collection, 'handlingEditor.name', eicName), + recommendation, + signatureName: eicName, + }) + reviewers = await helpers.getSubmittedReviewers({ + UserModel, + titleText, + fragmentHelper, + recommendation, }) - helpers.sendSubmittingAuthorEmail({ email, author, baseUrl }) } + } else { + email = helpers.updateEmailContentForReviewers({ + email, + customId, + subject: `Review no longer required`, + signatureName: get(collection, 'handlingEditor.name', eicName), + }) - if (hasPeerReview(collection)) { - let reviewers - if (isEditorInChief) { - if (recommendation !== 'publish' || hasEQA) { - email = helpers.updateEmailContentForReviewers({ - email, - customId, - signatureName: eicName, - subject: `A manuscript you reviewed has been rejected`, - }) - reviewers = helpers.getSubmittedReviewers({ - UserModel, - titleText, - fragmentHelper, - recommendation, - }) - } - } else { - email = helpers.updateEmailContentForReviewers({ - email, - customId, - subject: `Review no longer required`, - signatureName: get(collection, 'handlingEditor.name', eicName), - }) - - reviewers = helpers.getNoResponseReviewers({ - UserModel, - titleText, - fragmentHelper, - }) - } - helpers.sendReviewersEmail({ email, baseUrl, reviewers }) - - if (!isEditorInChief) { - helpers.sendEiCsEmail({ - email, - baseUrl, - customId, - titleText, - userHelper, - recommendation: newRecommendation, - targetUserName: collHelper.getHELastName(), - }) - } - } + reviewers = await helpers.getNoResponseReviewers({ + UserModel, + titleText, + fragmentHelper, + }) + + helpers.sendEiCsEmail({ + email, + baseUrl, + customId, + titleText, + userHelper, + recommendation: newRecommendation, + targetUserName: collHelper.getHELastName(), + }) } + + helpers.sendReviewersEmail({ email, baseUrl, reviewers }) }, }