diff --git a/packages/component-email/src/routes/emails/emailCopy.js b/packages/component-email/src/routes/emails/emailCopy.js index 18b8ee7ccf2fde216335b7589dc65523422cb1b3..d14178be9815e574a83f2e16aefff8495e59affd 100644 --- a/packages/component-email/src/routes/emails/emailCopy.js +++ b/packages/component-email/src/routes/emails/emailCopy.js @@ -1,17 +1,29 @@ +const config = require('config') + +const journalName = config.get('journal.name') const getEmailCopy = ({ emailType, role }) => { let paragraph + const hasIntro = true + const hasSignature = true switch (emailType) { case 'user-signup': - paragraph = `Welcome to Hindawi. Please confirm your account by clicking on the link below.` + paragraph = `Thank you for creating an account on Hindawi’s review system. + To submit a manuscript and access your dashboard, please confirm your account by clicking on the link below.` break case 'user-added-by-admin': - paragraph = `You have been invited to join Hindawi as a ${role}. Please confirm your account and set your account details by clicking on the link below.` + paragraph = `You have been invited to join Hindawi as a ${role}. + Please confirm your account and set your account details by clicking on the link below.` + break + case 'he-added-by-admin': + paragraph = `You have been invited to become an Academic Editor for the journal ${journalName}. + To begin performing your editorial duties, you will need to create an account on Hindawi’s review system.<br/><br/> + Please confirm your account details by clicking on the link below.` break default: throw new Error(`The ${emailType} email type is not defined.`) } - return { paragraph, hasLink: true } + return { paragraph, hasLink: true, hasIntro, hasSignature } } module.exports = { diff --git a/packages/component-email/src/routes/emails/helpers.js b/packages/component-email/src/routes/emails/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..fe28ae508c0199466df06fa19e94dfa88b111aa7 --- /dev/null +++ b/packages/component-email/src/routes/emails/helpers.js @@ -0,0 +1,45 @@ +const config = require('config') +const { services } = require('pubsweet-component-helper-service') + +const { getEmailCopy } = require('./emailCopy') + +const confirmSignUp = config.get('confirm-signup.url') +const { name: journalName, staffEmail } = config.get('journal') + +module.exports = { + sendNewUserEmail: ({ email, role }) => { + email.content.subject = 'Confirm your account' + + let emailType + if (role === 'Handling Editor') { + emailType = 'he-added-by-admin' + email.fromEmail = `${journalName} <${staffEmail}>` + } else { + emailType = 'user-added-by-admin' + } + + const { html, text } = email.getBody({ + body: getEmailCopy({ + role, + emailType, + }), + }) + + email.sendEmail({ html, text }) + }, + sendSignupEmail: ({ email, baseUrl, user }) => { + email.content.subject = 'Confirm your email address' + email.content.ctaLink = services.createUrl(baseUrl, confirmSignUp, { + userId: user.id, + confirmationToken: user.confirmationToken, + }) + + const { html, text } = email.getBody({ + body: getEmailCopy({ + emailType: 'user-signup', + }), + }) + + email.sendEmail({ html, text }) + }, +} diff --git a/packages/component-email/src/routes/emails/notifications.js b/packages/component-email/src/routes/emails/notifications.js index 1a89afff1ae771239a7fd6b6dba64a493b96f414..28791d3bae1ac9a59af53b0c7a6620aba7184c0e 100644 --- a/packages/component-email/src/routes/emails/notifications.js +++ b/packages/component-email/src/routes/emails/notifications.js @@ -2,22 +2,20 @@ const config = require('config') const unsubscribeSlug = config.get('unsubscribe.url') const resetPath = config.get('invite-reset-password.url') -const confirmSignUp = config.get('confirm-signup.url') +const staffEmail = config.get('journal.staffEmail') -const { Email, User, services } = require('pubsweet-component-helper-service') +const { Email, services } = require('pubsweet-component-helper-service') -const { getEmailCopy } = require('./emailCopy') +const { sendNewUserEmail, sendSignupEmail } = require('./helpers') module.exports = { async sendNotifications({ user, baseUrl, role, UserModel }) { - const userHelper = new User({ UserModel }) - const eicName = await userHelper.getEiCName() - const email = new Email({ type: 'user', + fromEmail: `Hindawi <${staffEmail}>`, toUser: { email: user.email, - name: `${user.firstName} ${user.lastName}`, + name: `${user.lastName}`, }, content: { ctaLink: services.createUrl(baseUrl, resetPath, { @@ -29,7 +27,7 @@ module.exports = { title: user.title, }), ctaText: 'CONFIRM ACCOUNT', - signatureName: eicName, + signatureName: 'Hindawi', unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { id: user.id, }), @@ -43,33 +41,3 @@ module.exports = { } }, } - -const sendNewUserEmail = ({ email, role }) => { - email.content.subject = 'Confirm Your Account' - - const { html, text } = email.getBody({ - body: getEmailCopy({ - emailType: 'user-added-by-admin', - role, - }), - }) - - email.sendEmail({ html, text }) -} - -const sendSignupEmail = ({ email, baseUrl, user }) => { - email.content.subject = 'Confirm Your Email Address' - email.content.ctaLink = services.createUrl(baseUrl, confirmSignUp, { - userId: user.id, - confirmationToken: user.confirmationToken, - }) - email.content.ctaText = 'CONFIRM' - - const { html, text } = email.getBody({ - body: getEmailCopy({ - emailType: 'user-signup', - }), - }) - - email.sendEmail({ html, text }) -} diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js index e9d29ef190c37c9b4a43c9536c737f2c17167505..61d7cf2acfc1c01ac4a0ecdf77577f71f667ba1f 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 }), }, collection1: { id: standardCollID, 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 5007bba300d33ea17fe4190d2412955c9719c2c0..40affb63b76e5970b505ea5300633084b931d141 100644 --- a/packages/component-helper-service/src/services/Collection.js +++ b/packages/component-helper-service/src/services/Collection.js @@ -97,6 +97,11 @@ class Collection { }) } } + + getHELastName() { + const [firstName, lastName] = this.collection.handlingEditor.name.split(' ') + return lastName || firstName + } } module.exports = Collection diff --git a/packages/component-helper-service/src/services/email/Email.js b/packages/component-helper-service/src/services/email/Email.js index 53436b212dd89df765028f90fc779d4f2e0045bf..0271625e2cb99f8db804d43000b6b54a89e78892 100644 --- a/packages/component-helper-service/src/services/email/Email.js +++ b/packages/component-helper-service/src/services/email/Email.js @@ -1,11 +1,14 @@ const config = require('config') + const helpers = require('./helpers') const SendEmail = require('@pubsweet/component-send-email') const logger = require('@pubsweet/logger') +const mainFromEmail = config.get('journal.staffEmail') class Email { constructor({ type = 'system', + fromEmail = mainFromEmail, toUser = { id: '', email: '', @@ -17,11 +20,13 @@ class Email { ctaText: '', signatureName: '', unsubscribeLink: '', + signatureJournal: '', }, }) { this.type = type this.toUser = toUser this.content = content + this.fromEmail = fromEmail } set _toUser(newToUser) { @@ -65,19 +70,20 @@ class Email { } sendEmail({ text, html }) { - const fromEmail = config.get('mailer.from') + const { fromEmail: from } = this + const { email: to } = this.toUser + const { subject } = this.content + const mailData = { - from: fromEmail, - to: this.toUser.email, - subject: this.content.subject, + to, text, html, + from, + subject, } logger.info( - `EMAIL: Sent email from ${fromEmail} to ${ - this.toUser.email - } with subject '${this.content.subject}'`, + `EMAIL: Sent email from ${from} to ${to} with subject '${subject}'`, ) SendEmail.send(mailData) } diff --git a/packages/component-helper-service/src/services/email/helpers.js b/packages/component-helper-service/src/services/email/helpers.js index df1cfc28014b9f860662a3c69a00f2cf04f5404f..f704b8d6656364b5069e9f99481dafc5045927ea 100644 --- a/packages/component-helper-service/src/services/email/helpers.js +++ b/packages/component-helper-service/src/services/email/helpers.js @@ -3,8 +3,9 @@ const handlebars = require('handlebars') const getNotificationBody = ({ replacements }) => { handlePartial('header', replacements) + if (replacements.hasIntro) handlePartial('intro', replacements) handlePartial('footer', replacements) - handlePartial('signature', replacements) + if (replacements.hasSignature) handlePartial('signature', replacements) if (replacements.hasLink) handlePartial('button', replacements) handlePartial('body', replacements) diff --git a/packages/component-helper-service/src/services/email/templates/partials/body.hbs b/packages/component-helper-service/src/services/email/templates/partials/body.hbs index 99513b980cc51a71d84c3d0b1d403f5a9e303679..59e1230635ab84764ca255052c0952cebf6df56e 100644 --- a/packages/component-helper-service/src/services/email/templates/partials/body.hbs +++ b/packages/component-helper-service/src/services/email/templates/partials/body.hbs @@ -2,7 +2,9 @@ <tr> <td style="padding:30px 23px 0px 23px;background-color:#ffffff;" height="100%" valign="top" bgcolor="#ffffff"> <div> - <p data-pm-slice="1 1 []">Dear Dr. {{toUserName}},</p> + {{#if hasIntro}} + {{> intro}} + {{/if}} <p> </p> <p> {{{paragraph}}} @@ -13,7 +15,9 @@ {{> button }} {{/if}} </p> - {{> signature}} + {{#if hasSignature }} + {{> signature}} + {{/if}} <p> </p> </div> </td> diff --git a/packages/component-helper-service/src/services/email/templates/partials/footer.hbs b/packages/component-helper-service/src/services/email/templates/partials/footer.hbs index 355088275373e0378176b00ca6a9007cc2d54a62..f461fdbaac1bb855f475c3590062cb7b269086b2 100644 --- a/packages/component-helper-service/src/services/email/templates/partials/footer.hbs +++ b/packages/component-helper-service/src/services/email/templates/partials/footer.hbs @@ -1,12 +1,12 @@ <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 class="Unsubscribe--senderName" style="font-family:Arial, Helvetica, sans-serif;font-size:12px;line-height:20px">Hindawi Limited</p> <p style="font-family:Arial, Helvetica, sans-serif;font-size:12px;line-height:20px"> - <span class="Unsubscribe--senderAddress">315 Madison Ave, Third Floor, Suite 3070</span>, - <span class="Unsubscribe--senderCity">NEW YORK</span>, - <span class="Unsubscribe--senderState">NY</span> - <span class="Unsubscribe--senderZip">10017</span> + <span class="Unsubscribe--senderAddress">3rd Floor, Adam House, 1 Fitzroy Square</span>, + <span class="Unsubscribe--senderCity">LONDON</span>, + <span class="Unsubscribe--senderState">United Kingdom</span> + <span class="Unsubscribe--senderZip">W1T 5HF</span> </p> </div> <p style="font-family:Arial, Helvetica, sans-serif;font-size:12px;line-height:20px"> diff --git a/packages/component-helper-service/src/services/email/templates/partials/intro.hbs b/packages/component-helper-service/src/services/email/templates/partials/intro.hbs new file mode 100644 index 0000000000000000000000000000000000000000..0ce780b6d9e09ac62aecd9ec48ef287f92184e30 --- /dev/null +++ b/packages/component-helper-service/src/services/email/templates/partials/intro.hbs @@ -0,0 +1 @@ +<p data-pm-slice="1 1 []">Dear Dr. {{toUserName}},</p> \ No newline at end of file diff --git a/packages/component-helper-service/src/services/email/templates/partials/signature.hbs b/packages/component-helper-service/src/services/email/templates/partials/signature.hbs index 615770e162d7915b38e49c485404aa7682f75339..eec0831b8cdc1d3835c9852b1d79c04a8dcce891 100644 --- a/packages/component-helper-service/src/services/email/templates/partials/signature.hbs +++ b/packages/component-helper-service/src/services/email/templates/partials/signature.hbs @@ -1,4 +1,4 @@ -<p>With many thanks and best regards, +<p>Kind regards, <br /> {{ signatureName }} - <br /> Hindawi + <br /> {{ signatureJournal }} </p> \ No newline at end of file diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js index 58d6e89b309ebd7162cc1d484d10534e846d3edf..2694ba4c5b0e8b77fcc80fc5ad2618950aca8bb8 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js +++ b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js @@ -1,9 +1,18 @@ +const config = require('config') + +const staffEmail = config.get('journal.staffEmail') + const getEmailCopy = ({ emailType, titleText, targetUserName, comments }) => { let paragraph let hasLink = true + let hasIntro = true + let hasSignature = true switch (emailType) { case 'he-assigned': - paragraph = `You have been assigned as a Handling Editor to ${titleText}. Please click on the link below to access the manuscript and make a decision.` + hasIntro = false + hasSignature = false + paragraph = `${targetUserName} has invited you to serve as the Handling Editor for ${titleText}.<br/><br/> + To review this manuscript and respond to the invitation, please visit the manuscript details page.` break case 'he-accepted': paragraph = `Dr. ${targetUserName} agreed to be a Handling Editor on ${titleText}. Please click on the link below to access the manuscript.` @@ -14,14 +23,17 @@ const getEmailCopy = ({ emailType, titleText, targetUserName, comments }) => { hasLink = false break case 'he-revoked': - paragraph = `Your Handling Editor assignment to ${titleText} has been revoked.` + hasIntro = false hasLink = false + hasSignature = false + paragraph = `${targetUserName} has removed you from the role of Handling Editor for ${titleText}.<br/><br/> + The manuscript will no longer appear in your dashboard. Please contact ${staffEmail} if you have any questions about this change.` break default: throw new Error(`The ${emailType} email type is not defined.`) } - return { paragraph, hasLink } + return { paragraph, hasLink, hasIntro, hasSignature } } module.exports = { diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js b/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..eb67aa42311e27a2ef50c3dae4567b909d35d1bb --- /dev/null +++ b/packages/component-invite/src/routes/collectionsInvitations/emails/helpers.js @@ -0,0 +1,83 @@ +const config = require('config') +const { services } = require('pubsweet-component-helper-service') + +const { getEmailCopy } = require('./emailCopy') + +const unsubscribeSlug = config.get('unsubscribe.url') +const { name: journalName, staffEmail } = config.get('journal') + +module.exports = { + sendInvitedHEEmail: ({ + email, + eicName, + baseUrl, + customId, + titleText, + isCanceled, + handlingEditor, + }) => { + email.toUser = { + email: handlingEditor.email, + } + + email.content.subject = isCanceled + ? `${customId}: Editor invitation cancelled` + : `${customId}: Invitation to edit a manuscript` + + email.fromEmail = `${journalName} <${staffEmail}>` + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: handlingEditor.id, + }, + ) + + const { html, text } = email.getBody({ + body: getEmailCopy({ + titleText, + targetUserName: eicName, + emailType: isCanceled ? 'he-revoked' : 'he-assigned', + }), + }) + + email.sendEmail({ html, text }) + }, + sendEiCEmail: async ({ + eic, + email, + baseUrl, + comments, + titleText, + isAccepted, + targetUserName, + subjectBaseText, + }) => { + email.content.subject = `${subjectBaseText} Assignment Response` + const emailType = isAccepted ? 'he-accepted' : 'he-declined' + + email.toUser = { + email: eic.email, + name: `${eic.firstName} ${eic.lastName}`, + } + + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: eic.id, + }, + ) + + const { html, text } = email.getBody({ + body: getEmailCopy({ + comments, + emailType, + titleText, + targetUserName, + }), + }) + + email.sendEmail({ html, text }) + }, +} diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js index 90df1a7ce364a2445dd79238dd9f4837392be5c8..c018cdefe26fb6a605118d81b09dc6880ba0559c 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js +++ b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js @@ -1,8 +1,5 @@ -const config = require('config') const { last } = require('lodash') -const unsubscribeSlug = config.get('unsubscribe.url') - const { User, Email, @@ -10,7 +7,7 @@ const { Fragment, } = require('pubsweet-component-helper-service') -const { getEmailCopy } = require('./emailCopy') +const { sendInvitedHEEmail, sendEiCEmail } = require('./helpers') module.exports = { async sendNotifications({ @@ -39,7 +36,8 @@ module.exports = { const eics = await userHelper.getEditorsInChief() const eic = eics[0] const eicName = `${eic.firstName} ${eic.lastName}` - const subjectBaseText = `${collection.customId}: Manuscript ` + const { customId } = collection + const subjectBaseText = `${customId}: Manuscript` const email = new Email({ type: 'user', @@ -58,9 +56,9 @@ module.exports = { email, baseUrl, eicName, - isCanceled, + customId, titleText, - subjectBaseText, + isCanceled, handlingEditor: invitedHE, }) } else { @@ -77,69 +75,3 @@ module.exports = { } }, } - -const sendInvitedHEEmail = ({ - email, - eicName, - baseUrl, - titleText, - isCanceled, - handlingEditor, - subjectBaseText, -}) => { - email.toUser = { - email: handlingEditor.email, - name: `${handlingEditor.firstName} ${handlingEditor.lastName}`, - } - - email.content.subject = isCanceled - ? `${subjectBaseText} Assignment Revoked` - : `${subjectBaseText} Assignment` - email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { - id: handlingEditor.id, - }) - email.content.signatureName = eicName - - const { html, text } = email.getBody({ - body: getEmailCopy({ - emailType: isCanceled ? 'he-revoked' : 'he-assigned', - titleText, - }), - }) - - email.sendEmail({ html, text }) -} - -const sendEiCEmail = async ({ - eic, - email, - baseUrl, - comments, - titleText, - isAccepted, - targetUserName, - subjectBaseText, -}) => { - email.content.subject = `${subjectBaseText} Assignment Response` - const emailType = isAccepted ? 'he-accepted' : 'he-declined' - - email.toUser = { - email: eic.email, - name: `${eic.firstName} ${eic.lastName}`, - } - - email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { - id: eic.id, - }) - - const { html, text } = email.getBody({ - body: getEmailCopy({ - comments, - emailType, - titleText, - targetUserName, - }), - }) - - email.sendEmail({ html, text }) -} diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js index 181da00983c2aaf6ffd392dfbab82910db0f5a93..940afbfad19817ac030736dd9c6c21b1494db574 100644 --- a/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js +++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/emailCopy.js @@ -1,5 +1,7 @@ const config = require('config') +const journalName = config.get('journal.name') + const getEmailCopy = ({ emailType, titleText, @@ -11,50 +13,48 @@ const getEmailCopy = ({ let resend = false switch (emailType) { case 'reviewer-invitation': - upperContent = `${titleText}, has been submitted for possible publication in Hindawi. As the Academic Editor handling the manuscript, I would be delighted if you would agree to review it and let me know whether you feel it is suitable for publication.` - manuscriptText = - "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." + upperContent = `${titleText}, has been submitted to ${journalName} for consideration. As the Academic Editor handling the manuscript, I would be delighted if you would agree to review it and let me know whether you feel it is suitable for publication.` + manuscriptText = `If you are able to review the manuscript, I would be grateful if you could submit your + report by ${expectedDate}.<br/> + 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 href="https://www.hindawi.com/ethics/#coi">https://www.hindawi.com/ethics/#coi</a>.<br/><br/> - If you are able to review the manuscript, I would be grateful if you could submit your - report by ${expectedDate}.` + 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 href="https://www.hindawi.com/ethics/#coi">https://www.hindawi.com/ethics/#coi</a>.<br/><br/>` break case 'reviewer-resend-invitation': resend = true - upperContent = `On ${expectedDate} I sent you a request to review ${titleText}, submitted for possible publication in Hindawi.<br/><br/> - I would be grateful if you would agree to review it and let me know whether you feel - it is suitable for publication. If you are unable to review this manuscript then - please decline to review. More details are available by clicking the link.` - lowerContent = `I would like to thank you in advance for your help with the evaluation of this manuscript, since it would not be possible for us to run the journal without the help of our reviewers.<br/><br/> + upperContent = `On ${expectedDate} I invited you to review ${titleText}, submitted to ${journalName} for consideration.<br/><br/> + I would be grateful if you would agree to review the manuscript and let me know whether you feel + it is suitable for publication. If you are unable to review this manuscript please decline to review. More details are available by clicking the link below.` + lowerContent = `Thank you in advance for taking the time to consider this invitation, as it would not be possible for us to run the journal without the help of our reviewers.<br/><br/> I am looking forward to hearing from you.` break case 'reviewer-accepted': paragraph = `We are pleased to inform you that Dr. ${targetUserName} has agreed to review ${titleText}.<br/><br/> - You should receive the report by Dr. ${targetUserName} before ${expectedDate}. If you have any queries, or would like to send a reminder if no report has been submitted, then please visit the manuscript details page.` + You should receive the report before ${expectedDate}.<br/><br/> + If the review is delayed and you would like to send a reminder to Dr. ${targetUserName}, please visit the manuscript details page.` break case 'reviewer-declined': paragraph = `We regret to inform you that Dr. ${targetUserName} has declined to review ${titleText}.<br/><br/> - Please visit the manuscript details page to see if you need to invite any additional reviewers in order to reach a decision on the manuscript` + Please visit the manuscript details to invite additional reviewers in order to reach a decision on the manuscript. ` break case 'reviewer-thank-you': paragraph = `Thank you for agreeing to review ${titleText}.<br/><br/> - You can view the full PDF file of the manuscript and post your review report using the following URL:` + You can view the full PDF file of the manuscript and post your review report using the following link.<br/> + You will be asked to log in before being able to complete your review.` break case 'reviewer-cancel-invitation': - paragraph = `You are no longer needed to review ${titleText}.<br/><br/> - If you have comments on this manuscript you believe the Editor should see, please email them to ${config.get( - 'mailer.from', - )} as soon as possible.<br/><br/> - Thank you for your time and I hope you will consider reviewing for Hindawi again.` + paragraph = `We recently invited you to review ${titleText} for ${journalName}.<br/> + This is to confirm that we no longer require your review.<br/><br/> + If you have comments on the manuscript you believe I should see, please email them to ${config.get( + 'journal.staffEmail', + )} as soon as possible.<br/><br/> + Thank you for your time and I hope you will consider reviewing for ${journalName} in the future.` hasLink = false break - case 'reviewer-new-account': - paragraph = `You have been invited to review ${titleText}. In order to respond to the invitation, you need to confirm your account.` - break default: throw new Error(`The ${emailType} email type is not defined.`) } @@ -66,6 +66,8 @@ const getEmailCopy = ({ upperContent, lowerContent, manuscriptText, + hasIntro: true, + hasSignature: true, } } diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js index b66445efe0a40c6470d9e04f3485710b5e8432ac..fdb2dd642133722baab938d04c2b47e6f48d43a1 100644 --- a/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js +++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/invitations.js @@ -35,9 +35,6 @@ module.exports = { }) const subjectBaseText = `${collection.customId}: Review` - const titleText = `The manuscript titled "${title}" by ${ - submittingAuthor.firstName - } ${submittingAuthor.lastName}` let queryParams = { invitationId: invitation.id, @@ -78,41 +75,50 @@ module.exports = { type: 'user', toUser: { email: invitedUser.email, - name: `${invitedUser.firstName} ${invitedUser.lastName}`, + name: `${invitedUser.lastName}`, }, content: { title, abstract, agreeLink, declineLink, - subject: `${subjectBaseText} Requested`, + authorsList: authorsList.join(', '), + subject: `${subjectBaseText} invitation`, detailsLink: services.createUrl(baseUrl, detailsPath), signatureName: get(collection, 'handlingEditor.name', 'Hindawi'), unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { id: invitedUser.id, }), - authorsList: authorsList.join(', '), }, }) sendInvitedUserEmail({ email, - titleText, + title, resend, timestamp, + authorName: `${submittingAuthor.firstName} ${submittingAuthor.lastName}`, }) }, } const sendInvitedUserEmail = async ({ email, - titleText, resend, + title, + authorName, timestamp, }) => { - const emailType = - resend === true ? 'reviewer-resend-invitation' : 'reviewer-invitation' - const daysExpected = resend === true ? 0 : 14 + let daysExpected = 14 + let emailType = 'reviewer-invitation' + let titleText = `A manuscript titled "${title}" by ${authorName} et al.` + + if (resend) { + emailType = 'reviewer-resend-invitation' + daysExpected = 0 + email.content.subject = `${email.content.subject} reminder` + titleText = `the manuscript titled "${title}" by ${authorName}` + } const { html, text } = email.getBody({ isReviewerInvitation: true, diff --git a/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js index 9eeb709b629ee52e0ab63624c4a25019b1dc1a95..c15717402311b42c516697898d97d2767ff44b5a 100644 --- a/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js +++ b/packages/component-invite/src/routes/fragmentsInvitations/emails/notifications.js @@ -2,6 +2,8 @@ const config = require('config') const { get } = require('lodash') const unsubscribeSlug = config.get('unsubscribe.url') +const fromEmail = config.get('journal.staffEmail') +const journalName = config.get('journal.name') const { User, @@ -20,7 +22,6 @@ module.exports = { UserModel, emailType, collection, - isNewUser = false, isCanceled = false, }) { const fragmentHelper = new Fragment({ fragment }) @@ -38,19 +39,18 @@ module.exports = { const handlingEditor = get(collection, 'handlingEditor') const userHelper = new User({ UserModel }) const eicName = await userHelper.getEiCName() - const subjectBaseText = isCanceled - ? `${collection.customId}: Reviewer ` - : `${collection.customId}: Manuscript ` const email = new Email({ + fromEmail, type: 'user', content: { + ctaText: 'MANUSCRIPT DETAILS', + signatureJournal: journalName, signatureName: handlingEditor.name, ctaLink: services.createUrl( baseUrl, `/projects/${collection.id}/versions/${fragment.id}/details`, ), - ctaText: 'MANUSCRIPT DETAILS', }, }) @@ -61,7 +61,7 @@ module.exports = { reviewer, titleText, isCanceled, - subjectBaseText, + customId: collection.customId, }) } @@ -72,8 +72,8 @@ module.exports = { titleText, emailType, handlingEditor, - subjectBaseText, - targetUserName: `${reviewer.firstName} ${reviewer.lastName}`, + customId: collection.customId, + targetUserName: `${reviewer.lastName}`, }) } }, @@ -83,22 +83,26 @@ const sendHandlingEditorEmail = ({ email, eicName, baseUrl, + customId, titleText, emailType, handlingEditor, targetUserName, - subjectBaseText, }) => { email.toUser = { email: handlingEditor.email, name: handlingEditor.name, } - email.content.subject = `${subjectBaseText} Reviews` + email.content.subject = + emailType === 'reviewer-accepted' + ? `${customId}: A reviewer has agreed` + : `${customId}: A reviewer has declined` email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { id: handlingEditor.id, }) email.content.signatureName = eicName + email.content.signatureJournal = '' const { html, text } = email.getBody({ body: getEmailCopy({ @@ -118,20 +122,21 @@ const sendReviewerEmail = async ({ email, baseUrl, reviewer, + customId, titleText, isCanceled, - subjectBaseText, }) => { email.content.subject = isCanceled - ? `${subjectBaseText} Unassigned` - : `${subjectBaseText} Review` + ? `${customId}: Review no longer required` + : `${customId}: Thank you for agreeing to review` + const emailType = isCanceled ? 'reviewer-cancel-invitation' : 'reviewer-thank-you' email.toUser = { email: reviewer.email, - name: `${reviewer.firstName} ${reviewer.lastName}`, + name: `${reviewer.lastName}`, } email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js index 2f438381c22a6fbb03c602df9b76ec946790d916..b48925f983d296cd88f78d43abd65a0cd633f845 100644 --- a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js +++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js @@ -1,39 +1,48 @@ +const config = require('config') + +const journalName = config.get('journal.name') + const getEmailCopy = ({ emailType, titleText, expectedDate, customId }) => { let paragraph const hasLink = true + const hasIntro = true + const hasSignature = true switch (emailType) { case 'he-new-version-submitted': - paragraph = `A new version of ${titleText} has been submitted. - Previous reviewers have been automatically invited to review the manuscript again. Please visit the manuscript details page to see the latest version and any other actions you may need to take.` + paragraph = `The authors of ${titleText} have submitted a revised version. <br/><br/> + To review this new submission and proceed with the review process, please visit the manuscript details page.` break case 'submitted-reviewers-after-revision': - paragraph = `A new version of ${titleText} has been submitted. As you have reviewed the previous version of this manuscript, I would be grateful if you can review this revised version and submit a review report by ${expectedDate}. You can download the PDF of the revised version and submit your new review from the following URL:` - break - case 'eic-manuscript-submitted': - paragraph = `A new manuscript has been submitted. You can view ${titleText} and take further actions by clicking on the following link:` + paragraph = `The authors have submitted a new version of ${titleText}, which you reviewed for ${journalName}.<br/><br/> + As you reviewed the previous version of this manuscript, I would be grateful if you could review this revision and submit a new report by ${expectedDate}. + To download the updated PDF and proceed with the review process, please visit the manuscript details page.<br/><br/> + Thank you again for reviewing for ${journalName}.` break + // case 'eic-manuscript-submitted': + // paragraph = `A new manuscript has been submitted. You can view ${titleText} and take further actions by clicking on the following link:` + // break case 'eqs-manuscript-submitted': paragraph = `Manuscript ID ${customId} has been submitted and a package has been sent. Please click on the link below to either approve or reject the manuscript:` break case 'coauthors-manuscript-submitted': - paragraph = `${titleText} has been received.<br/> - Please verify your details by clicking the link below.<br/> - Once confirmed, you will also be able to view the status and progress of the manuscript.<br/> - Thank you for submitting your work to Hindawi. <br/> + paragraph = `${titleText}.<br/><br/> + To confirm the submission and view the status of the manuscript, please verify your details by clicking the link below.<br/><br/> + Thank you for submitting your work to ${journalName}. ` break case 'submitting-author-manuscript-submitted': - paragraph = `Congratulations, ${titleText} has been successfully submitted.<br/> - All authors will receive correspondence regarding this manuscript, though only you will be able to make updates.<br/> - In order to view the status of the manuscript, please click the link below.<br/> - Thank you for submitting your work to Hindawi. <br/> + paragraph = `Congratulations, ${titleText} has been successfully submitted to ${journalName}.<br/><br/> + We will confirm this submission with all authors of the manuscript, but you will be the primary recipient of communications from the journal. + As submitting author, you will be responsible for responding to editorial queries and making updates to the manuscript. <br/><br/> + In order to view the status of the manuscript, please visit the manuscript details page.<br/><br/> + Thank you for submitting your work to ${journalName}. ` break default: throw new Error(`The ${emailType} email type is not defined.`) } - return { paragraph, hasLink } + return { paragraph, hasLink, hasIntro, hasSignature } } module.exports = { diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js index 94e16bb577590e7bc50046a654457bd8cbdd68ec..e021abc118ce332a834ea9ce18323ae9eba1937c 100644 --- a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js @@ -9,10 +9,10 @@ const { } = require('pubsweet-component-helper-service') const resetPath = config.get('invite-reset-password.url') -const { getEmailCopy } = require('./emailCopy') - +const { name: journalName, staffEmail } = config.get('journal') const unsubscribeSlug = config.get('unsubscribe.url') -const editorialAssistantEmail = config.get('mailer.editorialAssistant') + +const { getEmailCopy } = require('./emailCopy') module.exports = { async sendNotifications({ @@ -35,15 +35,14 @@ module.exports = { UserModel, }) - const subjectBaseText = `${collection.customId}: Manuscript` - const titleText = `the manuscript titled "${parsedFragment.title}" by ${ - submittingAuthor.firstName - } ${submittingAuthor.lastName}` + const { customId } = collection const email = new Email({ type: 'user', + fromEmail: `${journalName} <${staffEmail}>`, content: { - signatureName: get(collection, 'handlingEditor.name', 'Hindawi'), + signatureName: '', + signatureJournal: journalName, ctaLink: services.createUrl( baseUrl, `/projects/${collection.id}/versions/${fragment.id}/details`, @@ -59,8 +58,8 @@ module.exports = { email, eicName, baseUrl, - titleText, - subjectBaseText, + customId, + title: parsedFragment.title, handlingEditor: get(collection, 'handlingEditor', {}), }) } @@ -69,10 +68,10 @@ module.exports = { sendReviewersEmail({ email, baseUrl, - titleText, + customId, UserModel, fragmentHelper, - subjectBaseText, + title: parsedFragment.title, }) } @@ -82,18 +81,18 @@ module.exports = { eicName, baseUrl, collection, - subjectBaseText, - title: parsedFragment.title, }) sendAuthorsEmail({ email, baseUrl, - titleText, UserModel, - subjectBaseText, fragmentId: fragment.id, fragmentAuthors: authors, collectionId: collection.id, + title: parsedFragment.title, + submittingAuthorName: `${submittingAuthor.firstName} ${ + submittingAuthor.lastName + }`, }) } }, @@ -101,11 +100,11 @@ module.exports = { const sendHandlingEditorEmail = ({ email, + title, eicName, baseUrl, - titleText, + customId, handlingEditor, - subjectBaseText, }) => { const emailType = 'he-new-version-submitted' @@ -117,12 +116,12 @@ const sendHandlingEditorEmail = ({ id: handlingEditor.id, }) email.content.signatureName = eicName - email.content.subject = `${subjectBaseText} Update` + email.content.subject = `${customId}: Revision submitted` const { html, text } = email.getBody({ body: getEmailCopy({ emailType, - titleText, + titleText: `the manuscript titled ${title}`, }), }) email.sendEmail({ html, text }) @@ -130,13 +129,13 @@ const sendHandlingEditorEmail = ({ const sendReviewersEmail = async ({ email, + title, baseUrl, - titleText, + customId, UserModel, fragmentHelper, - subjectBaseText, }) => { - email.content.subject = `${subjectBaseText} Update` + email.content.subject = `${customId}: A manuscript you reviewed has been revised` const emailType = 'submitted-reviewers-after-revision' const reviewers = await fragmentHelper.getReviewers({ @@ -147,7 +146,7 @@ const sendReviewersEmail = async ({ reviewers.forEach(reviewer => { email.toUser = { email: reviewer.email, - name: `${reviewer.firstName} ${reviewer.lastName}`, + name: `${reviewer.lastName}`, } email.content.unsubscribeLink = services.createUrl( @@ -161,7 +160,7 @@ const sendReviewersEmail = async ({ const { html, text } = email.getBody({ body: getEmailCopy({ emailType, - titleText, + titleText: `the manuscript titled ${title}`, expectedDate: services.getExpectedDate({ daysExpected: 14 }), }), }) @@ -170,29 +169,21 @@ const sendReviewersEmail = async ({ }) } -const sendEQSEmail = ({ - email, - title, - eicName, - baseUrl, - collection, - subjectBaseText, -}) => { +const sendEQSEmail = ({ email, eicName, baseUrl, collection }) => { const emailType = 'eqs-manuscript-submitted' email.toUser = { - email: editorialAssistantEmail, + email: staffEmail, name: 'Editorial Assistant', } email.content.unsubscribeLink = baseUrl email.content.signatureName = eicName - email.content.subject = `${subjectBaseText} Submitted` + email.content.subject = `Manuscript Submitted` email.content.ctaLink = services.createUrl( baseUrl, config.get('eqs-decision.url'), { - title, collectionId: collection.id, customId: collection.customId, token: collection.technicalChecks.token, @@ -211,15 +202,16 @@ const sendEQSEmail = ({ const sendAuthorsEmail = async ({ email, + title, baseUrl, - customId, UserModel, - titleText, fragmentId, collectionId, fragmentAuthors, + submittingAuthorName, }) => { - email.content.subject = 'Manuscript Sumbmitted' + email.content.subject = `Manuscript submitted to ${journalName}` + email.content.signatureName = '' const userEmailData = await Promise.all( fragmentAuthors.map(async author => { @@ -227,15 +219,13 @@ const sendAuthorsEmail = async ({ return { ...author, isConfirmed: user.isConfirmed, - passwordResetToken: user.passwordResetToken, ...getEmailCopy({ - customId, emailType: author.isSubmitting ? 'submitting-author-manuscript-submitted' : 'coauthors-manuscript-submitted', titleText: author.isSubmitting - ? titleText - : titleText.replace(/^\w/, firstChar => firstChar.toUpperCase()), + ? `the manuscript titled "${title}"` + : `The manuscript titled "${title}" has been submitted to ${journalName} by ${submittingAuthorName}`, }), } }), @@ -244,7 +234,7 @@ const sendAuthorsEmail = async ({ userEmailData.forEach(author => { email.toUser = { email: author.email, - name: `${author.firstName} ${author.lastName}`, + name: `${author.lastName}`, } email.content.unsubscribeLink = services.createUrl( baseUrl, @@ -279,6 +269,8 @@ const sendAuthorsEmail = async ({ body: { paragraph: author.paragraph, hasLink: author.hasLink, + hasIntro: author.hasIntro, + hasSignature: author.hasSignature, }, }) email.sendEmail({ html, text }) 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 b6f8c7752688e0c4ff709f3a4637e4791eed0d0f..6023e94589f85b4aef8ca3c692e2ecc6340d267e 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/emailCopy.js @@ -1,3 +1,8 @@ +const config = require('config') + +const staffEmail = config.get('journal.staffEmail') +const journalName = config.get('journal.name') + const getEmailCopy = ({ customId, emailType, @@ -8,89 +13,107 @@ const getEmailCopy = ({ }) => { let paragraph let hasLink = true + let hasIntro = true + let hasSignature = true switch (emailType) { case 'author-request-to-revision': - paragraph = `In order for ${titleText} to proceed to publication, there needs to be a revision. <br/> - ${comments}<br/> - For more information about what is required, please visit the manuscript details page.` + 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': - paragraph = `I am sorry to inform you that ${titleText} has been rejected for publication. <br/><br/> - ${comments}<br/><br/>` + paragraph = `The peer review of ${titleText} has now been completed. I regret to inform you that your manuscript has been rejected for publication.<br/><br/> + ${comments}<br/><br/> + Thank you for your submission to ${journalName}.` hasLink = false break case 'author-manuscript-published': - paragraph = `I am delighted to inform you that ${titleText} has passed through the review process and will be published in Hindawi.<br/><br/> - Thanks again for choosing to publish with us.` - hasLink = false + paragraph = `I am delighted to inform you that the review of ${titleText} has been completed and your article will be published in ${journalName}.<br/><br/> + Please visit the manuscript details page to review the editorial notes and any comments from external reviewers.<br/><br/> + Your article will now be passed to our production team for processing, and you will hear directly from them should we require any further information.<br/><br/> + Thank you for choosing to publish with ${journalName}.` break case 'he-manuscript-rejected': hasLink = false - paragraph = `Thank you for your recommendation to reject ${titleText} based on the reviews you received.<br/><br/> - I can confirm this article has now been rejected.` + hasIntro = false + hasSignature = false + paragraph = `${targetUserName} has confirmed your decision to reject the ${titleText}.<br/><br/> + No further action is required at this time. To review this decision, please visit the manuscript details page.<br/><br/> + Thank you for handling this manuscript on behalf of ${journalName}.` break case 'he-manuscript-published': - hasLink = false - paragraph = `Thank you for your recommendation to publish ${titleText} based on the reviews you received.<br/><br/> - I can confirm this article will now go through to publication.` + paragraph = `${targetUserName} has confirmed your decision to accept ${titleText}.<br/><br/> + No further action is required at this time. To review this decision, please visit the manuscript details.<br/><br/> + 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 - paragraph = `I appreciate any time you may have spent reviewing ${titleText}. However, an editorial decision has been made and the review of this manuscript is now complete. I apologize for any inconvenience. <br/> - If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible. <br/> - Thank you for your interest and I hope you will consider reviewing for Hindawi again.` + paragraph = `I appreciate any time you may have spent reviewing ${titleText}. However, I am prepared to make an editorial decision and your review is no longer required at this time. I apologize for any inconvenience. <br/><br/> + If you have comments on this manuscript you believe I should see, please email them to ${staffEmail} as soon as possible. <br/><br/> + Thank you for your interest and I hope you will consider reviewing for ${journalName} again.` break case 'pending-reviewers-after-recommendation': hasLink = false - paragraph = `An editorial decision has been made regarding ${titleText}. So, you do not need to proceed with the review of this manuscript. <br/><br/> - If you have comments on this manuscript you believe the Editor should see, please email them to Hindawi as soon as possible.` + paragraph = `I appreciate any time you may have spent reviewing ${titleText} for ${journalName}. However, I am prepared to make an editorial decision and your review is no longer required at this time. I apologize for any inconvenience. <br/><br/> + If you have comments on this manuscript you believe I should see, please email them to ${staffEmail} as soon as possible. <br/><br/> + 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 on ${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': - hasLink = false - paragraph = `Thank you for your review on ${titleText}. After taking into account the reviews and the recommendation of the Handling Editor, I can confirm this article has now been rejected.<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 has now been rejected.<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, please email them to ${staffEmail} as soon as possible. Thank you for reviewing for ${journalName}.` break case 'he-review-submitted': paragraph = `We are pleased to inform you that Dr. ${targetUserName} has submitted a review for ${titleText}.<br/> - Please visit the manuscript details page to see the full review.` + To see the full report, please visit the manuscript details page.` break case 'eic-recommend-to-publish-from-he': - paragraph = `It is my recommendation, based on the reviews I have received for ${titleText} that we should proceed to publication.<br/> + hasIntro = false + hasSignature = false + paragraph = `Dr. ${targetUserName} has recommended accepting ${titleText} for publication.<br/> ${comments}<br/> - For more information, and to see the full review, please visit the manuscript details page.` + To review this decision, please visit the manuscript details page.` break case 'eic-recommend-to-reject-from-he': - paragraph = `It is my recommendation, based on the reviews I have received for ${titleText} that we should reject it for publication.<br/> + hasIntro = false + hasSignature = false + paragraph = `Dr. ${targetUserName} has recommended rejecting ${titleText}.<br/> ${comments}<br/> - For more information, and to see the full review, please visit the manuscript details page.` + To review this decision, please visit the manuscript details page.` break case 'eic-request-revision-from-he': - paragraph = `In order for ${titleText} to proceed to publication, there needs to be a revision. <br/><br/> - For more information about what is required, please visit the manuscript details page.` + hasIntro = false + hasSignature = false + paragraph = `Dr. ${targetUserName} has asked the authors to submit a revised version of ${titleText}.<br/><br/> + 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` + Please complete QA screening so that manuscript can be sent to production.` break default: throw new Error(`The ${emailType} email type is not defined.`) } - return { paragraph, hasLink } + return { paragraph, hasLink, hasIntro, hasSignature } } module.exports = { diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js new file mode 100644 index 0000000000000000000000000000000000000000..813b50f59c642813a0abcb651853f5d0c0afd426 --- /dev/null +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/helpers.js @@ -0,0 +1,392 @@ +const config = require('config') +const { get, chain } = require('lodash') + +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 }) => { + reviewers.forEach(reviewer => { + email.toUser = { + email: reviewer.email, + name: `${reviewer.lastName}`, + } + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: reviewer.id, + }, + ) + const { html, text } = email.getBody({ + body: { + paragraph: reviewer.paragraph, + hasLink: reviewer.hasLink, + hasIntro: reviewer.hasIntro, + hasSignature: reviewer.hasSignature, + }, + }) + email.sendEmail({ html, text }) + }) + }, + getSubmittedReviewers: async ({ + UserModel, + titleText, + fragmentHelper, + recommendation, + }) => { + const emailType = + recommendation === 'publish' + ? 'submitted-reviewers-after-publish' + : 'submitted-reviewers-after-reject' + + const reviewers = (await fragmentHelper.getReviewers({ + UserModel, + type: 'submitted', + })).map(rev => ({ + ...rev, + emailType, + ...getEmailCopy({ + emailType, + titleText, + }), + })) + + return reviewers + }, + getNoResponseReviewers: async ({ fragmentHelper, UserModel, titleText }) => { + const acceptedReviewers = (await fragmentHelper.getReviewers({ + UserModel, + type: 'accepted', + })).map(rev => ({ + ...rev, + ...getEmailCopy({ + emailType: 'accepted-reviewers-after-recommendation', + titleText, + }), + })) + + const pendingReviewers = (await fragmentHelper.getReviewers({ + UserModel, + type: 'pending', + })).map(rev => ({ + ...rev, + ...getEmailCopy({ + emailType: 'pending-reviewers-after-recommendation', + titleText, + }), + })) + + const reviewers = [...acceptedReviewers, ...pendingReviewers] + + return reviewers + }, + updateEmailContentForReviewers: ({ + email, + 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: ({ + email, + comments, + emailType, + titleText, + targetUserName, + }) => { + const { html, text } = email.getBody({ + body: getEmailCopy({ + emailType, + titleText, + comments, + targetUserName, + }), + }) + email.sendEmail({ html, text }) + }, + updateEmailContentForHE: ({ + email, + baseUrl, + eicName, + customId, + heLastName, + handlingEditor, + recommendation, + recommendationType, + }) => { + if (recommendationType === 'review') { + email.content.subject = `${customId}: A review has been submitted` + } else { + 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 = { + email: handlingEditor.email, + name: heLastName, + } + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: handlingEditor.id, + }, + ) + + email.content.signatureName = eicName + delete email.content.signatureJournal + + return email + }, + getEmailTypeByRecommendationForHE: ({ + recommendation, + recommendationType, + }) => { + let emailType + if (recommendationType === 'review') { + emailType = 'he-review-submitted' + } else { + switch (recommendation) { + case 'return-to-handling-editor': + emailType = 'he-manuscript-return-with-comments' + break + case 'publish': + emailType = 'he-manuscript-published' + break + case 'reject': + emailType = 'he-manuscript-rejected' + break + default: + throw new Error(`undefined recommendation: ${recommendation} `) + } + } + + return emailType + }, + getEiCCommentsForHE: ({ newRecommendation }) => { + const eicComments = chain(newRecommendation) + .get('comments') + .find(comm => !comm.public) + .get('content') + .value() + + return eicComments + }, + sendEiCsEmail: async ({ + email, + customId, + titleText, + userHelper, + targetUserName, + recommendation: { recommendation, comments: recComments = [] }, + }) => { + let emailType + + switch (recommendation) { + case 'minor': + case 'major': + emailType = 'eic-request-revision-from-he' + email.content.subject = `${customId}: Revision requested` + break + case 'publish': + emailType = 'eic-recommend-to-publish-from-he' + email.content.subject = `${customId}: Recommendation to publish` + break + case 'reject': + emailType = 'eic-recommend-to-reject-from-he' + email.content.subject = `${customId}: Recommendation to reject` + break + default: + throw new Error(`undefined recommendation: ${recommendation} `) + } + delete email.content.signatureJournal + + const privateNote = recComments.find(comm => !comm.public) + const content = get(privateNote, 'content') + const comments = content + ? `The editor provided the following comments: "${content}"` + : '' + + const editors = (await userHelper.getEditorsInChief()).map(eic => ({ + ...eic, + ...getEmailCopy({ + comments, + emailType, + titleText, + targetUserName, + }), + })) + + editors.forEach(eic => { + email.toUser = { + email: eic.email, + name: `${eic.firstName} ${eic.lastName}`, + } + const { html, text } = email.getBody({ + body: { + paragraph: eic.paragraph, + hasLink: eic.hasLink, + hasIntro: eic.hasIntro, + hasSignature: eic.hasSignature, + }, + }) + email.sendEmail({ html, text }) + }) + }, + sendAuthorsEmail: async ({ email, authors, baseUrl }) => { + authors.forEach(author => { + email.toUser = { + email: author.email, + name: `${author.lastName}`, + } + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: author.id, + }, + ) + const { html, text } = email.getBody({ + body: { + paragraph: author.paragraph, + hasLink: author.hasLink, + hasIntro: author.hasIntro, + hasSignature: author.hasSignature, + }, + }) + email.sendEmail({ html, text }) + }) + }, + getSubmittingAuthor: ({ + title, + journalName, + authorNoteText, + submittingAuthor, + }) => { + const author = { + ...submittingAuthor, + ...getEmailCopy({ + emailType: 'author-request-to-revision', + titleText: `your submission "${title}" to ${journalName}`, + comments: authorNoteText, + }), + } + + return author + }, + getPrivateNoteTextForAuthor: ({ newRecommendation }) => { + const authorNote = newRecommendation.comments.find(comm => comm.public) + const content = get(authorNote, 'content') + const authorNoteText = content ? `Reason & Details: "${content}"` : '' + + return authorNoteText + }, + 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') + } + const comments = `Please find our editorial comments below<br/>: "${content}"` + + return comments + }, + getAllAuthors: ({ title, comments, emailType, fragmentAuthors }) => { + const authors = fragmentAuthors.map(author => ({ + ...author, + ...getEmailCopy({ + comments, + emailType, + titleText: `your manuscript titled "${title}"`, + }), + })) + + return authors + }, + sendSubmittingAuthorEmail: ({ email, author, baseUrl }) => { + email.toUser = { + email: author.email, + name: `${author.lastName}`, + } + email.content.unsubscribeLink = services.createUrl( + baseUrl, + unsubscribeSlug, + { + id: author.id, + }, + ) + const { html, text } = email.getBody({ + body: { + paragraph: author.paragraph, + hasLink: author.hasLink, + hasIntro: author.hasIntro, + hasSignature: author.hasSignature, + }, + }) + email.sendEmail({ html, text }) + }, + updateEmailContentForAllAuthors: ({ email, recommendation, customId }) => { + switch (recommendation) { + case 'publish': + email.content.subject = `${customId}: Manuscript accepted` + break + case 'reject': + email.content.subject = `${customId}: Manuscript rejected` + break + default: + throw new Error(`Undefined recommendation: ${recommendation}`) + } + email.content.signatureJournal = journalName + + return email + }, + getEmailTypeByRecommendationForAuthors: ({ recommendation }) => { + let emailType + switch (recommendation) { + case 'publish': + emailType = 'author-manuscript-published' + break + case 'reject': + emailType = 'author-manuscript-rejected' + break + default: + throw new Error(`Undefined recommendation: ${recommendation}`) + } + + return emailType + }, +} 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 a84b5541b3768d11c3784e7287a2009882aa7a3c..31fae2c98f726a45ba24fb8af41add253f07bb5f 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js @@ -1,18 +1,19 @@ const config = require('config') -const { chain, get, isEmpty } = require('lodash') +const { get, isEmpty } = require('lodash') const { User, Email, services, Fragment, + Collection, } = require('pubsweet-component-helper-service') const { getEmailCopy } = require('./emailCopy') +const helpers = require('./helpers') -const editorialAssistantEmail = config.get('mailer.editorialAssistant') -const unsubscribeSlug = config.get('unsubscribe.url') - +const editorialAssistantEmail = config.get('journal.staffEmail') +const journalName = config.get('journal.name') module.exports = { async sendNotifications({ hasEQA, @@ -31,19 +32,20 @@ module.exports = { const fragmentAuthors = await fragmentHelper.getAuthorData({ UserModel }) const subjectBaseText = `${collection.customId}: Manuscript` - const titleText = `the manuscript titled "${parsedFragment.title}" by ${ + const titleText = `Txhe manuscript titled "${parsedFragment.title}" by ${ fragmentAuthors.submittingAuthor.firstName } ${fragmentAuthors.submittingAuthor.lastName}` const userHelper = new User({ UserModel }) const eicName = await userHelper.getEiCName() - const email = new Email({ + let email = new Email({ type: 'user', content: { + signatureName: eicName, unsubscribeLink: baseUrl, ctaText: 'MANUSCRIPT DETAILS', - signatureName: eicName, + signatureJournal: journalName, ctaLink: services.createUrl( baseUrl, `/projects/${collection.id}/versions/${fragment.id}/details`, @@ -51,9 +53,11 @@ module.exports = { }, }) + const { recommendation, recommendationType } = newRecommendation + // the EiC recommends to publish so an email to the EQA needs to be sent, // one requesting approval or one informing them that the manuscript has been published - if (isEditorInChief && newRecommendation.recommendation === 'publish') { + if (isEditorInChief && recommendation === 'publish') { sendEQAEmail({ email, eicName, @@ -64,376 +68,139 @@ module.exports = { }) } - let comments - if (isEditorInChief) { - const eicComments = chain(newRecommendation) - .get('comments') - .find(comm => !comm.public) - .get('content') - .value() - - comments = eicComments - } - const hasPeerReview = (collection = {}) => !isEmpty(collection.handlingEditor) + 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 || newRecommendation.recommendationType === 'review') && - hasPeerReview(collection) + (isEditorInChief || recommendationType === 'review') && + hasPeerReview(collection) && + (recommendation !== 'publish' || hasEQA) ) { - // the request came from either the Editor in Chief or a reviewer, so the HE needs to be notified - sendHandlingEditorEmail({ + email = helpers.updateEmailContentForHE({ email, - hasEQA, 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, - subjectBaseText, - handlingEditor: get(collection, 'handlingEditor', {}), - recommendation: newRecommendation.recommendation, - recommendationType: newRecommendation.recommendationType, }) } if ( - newRecommendation.recommendationType !== 'review' && - newRecommendation.recommendation !== 'return-to-handling-editor' + recommendationType === 'review' || + recommendation === 'return-to-handling-editor' ) { - if (isEditorInChief || collection.status === 'revisionRequested') { - sendAuthorsEmail({ - email, - hasEQA, - baseUrl, - titleText, - parsedFragment, - fragmentAuthors, - isEditorInChief, - subjectBaseText, - newRecommendation, - handlingEditorName: get(collection, 'handlingEditor.name', eicName), - }) - } - - if (hasPeerReview(collection)) { - sendReviewersEmail({ - email, - hasEQA, - baseUrl, - UserModel, - titleText, - fragmentHelper, - isEditorInChief, - subjectBaseText, - recommendation: newRecommendation.recommendation, - handlingEditorName: get(collection, 'handlingEditor.name', eicName), - }) - - if (!isEditorInChief) { - sendEiCsEmail({ - email, - baseUrl, - userHelper, - titleText, - subjectBaseText, - recommendation: newRecommendation, - }) - } - } - } - }, -} - -const sendHandlingEditorEmail = ({ - email, - hasEQA, - eicName, - baseUrl, - comments, - titleText, - handlingEditor, - targetUserName, - recommendation, - subjectBaseText, - recommendationType, -}) => { - let emailType - if (recommendationType === 'review') { - email.content.subject = `${subjectBaseText} Review` - emailType = 'he-review-submitted' - } else { - email.content.subject = `${subjectBaseText} Decision` - - if (recommendation === 'publish' && !hasEQA) { - // the EiC recommended to publish but the manuscript has not passed through the EQA process - // so the HE should not receive any email return } - switch (recommendation) { - case 'return-to-handling-editor': - emailType = 'he-manuscript-return-with-comments' - break - case 'publish': - emailType = 'he-manuscript-published' - break - case 'reject': - emailType = 'he-manuscript-rejected' - break - default: - throw new Error(`undefined recommendation: ${recommendation} `) - } - } - - email.toUser = { - email: handlingEditor.email, - name: handlingEditor.name, - } - email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, { - id: handlingEditor.id, - }) - - email.content.signatureName = eicName - - const { html, text } = email.getBody({ - body: getEmailCopy({ - emailType, - titleText, - comments, - targetUserName, - }), - }) - email.sendEmail({ html, text }) -} - -const sendAuthorsEmail = async ({ - email, - hasEQA, - baseUrl, - titleText, - isEditorInChief, - subjectBaseText, - fragmentAuthors, - newRecommendation, - handlingEditorName, - parsedFragment: { heRecommendation }, -}) => { - let emailType, authors, comments - - if (isEditorInChief) { - const heComments = get(heRecommendation, 'comments', []) - if (heComments.length) { - const publicComment = heComments.find(comm => comm.public) - const content = get(publicComment, 'content') - if (!content) { - throw new Error('a public comment cannot be without content') - } - comments = `Reason & Details: "${content}"` - } - - if (newRecommendation.recommendation === 'publish') { - if (!hasEQA) { - // the manuscript did not pass through the EQA process - return - } - - emailType = 'author-manuscript-published' - email.content.subject = `${subjectBaseText} Published` - } else { - emailType = 'author-manuscript-rejected' - email.content.subject = `${subjectBaseText} Decision` - } - - authors = fragmentAuthors.activeAuthors.map(author => ({ - ...author, - ...getEmailCopy({ - emailType, - titleText, + // 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, - }), - })) - } else { - emailType = 'author-request-to-revision' - - email.content.subject = `${subjectBaseText} Recommendation` - email.content.signatureName = handlingEditorName + emailType, + title: parsedFragment.title, + fragmentAuthors: fragmentAuthors.activeAuthors, + }) + email = helpers.updateEmailContentForAllAuthors({ + email, + customId, + recommendation, + }) + helpers.sendAuthorsEmail({ email, authors, baseUrl }) + } - const authorNote = newRecommendation.comments.find(comm => comm.public) - const content = get(authorNote, 'content') - const authorNoteText = content ? `Reason & Details: "${content}"` : '' - authors = [ - { - ...fragmentAuthors.submittingAuthor, - ...getEmailCopy({ - emailType, - titleText, - comments: authorNoteText, - }), - }, - ] - } + // 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), + }) - authors.forEach(author => { - email.toUser = { - email: author.email, - name: `${author.firstName} ${author.lastName}`, + helpers.sendSubmittingAuthorEmail({ email, author, baseUrl }) } - email.content.unsubscribeLink = services.createUrl( - baseUrl, - unsubscribeSlug, - { - id: author.id, - }, - ) - const { html, text } = email.getBody({ - body: { - paragraph: author.paragraph, - hasLink: author.hasLink, - }, - }) - email.sendEmail({ html, text }) - }) -} -const sendReviewersEmail = async ({ - email, - baseUrl, - hasEQA, - eicName, - titleText, - UserModel, - fragmentHelper, - recommendation, - isEditorInChief, - subjectBaseText, - handlingEditorName, -}) => { - let reviewers - if (isEditorInChief) { - email.content.subject = `${subjectBaseText} Decision` - const emailType = - recommendation === 'publish' - ? 'submitted-reviewers-after-publish' - : 'submitted-reviewers-after-reject' - - if (recommendation === 'publish' && !hasEQA) { - // the manuscript has not passed through the EQA process - // so the reviewers should not receive any email + if (!hasPeerReview(collection)) { return } - reviewers = (await fragmentHelper.getReviewers({ - UserModel, - type: 'submitted', - })).map(rev => ({ - ...rev, - emailType, - ...getEmailCopy({ - emailType, - titleText, - }), - })) - email.content.signatureName = eicName - } else { - email.content.signatureName = handlingEditorName - email.content.subject = `${subjectBaseText} ${getSubjectByRecommendation( - recommendation, - )}` + let reviewers = [] + if (isEditorInChief) { + if (recommendation !== 'publish' || hasEQA) { + email = helpers.updateEmailContentForReviewers({ + email, + customId, + recommendation, + signatureName: eicName, + }) + reviewers = await helpers.getSubmittedReviewers({ + UserModel, + titleText, + fragmentHelper, + recommendation, + }) + } + } else { + email = helpers.updateEmailContentForReviewers({ + email, + customId, + subject: `Review no longer required`, + signatureName: get(collection, 'handlingEditor.name', eicName), + }) - const acceptedReviewers = (await fragmentHelper.getReviewers({ - UserModel, - type: 'accepted', - })).map(rev => ({ - ...rev, - ...getEmailCopy({ - emailType: 'accepted-reviewers-after-recommendation', + reviewers = await helpers.getNoResponseReviewers({ + UserModel, titleText, - }), - })) + fragmentHelper, + }) - const pendingReviewers = (await fragmentHelper.getReviewers({ - UserModel, - type: 'pending', - })).map(rev => ({ - ...rev, - ...getEmailCopy({ - emailType: 'pending-reviewers-after-recommendation', + helpers.sendEiCsEmail({ + email, + baseUrl, + customId, titleText, - }), - })) - - reviewers = [...acceptedReviewers, ...pendingReviewers] - } - - reviewers.forEach(reviewer => { - email.toUser = { - email: reviewer.email, - name: `${reviewer.firstName} ${reviewer.lastName}`, + userHelper, + recommendation: newRecommendation, + targetUserName: collHelper.getHELastName(), + }) } - email.content.unsubscribeLink = services.createUrl( - baseUrl, - unsubscribeSlug, - { - id: reviewer.id, - }, - ) - const { html, text } = email.getBody({ - body: { paragraph: reviewer.paragraph, hasLink: reviewer.hasLink }, - }) - email.sendEmail({ html, text }) - }) -} -const sendEiCsEmail = async ({ - email, - titleText, - userHelper, - subjectBaseText, - recommendation: { recommendation, comments: recComments = [] }, -}) => { - let emailType - - email.content.subject = `${subjectBaseText} Recommendation` - switch (recommendation) { - case 'minor': - case 'major': - emailType = 'eic-request-revision-from-he' - break - case 'publish': - emailType = 'eic-recommend-to-publish-from-he' - break - case 'reject': - emailType = 'eic-recommend-to-reject-from-he' - break - default: - throw new Error(`undefined recommendation: ${recommendation} `) - } - - const privateNote = recComments.find(comm => !comm.public) - const content = get(privateNote, 'content') - const comments = content ? `Note to Editor: "${content}"` : '' - - const editors = (await userHelper.getEditorsInChief()).map(eic => ({ - ...eic, - ...getEmailCopy({ - emailType, - titleText, - comments, - }), - })) - - editors.forEach(eic => { - email.toUser = { - email: eic.email, - name: `${eic.firstName} ${eic.lastName}`, - } - const { html, text } = email.getBody({ - body: { paragraph: eic.paragraph, hasLink: eic.hasLink }, - }) - email.sendEmail({ html, text }) - }) + helpers.sendReviewersEmail({ email, baseUrl, reviewers }) + }, } const sendEQAEmail = ({ @@ -448,7 +215,7 @@ const sendEQAEmail = ({ switch (collection.status) { case 'accepted': emailType = 'eqa-manuscript-published' - email.content.subject = `${subjectBaseText} Decision` + email.content.subject = `${subjectBaseText} decision finalized` break case 'inQA': emailType = 'eqa-manuscript-request-for-approval' @@ -488,8 +255,3 @@ const sendEQAEmail = ({ }) email.sendEmail({ html, text }) } - -const getSubjectByRecommendation = recommendation => - ['minor', 'major'].includes(recommendation) - ? 'Revision Requested' - : 'Recommendation Submitted' diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js index 1e0e4f2425d884b64e5e0ad3c8616d83c371e8a3..43ea6d60498e6c90dceadec514060fe4d55bf3a9 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/patch.js @@ -55,7 +55,7 @@ module.exports = models => async (req, res) => { UserModel: models.User, baseUrl: services.getBaseUrl(req), newRecommendation: recommendation, - targetUserName: `${user.firstName} ${user.lastName}`, + targetUserName: `${user.lastName}`, }) if (['underReview'].includes(collection.status)) { diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js index 4e7a82189d0996f4b5b61da58807143aecabe348..6b2ccae9ccf2e8c4eb5e65974c37f105ae66221a 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js @@ -118,6 +118,7 @@ module.exports = models => async (req, res) => { isEditorInChief, newRecommendation, UserModel: models.User, + targetUserName: reqUser.lastName, baseUrl: services.getBaseUrl(req), }) } diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js index 0c36acca52a116cc5f9584d0679a52944e635b02..d454047c92f9d937a234ee0eb60baf89e0ed50b1 100644 --- a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js +++ b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/emailCopy.js @@ -1,9 +1,19 @@ +const config = require('config') + +// const staffEmail = config.get('journal.staffEmail') +const journalName = config.get('journal.name') + const getEmailCopy = ({ emailType, titleText, comments }) => { let paragraph let hasLink = true + let hasIntro = true + let hasSignature = true switch (emailType) { case 'eqs-manuscript-accepted': - paragraph = `We are please to inform you that ${titleText} has passed the Hindawi technical check process and is now submitted. Please click the link below to access the manuscript.` + hasIntro = false + hasSignature = false + paragraph = `A new ${titleText} has been submitted to ${journalName}.<br/><br/> + To begin the review process, please visit the manuscript details page.` break case 'he-manuscript-published': hasLink = false @@ -28,7 +38,7 @@ const getEmailCopy = ({ emailType, titleText, comments }) => { throw new Error(`The ${emailType} email type is not defined.`) } - return { paragraph, hasLink } + return { paragraph, hasLink, hasIntro, hasSignature } } module.exports = { diff --git a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js index d130afb1506b1cabc01f24df626b066fdd726815..a51cf5e2b78b9f40d44a95d6c7e4898e9497bd76 100644 --- a/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/technicalChecks/notifications/notifications.js @@ -10,6 +10,7 @@ const { const { getEmailCopy } = require('./emailCopy') const unsubscribeSlug = config.get('unsubscribe.url') +const { name: journalName, staffEmail } = config.get('journal') module.exports = { async sendNotifications({ @@ -34,11 +35,11 @@ module.exports = { UserModel, }) - const titleText = `the manuscript titled "${parsedFragment.title}" by ${ + const titleText = `manuscript titled "${parsedFragment.title}" by ${ submittingAuthor.firstName } ${submittingAuthor.lastName}` const subjectBaseText = `${collection.customId}: Manuscript` - + const { customId } = collection const userHelper = new User({ UserModel }) const subject = `${subjectBaseText} ${ agree ? '' : 'Not ' @@ -46,6 +47,7 @@ module.exports = { const email = new Email({ type: 'user', + fromEmail: `${journalName} <${staffEmail}>`, content: { subject, signatureName: 'EQA Team', @@ -85,7 +87,14 @@ module.exports = { fragmentAuthors: authors, }) } else { - sendEditorsEmail({ email, agree, comments, userHelper, titleText }) + sendEditorsEmail({ + email, + agree, + customId, + comments, + titleText, + userHelper, + }) } }, } @@ -93,10 +102,12 @@ module.exports = { const sendEditorsEmail = async ({ email, agree, - comments = '', - userHelper, titleText, + customId, + userHelper, + comments = '', }) => { + email.content.subject = `${customId}: New manuscript submitted` const emailType = agree ? 'eqs-manuscript-accepted' : 'eqa-manuscript-returned-to-eic' @@ -116,7 +127,12 @@ const sendEditorsEmail = async ({ name: `${eic.firstName} ${eic.lastName}`, } const { html, text } = email.getBody({ - body: { paragraph: eic.paragraph, hasLink: eic.hasLink }, + body: { + paragraph: eic.paragraph, + hasLink: eic.hasLink, + hasIntro: eic.hasIntro, + hasSignature: eic.hasSignature, + }, }) email.sendEmail({ html, text }) }) diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js index 768e933842c849abb6cbe6812a2591fe402afbf3..386431403037ea057fe143a9fb10c873f1349307 100644 --- a/packages/xpub-faraday/config/default.js +++ b/packages/xpub-faraday/config/default.js @@ -3,8 +3,6 @@ const path = require('path') const components = require('./components.json') const logger = require('winston') -// const environment = process.env.NODE_ENV || 'development' - const getDbConfig = () => { if (process.env.DATABASE) { return { @@ -115,7 +113,6 @@ module.exports = { mailer: { from: 'hindawi@thinslices.com', path: `${__dirname}/mailer`, - editorialAssistant: 'hindawi+editorial@thinslices.com', }, SES: { accessKey: process.env.AWS_SES_ACCESS_KEY, @@ -450,4 +447,8 @@ module.exports = { key: process.env.PUBLONS_KEY || '', reviewersUrl: 'https://api.clarivate.com/reviewer-connect/api/', }, + journal: { + name: 'Bioinorganic Chemistry and Applications', + staffEmail: 'hindawi+staff@thinslices.com', + }, }