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()
}

Mihail Hagiu
committed
async notifySAWhenEiCRequestsRevision() {
const {
eicName,
submittingAuthor,
titleText,
} = await this._getNotificationProperties()
const authorNoteText = helpers.getPrivateNoteTextForAuthor({
newRecommendation: this.newRecommendation,
})
const { paragraph, ...bodyProps } = getEmailCopy({

Mihail Hagiu
committed
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
titleText,
comments: authorNoteText,
})
const email = new Email({
type: 'user',
toUser: {
email: submittingAuthor.email,
name: submittingAuthor.lastName,
},
fromEmail: `${eicName} <${staffEmail}>`,
content: {
subject: `${this.collection.customId}: Revision requested`,
paragraph,
signatureName: eicName,
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,
})
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
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
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()
})
}
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
async notifyReviewersWhenAuthorSubmitsMajorRevision(newFragmentId) {
const { fragmentHelper } = await this._getNotificationProperties()
const { collection, UserModel } = this
const handlingEditor = get(collection, 'handlingEditor')
const parsedFragment = await fragmentHelper.getFragmentData({
handlingEditor,
})
const reviewers = await fragmentHelper.getReviewers({
UserModel,
type: 'submitted',
})
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'submitted-reviewers-after-revision',
titleText: `the manuscript titled "${parsedFragment.title}"`,
expectedDate: services.getExpectedDate({ daysExpected: 14 }),
})
reviewers.forEach(reviewer => {
const email = new Email({
type: 'user',
fromEmail: `${handlingEditor.name} <${staffEmail}>`,
toUser: {
email: reviewer.email,
name: `${reviewer.lastName}`,
},
content: {
subject: `${
collection.customId
}: A manuscript you reviewed has been revised`,
paragraph,
signatureName: handlingEditor.name,
signatureJournal: journalName,
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${collection.id}/versions/${newFragmentId}/details`,
),
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: reviewer.id,
token: reviewer.accessTokens.unsubscribe,
}),
},
bodyProps,
})
return email.sendEmail()
})
}
async notifyHandlingEditorWhenAuthorSubmitsRevision(newFragment) {
const { collection, UserModel } = this
const handlingEditor = get(collection, 'handlingEditor')
const fragmentHelper = new Fragment({ fragment: newFragment })
const parsedFragment = await fragmentHelper.getFragmentData({
handlingEditor,
})
const { paragraph, ...bodyProps } = getEmailCopy({
emailType: 'he-new-version-submitted',
titleText: `the manuscript titled "${parsedFragment.title}"`,
})
const heUser = await UserModel.find(handlingEditor.id)
const email = new Email({
type: 'user',
fromEmail: `${journalName} <${staffEmail}>`,
toUser: {
email: heUser.email,
},
content: {
subject: `${collection.customId}: Revision submitted`,
paragraph,
signatureName: '',
signatureJournal: journalName,
ctaLink: services.createUrl(
this.baseUrl,
`/projects/${collection.id}/versions/${newFragment.id}/details`,
),
ctaText: 'MANUSCRIPT DETAILS',
unsubscribeLink: services.createUrl(this.baseUrl, unsubscribeSlug, {
id: heUser.id,
token: heUser.accessTokens.unsubscribe,
}),
},
bodyProps,
})
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