Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
helpers.js 12.32 KiB
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 { name: journalName, staffEmail } = config.get('journal')

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,
          token: reviewer.accessTokens.unsubscribe,
        },
      )
      const emailBodyProps = {
        paragraph: reviewer.paragraph,
        hasLink: reviewer.hasLink,
        hasIntro: reviewer.hasIntro,
        hasSignature: reviewer.hasSignature,
      }

      const { html, text } = email.getNotificationBody({ emailBodyProps })
      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
    email.fromEmail = `${signatureName} <$staffEmail>`
    return email
  },
  sendHandlingEditorEmail: ({
    email,
    comments,
    emailType,
    titleText,
    targetUserName,
  }) => {
    const { html, text } = email.getNotificationBody({
      emailBodyProps: getEmailCopy({
        emailType,
        titleText,
        comments,
        targetUserName,
      }),
    })
    email.sendEmail({ html, text })
  },
  updateEmailContentForHE: ({
    email,
    baseUrl,
    eicName,
    customId,
    heLastName,
    handlingEditor,
    recommendation,
    recommendationType,
  }) => {
    // TODO: this should probably be split in two functions, one for each type
    email.fromEmail = `${eicName} <${staffEmail}>`
    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,
        token: handlingEditor.accessTokens.unsubscribe,
      },
    )

    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
    email.fromEmail = `${journalName} <${staffEmail}>`
    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.getNotificationBody({
        emailBodyProps: {
          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,
          token: author.accessTokens.unsubscribe,
        },
      )
      const { html, text } = email.getNotificationBody({
        emailBodyProps: {
          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.fromEmail = `${signatureName} <${staffEmail}>`
    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,
        token: author.accessTokens.unsubscribe,
      },
    )
    const { html, text } = email.getNotificationBody({
      emailBodyProps: {
        paragraph: author.paragraph,
        hasLink: author.hasLink,
        hasIntro: author.hasIntro,
        hasSignature: author.hasSignature,
      },
    })
    email.sendEmail({ html, text })
  },
  updateEmailContentForAllAuthors: ({
    email,
    recommendation,
    customId,
    eicName,
  }) => {
    email.fromEmail = `${eicName} <${staffEmail}>`
    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,
    hasPeerReview,
  }) => {
    let emailType
    switch (recommendation) {
      case 'publish':
        emailType = 'author-manuscript-published'
        break
      case 'reject':
        emailType = hasPeerReview
          ? 'author-manuscript-rejected'
          : 'authors-manuscript-rejected-before-review'
        break
      default:
        throw new Error(`Undefined recommendation: ${recommendation}`)
    }

    return emailType
  },
  sendEQAEmail: ({
    email,
    eicName,
    baseUrl,
    titleText,
    collection,
    subjectBaseText,
  }) => {
    let emailType
    switch (collection.status) {
      case 'accepted':
        emailType = 'eqa-manuscript-published'
        email.content.subject = `${subjectBaseText} decision finalized`
        break
      case 'inQA':
        emailType = 'eqa-manuscript-request-for-approval'
        email.content.subject = `${subjectBaseText} Request for EQA Approval`
        email.content.ctaLink = services.createUrl(
          baseUrl,
          config.get('eqa-decision.url'),
          {
            collectionId: collection.id,
            customId: collection.customId,
            token: collection.technicalChecks.token,
          },
        )
        email.content.ctaText = 'MAKE DECISION'
        break
      default:
        throw new Error(
          `Cannot send EQA email when collection status is ${
            collection.status
          } `,
        )
    }

    email.toUser = {
      email: editorialAssistantEmail,
      name: 'Editorial Assistant',
    }

    email.content.unsubscribeLink = baseUrl
    email.content.signatureName = eicName

    const { html, text } = email.getNotificationBody({
      emailBodyProps: getEmailCopy({
        eicName,
        titleText,
        emailType,
        customId: collection.customId,
      }),
    })
    email.sendEmail({ html, text })
  },
}