Skip to content
Snippets Groups Projects
Collection.js 6.04 KiB
Newer Older
const { v4 } = require('uuid')
const logger = require('@pubsweet/logger')
const {
  findLast,
  isEmpty,
  maxBy,
  get,
  flatMap,
  last,
  has,
  set,
} = require('lodash')

class Collection {
  constructor({ collection = {} }) {
    this.collection = collection
  }

  async updateStatusByRecommendation({
    recommendation,
    isHandlingEditor = false,
  }) {
    let newStatus
    if (isHandlingEditor) {
      newStatus = 'pendingApproval'
      if (['minor', 'major'].includes(recommendation)) {
        newStatus = 'revisionRequested'
      }
    } else {
      if (recommendation === 'minor') {
        newStatus = this.hasAtLeastOneReviewReport(fragments)
          ? 'reviewCompleted'
          : 'heAssigned'
        newStatus = 'underReview'
    return this.updateStatus({ newStatus })
  }

  async updateStatus({ newStatus }) {
    this.collection.status = newStatus
    await this.collection.save()
  }

  async addHandlingEditor({ user, invitation }) {
    this.collection.handlingEditor = {
      id: user.id,
      name: `${user.firstName} ${user.lastName}`,
      invitedOn: invitation.invitedOn,
      respondedOn: invitation.respondedOn,
      email: user.email,
      hasAnswer: invitation.hasAnswer,
      isAccepted: invitation.isAccepted,
    }
    await this.updateStatus({ newStatus: 'heInvited' })
  }

  async updateHandlingEditor({ isAccepted }) {
    const { collection: { handlingEditor } } = this
    handlingEditor.hasAnswer = true
    handlingEditor.isAccepted = isAccepted
    handlingEditor.respondedOn = Date.now()

    const newStatus = isAccepted ? 'heAssigned' : 'submitted'

    await this.updateStatus({ newStatus })
  async updateStatusByNumberOfReviewers({ invitations }) {
    const reviewerInvitations = invitations.filter(
      inv => inv.role === 'reviewer',
    )
    if (reviewerInvitations.length === 0)
      await this.updateStatus({ newStatus: 'heAssigned' })
  }
    const [firstName, lastName] = this.collection.handlingEditor.name.split(' ')
    return lastName || firstName
  async getReviewerNumber({ userId }) {
    const allCollectionFragments = await this.collection.getFragments()
    const allCollectionInvitations = flatMap(
      allCollectionFragments,
      fragment => fragment.invitations,
    const allNumberedInvitationsForUser = allCollectionInvitations
    if (isEmpty(allNumberedInvitationsForUser)) {
      const maxReviewerNumber = get(
        maxBy(allCollectionInvitations, 'reviewerNumber'),
        'reviewerNumber',
        0,
      )
      return maxReviewerNumber + 1
    }
    return allNumberedInvitationsForUser[0].reviewerNumber
  }
  // eslint-disable-next-line class-methods-use-this
  hasAtLeastOneReviewReport(fragments) {
    return fragments.some(fragment =>
      new Fragment({ fragment }).hasReviewReport(),
    )
  }

  canHEMakeRecommendation(fragments, fragmentHelper) {
    if (this.collection.fragments.length === 1) {
      return fragmentHelper.hasReviewReport()
    }
    const previousVersionRecommendations = get(
      fragments[fragments.length - 2],
      'recommendations',
      [],
    )

    const lastEditorRecommendation = findLast(
      previousVersionRecommendations,
      recommendation =>
        recommendation.recommendationType === 'editorRecommendation',
    )

    if (lastEditorRecommendation.recommendation === 'minor') {
      return this.hasAtLeastOneReviewReport(fragments)
    } else if (
      ['major', 'revision'].includes(lastEditorRecommendation.recommendation)
    ) {

  async getAllFragments({ FragmentModel }) {
    return Promise.all(
      this.collection.fragments.map(async fragment =>
        FragmentModel.find(fragment),
      ),
    )
  }

  isLatestVersion(fragmentId) {
    return last(this.collection.fragments) === fragmentId
  }

  hasEQA() {
    const technicalChecks = get(this.collection, 'technicalChecks', {})
    return has(technicalChecks, 'eqa')
  }

  async setTechnicalChecks() {
    set(this.collection, 'technicalChecks.token', v4())
    set(this.collection, 'technicalChecks.eqa', false)
    await this.collection.save()
  }

  async sendToMTS({ FragmentModel, UserModel, fragmentHelper }) {
    await Promise.all(
      this.collection.fragments.map(async fragmentId => {
        const fragment = await FragmentModel.find(fragmentId)

        let fragmentUsers = []
        try {
          fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
            collection: this.collection,
            UserModel,
          })

          await sendMTSPackage({
            collection: this.collection,
            fragment,
            isEQA: true,
            fragmentUsers,
          })
        } catch (e) {
          logger.error(e)
        }
      }),
    ).catch(e => {
      throw new Error('Something went wrong.')
    })
  }

  async removeTechnicalChecks() {
    this.collection.technicalChecks = {}
    await this.collection.save()
  }

  hasHandlingEditor() {
    return has(this.collection, 'handlingEditor')
  }

  async addFragment(newFragmentId) {
    this.collection.fragments.push(newFragmentId)
    await this.collection.save()
  }
}

const sendMTSPackage = async ({
  fragment,
  collection,
  isEQA = false,
  fragmentUsers = [],
}) => {
  const s3Config = get(config, 'pubsweet-component-aws-s3', {})
  const mtsConfig = get(config, 'mts-service', {})
  const { sendPackage } = require('pubsweet-component-mts-package')

  const { journal, xmlParser, ftp } = mtsConfig
  const packageFragment = {
    ...fragment,
    metadata: {
      ...fragment.metadata,
      customId: collection.customId,
    },
  }

  await sendPackage({
    isEQA,
    s3Config,
    fragmentUsers,
    ftpConfig: ftp,
    config: journal,
    options: xmlParser,
    fragment: packageFragment,
  })