Newer
Older
const config = require('config')
const { get, isEmpty, chain } = require('lodash')
const Email = require('@pubsweet/component-email-templating')
const {
User,
services,
Fragment,
Collection,
} = require('pubsweet-component-helper-service')
const helpers = require('./helpers')
const { getEmailCopy } = require('./emailCopy')
const { name: journalName, staffEmail } = config.get('journal')
const unsubscribeSlug = config.get('unsubscribe.url')
class Notification {
constructor({
baseUrl = '',
fragment = {},
UserModel = {},
collection = {},
newRecommendation = {},
}) {
this.baseUrl = baseUrl
this.fragment = fragment
this.UserModel = UserModel
this.collection = collection
this.newRecommendation = newRecommendation
}
async notifyHEWhenReviewerSubmitsReport(reviewerLastName) {
const { eicName, titleText } = await this._getNotificationProperties()
const handlingEditorId = get(this.collection, 'handlingEditor.id')
const heUser = await this.UserModel.find(handlingEditorId)
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'he-review-submitted',
titleText,
targetUserName: reviewerLastName,
})
const email = new Email({
type: 'user',
toUser: {
email: heUser.email,
name: heUser.lastName,
},
fromEmail: `${eicName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: A review has been submitted`,
paragraph,
signatureName: eicName,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: heUser.id,
token: heUser.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
async notifyHEWhenEiCMakesDecision() {
const {
eicName,
titleText,
recommendation,
} = await this._getNotificationProperties()
const handlingEditorId = get(this.collection, 'handlingEditor.id')
const heUser = await this.UserModel.find(handlingEditorId)
const { paragraph, ...bodyProps } = getEmailCopy({
titleText,
targetUserName: eicName,
emailType:
recommendation === 'publish'
? 'he-manuscript-published'
: 'he-manuscript-rejected',
})
const email = new Email({
type: 'user',
toUser: {
email: heUser.email,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: Editorial decision confirmed`,
paragraph,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: heUser.id,
token: heUser.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
}
async notifyHEWhenEiCReturnsToHE() {
const { eicName, titleText } = await this._getNotificationProperties()
Andrei Cioromila
committed
const handlingEditorId = get(this.collection, 'handlingEditor.id')
const heUser = await this.UserModel.find(handlingEditorId)
const eicComments = chain(this.newRecommendation)
.get('comments')
.find(comm => !comm.public)
.get('content')
.value()
const { paragraph, ...bodyProps } = getEmailCopy({
titleText,
comments: eicComments,
targetUserName: eicName,
emailType: 'he-manuscript-return-with-comments',
})
const email = new Email({
type: 'user',
toUser: {
Andrei Cioromila
committed
email: heUser.email,
name: heUser.lastName,
},
fromEmail: `${eicName} <${staffEmail}>`,
content: {
subject: `${
this.collection.customId
}: Editorial decision returned with comments`,
paragraph,
signatureName: eicName,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
Andrei Cioromila
committed
id: heUser.id,
token: heUser.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
}
Andrei Cioromila
committed
async notifyEAWhenEiCMakesFinalDecision() {
const { eicName, titleText } = await this._getNotificationProperties()
const subjectBaseText = `${this.collection.customId}: Manuscript`
const { paragraph, ...bodyProps } = getEmailCopy({
eicName,
titleText,
emailType: 'eqa-manuscript-published',
})
const email = new Email({
type: 'system',
toUser: {
email: staffEmail,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject: `${subjectBaseText} decision finalized`,
paragraph,
unsubscribeLink: this.baseUrl,
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
async notifyEAWhenEiCRequestsEQAApproval() {
const { eicName } = await this._getNotificationProperties()
const subjectBaseText = `${this.collection.customId}: Manuscript`
const { paragraph, ...bodyProps } = getEmailCopy({
eicName,
customId: this.collection.customId,
emailType: 'eqa-manuscript-request-for-approval',
})
const email = new Email({
type: 'system',
toUser: {
email: staffEmail,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject: `${subjectBaseText} Request for EQA approval`,
paragraph,
unsubscribeLink: this.baseUrl,
ctaText: 'MAKE DECISION',
ctaLink: services.createUrl(
this.baseUrl,
config.get('eqa-decision.url'),
{
collectionId: this.collection.id,
customId: this.collection.customId,
token: this.collection.technicalChecks.token,
},
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
async notifyAuthorsWhenEiCMakesDecision() {
const {
eicName,
titleText,
activeAuthors,
recommendation,
parsedFragment,
} = await this._getNotificationProperties()
Andrei Cioromila
committed
Andrei Cioromila
committed
const subjectOpts = {
publish: `${this.collection.customId}: Manuscript accepted`,
reject: `${this.collection.customId}: Manuscript rejected`,
}
const subject = subjectOpts[recommendation]
Andrei Cioromila
committed
Andrei Cioromila
committed
if (isEmpty(subject)) {
throw new Error(`Undefined recommendation: ${recommendation}`)
}
Andrei Cioromila
committed
Andrei Cioromila
committed
const hasPeerReview = !isEmpty(this.collection.handlingEditor)
const emailType = helpers.getEmailTypeByRecommendationForAuthors({
recommendation,
hasPeerReview,
})
const comments = hasPeerReview
? helpers.getHEComments({
heRecommendation: parsedFragment.heRecommendation,
})
: this.newRecommendation.comments[0].content
const { paragraph, ...bodyProps } = getEmailCopy({
titleText,
emailType,
comments,
})
Andrei Cioromila
committed
activeAuthors.forEach(async author => {
Andrei Cioromila
committed
const email = new Email({
type: 'user',
toUser: {
email: author.email,
name: author.lastName,
},
fromEmail: `${eicName} <${staffEmail}>`,
content: {
subject,
paragraph,
Andrei Cioromila
committed
signatureName: eicName,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: author.id,
token: author.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
signatureJournal: journalName,
},
bodyProps,
Andrei Cioromila
committed
})
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
})
}
Andrei Cioromila
committed
async notifyReviewersWhenEiCMakesDecision() {
const {
eicName,
titleText,
recommendation,
fragmentHelper,
} = await this._getNotificationProperties()
Andrei Cioromila
committed
const emailType =
recommendation === 'publish'
? 'submitted-reviewers-after-publish'
: 'submitted-reviewers-after-reject'
const subject =
recommendation === 'publish'
? 'A manuscript you reviewed has been accepted'
: 'A manuscript you reviewed has been rejected'
const reviewers = await fragmentHelper.getReviewers({
UserModel: this.UserModel,
type: 'submitted',
})
const { paragraph, ...bodyProps } = getEmailCopy({
Andrei Cioromila
committed
emailType,
titleText,
})
reviewers.forEach(reviewer => {
const email = new Email({
type: 'user',
toUser: {
email: reviewer.email,
name: reviewer.lastName,
},
fromEmail: `${eicName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: ${subject}`,
paragraph,
Andrei Cioromila
committed
signatureName: eicName,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: reviewer.id,
token: reviewer.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
signatureJournal: journalName,
},
bodyProps,
Andrei Cioromila
committed
})
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
})
}
async notifySAWhenHERequestsRevision() {
const {
eicName,
submittingAuthor,
parsedFragment: { title },
} = await this._getNotificationProperties()
const authorNoteText = helpers.getPrivateNoteTextForAuthor({
newRecommendation: this.newRecommendation,
})
const signatureName = get(this.collection, 'handlingEditor.name', eicName)
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'author-request-to-revision',
titleText: `your submission "${title}" to ${journalName}`,
comments: authorNoteText,
})
const email = new Email({
type: 'user',
toUser: {
email: submittingAuthor.email,
name: submittingAuthor.lastName,
},
fromEmail: `${signatureName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: Revision requested`,
paragraph,
signatureName,
ctaText: 'MANUSCRIPT DETAILS',
signatureJournal: journalName,
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: submittingAuthor.id,
token: submittingAuthor.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
})
Andrei Cioromila
committed
return email.sendEmail()
}
Andrei Cioromila
committed
async notifyReviewersWhenHEMakesRecommendation() {
const {
eicName,
titleText,
fragmentHelper,
} = await this._getNotificationProperties()
Andrei Cioromila
committed
const signatureName = get(this.collection, 'handlingEditor.name', eicName)
const acceptedReviewers = await fragmentHelper.getReviewers({
UserModel: this.UserModel,
type: 'accepted',
})
const acceptedReviewersEmailBody = getEmailCopy({
emailType: 'accepted-reviewers-after-recommendation',
titleText,
})
const pendingReviewers = await fragmentHelper.getReviewers({
UserModel: this.UserModel,
type: 'pending',
})
const pendingReviewersEmailBody = getEmailCopy({
emailType: 'pending-reviewers-after-recommendation',
titleText,
})
const buildSendEmailFunction = emailBodyProps => reviewer => {
const { paragraph, ...bodyProps } = emailBodyProps
Andrei Cioromila
committed
const email = new Email({
type: 'user',
toUser: {
email: reviewer.email,
name: reviewer.lastName,
},
fromEmail: `${signatureName} <${staffEmail}>`,
Andrei Cioromila
committed
content: {
subject: `${this.collection.customId}: Review no longer required`,
paragraph,
Andrei Cioromila
committed
signatureName,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: reviewer.id,
token: reviewer.accessTokens.unsubscribe,
}),
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
signatureJournal: journalName,
},
bodyProps,
Andrei Cioromila
committed
})
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
}
acceptedReviewers.forEach(
buildSendEmailFunction(acceptedReviewersEmailBody),
)
pendingReviewers.forEach(buildSendEmailFunction(pendingReviewersEmailBody))
}
Andrei Cioromila
committed
async notifyEiCWhenHEMakesRecommendation() {
const {
eicName,
titleText,
recommendation,
} = await this._getNotificationProperties()
Andrei Cioromila
committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
let emailType, subject
switch (recommendation) {
case 'minor':
case 'major':
emailType = 'eic-request-revision-from-he'
subject = `${this.collection.customId}: Revision requested`
break
case 'publish':
emailType = 'eic-recommend-to-publish-from-he'
subject = `${this.collection.customId}: Recommendation to publish`
break
case 'reject':
emailType = 'eic-recommend-to-reject-from-he'
subject = `${this.collection.customId}: Recommendation to reject`
break
default:
throw new Error(`undefined recommendation: ${recommendation} `)
}
const privateNote = this.newRecommendation.comments.find(
comm => !comm.public,
)
const content = get(privateNote, 'content')
const comments = content
? `The editor provided the following comments: "${content}"`
: ''
const collHelper = new Collection({ collection: this.collection })
const targetUserName = collHelper.getHELastName()
const userHelper = new User({ UserModel: this.UserModel })
const editors = await userHelper.getEditorsInChief()
const { paragraph, ...bodyProps } = getEmailCopy({
Andrei Cioromila
committed
comments,
emailType,
titleText,
targetUserName,
})
editors.forEach(eic => {
const email = new Email({
type: 'user',
toUser: {
email: eic.email,
name: `${eic.firstName} ${eic.lastName}`,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject,
paragraph,
signatureName: eicName,
Andrei Cioromila
committed
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: this.baseUrl,
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
})
Andrei Cioromila
committed
return email.sendEmail()
Andrei Cioromila
committed
})
}
async notifyEiCWhenEQSAcceptsManuscript() {
const { submittingAuthor } = await this._getNotificationProperties()
const userHelper = new User({ UserModel: this.UserModel })
const editors = await userHelper.getEditorsInChief()
const fragmentHelper = new Fragment({ fragment: this.fragment })
const parsedFragment = await fragmentHelper.getFragmentData({})
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'eic-manuscript-accepted-by-eqs',
titleText: `manuscript titled "${parsedFragment.title}" by ${
submittingAuthor.firstName
} ${submittingAuthor.lastName}`,
})
editors.forEach(eic => {
const email = new Email({
type: 'system',
toUser: {
email: eic.email,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: New manuscript submitted`,
paragraph,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: this.baseUrl,
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
})
}
async notifyEiCWhenEQARejectsManuscript(comments) {
const { titleText } = await this._getNotificationProperties()
const userHelper = new User({ UserModel: this.UserModel })
const editors = await userHelper.getEditorsInChief()
const { paragraph, ...bodyProps } = getEmailCopy({
comments,
titleText,
emailType: 'eic-manuscript-returned-by-eqa',
})
editors.forEach(eic => {
const email = new Email({
type: 'system',
toUser: {
email: eic.email,
},
fromEmail: `${journalName} <${staffEmail}>`,
content: {
subject: `${
this.collection.customId
}: Manuscript returned with comments`,
paragraph,
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: this.baseUrl,
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${this.collection.id}/versions/${
this.fragment.id
}/details`,
),
},
bodyProps,
Andrei Cioromila
committed
return email.sendEmail()
})
}
async _getNotificationProperties() {
const fragmentHelper = new Fragment({ fragment: this.fragment })
const parsedFragment = await fragmentHelper.getFragmentData({
handlingEditor: this.collection.handlingEditor,
})
const {
submittingAuthor,
activeAuthors,
} = await fragmentHelper.getAuthorData({
UserModel: this.UserModel,
const userHelper = new User({ UserModel: this.UserModel })
const eicName = await userHelper.getEiCName()
const titleText = `the manuscript titled "${parsedFragment.title}" by ${
submittingAuthor.firstName
} ${submittingAuthor.lastName}`
const { recommendation, recommendationType } = this.newRecommendation
return {
recommendation,
recommendationType,
eicName,
titleText,
submittingAuthor,
activeAuthors,
parsedFragment,
fragmentHelper,
}
}
module.exports = Notification