Skip to content
Snippets Groups Projects
post.js 7.86 KiB
Newer Older
const uuid = require('uuid')
const { pick, get, set, has, isEmpty, last } = require('lodash')
const { v4 } = require('uuid')
const logger = require('@pubsweet/logger')
} = require('pubsweet-component-helper-service')
const { features = {}, recommendations } = config
const Notification = require('../../notifications/notification')
module.exports = models => async (req, res) => {
  const { recommendation, comments, recommendationType } = req.body
  if (!services.checkForUndefinedParams(recommendationType))
    return res.status(400).json({ error: 'Recommendation type is required.' })

  const reqUser = await models.User.find(req.user)
  const isEditorInChief = reqUser.editorInChief || reqUser.admin

  const { collectionId, fragmentId } = req.params
  try {
    collection = await models.Collection.find(collectionId)
    if (!collection.fragments.includes(fragmentId))
      return res.status(400).json({
Sebastian Mihalache's avatar
Sebastian Mihalache committed
        error: `Collection and fragment do not match.`,
      })
    fragment = await models.Fragment.find(fragmentId)
  } catch (e) {
    const notFoundError = await services.handleNotFoundError(e, 'Item')
    return res.status(notFoundError.status).json({
      error: notFoundError.message,
    })
  }
Sebastian Mihalache's avatar
Sebastian Mihalache committed

  const collectionHelper = new Collection({ collection })

  try {
    fragments = await Promise.all(
      collection.fragments.map(
        async fragment => await models.Fragment.find(fragment),
      ),
    )
  } catch (e) {
    const notFoundError = await services.handleNotFoundError(e, 'Item')
    fragments = []
    return res.status(notFoundError.status).json({
      error: notFoundError.message,
    })
  }
  const currentUserRecommendation = get(fragment, 'recommendations', []).filter(
    r => r.userId === req.user,
  )
  const authsome = authsomeHelper.getAuthsome(models)
  const target = {
    path: req.route.path,
  }
  const canPost = await authsome.can(req.user, 'POST', target)
  if (!canPost)
    return res.status(403).json({
      error: 'Unauthorized.',
    })
Sebastian Mihalache's avatar
Sebastian Mihalache committed

  const fragmentHelper = new Fragment({ fragment })
    recommendationType === recommendations.type.editor &&
    last(collection.fragments) !== fragmentId
  ) {
    return res
      .status(400)
      .json({ error: 'Cannot make a recommendation on an older version.' })
  }

  if (
    recommendationType === recommendations.type.review &&
    last(collection.fragments) !== fragmentId
  ) {
    return res
      .status(400)
      .json({ error: 'Cannot write a review on an older version.' })
  }
    last(collection.fragments) === fragmentId &&
    if (recommendationType === recommendations.type.review) {
      return res
        .status(400)
        .json({ error: 'Cannot write another review on this version.' })
      .json({ error: 'Cannot make another recommendation on this version.' })
  if (
    recommendation === recommendations.publish &&
    recommendationType === recommendations.type.editor &&
    collection.handlingEditor &&
    collection.handlingEditor.id === req.user
  ) {
    if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
Anca Ursachi's avatar
Anca Ursachi committed
      return res.status(400).json({
        error: 'Cannot publish without at least one reviewer report.',
      })
  fragment.recommendations = fragment.recommendations || []
  const newRecommendation = {
    id: uuid.v4(),
    userId: reqUser.id,
    createdOn: Date.now(),
    updatedOn: Date.now(),
Sebastian Mihalache's avatar
Sebastian Mihalache committed

  newRecommendation.recommendation = recommendation || undefined
  newRecommendation.comments = comments || undefined
  if (recommendationType === 'editorRecommendation') {
    collectionHelper.updateStatusOnRecommendation({
      isEditorInChief,
      recommendation,
    })

    if (!isEditorInChief && ['minor', 'major'].includes(recommendation)) {
      fragment.revision = pick(fragment, ['authors', 'files', 'metadata'])
    }

    const technicalChecks = get(collection, 'technicalChecks', {})
    const hasEQA = has(technicalChecks, 'eqa')
    // the manuscript has not yet passed through the EQA process so we need to upload it to the FTP server
    if (isEditorInChief && recommendation === 'publish' && !hasEQA) {
      if (features.mts) {
        await Promise.all(
          collection.fragments.map(async fragmentId => {
            const fragment = await models.Fragment.find(fragmentId)
            const fragmentHelper = new Fragment({ fragment })

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

              await sendMTSPackage({
                collection,
                fragment,
                isEQA: true,
                fragmentUsers,
              })
            } catch (e) {
              logger.error(e)
            }
          }),
        ).catch(e =>
          res.status(500).json({
            error: 'Something went wrong.',
          }),
        )
      collection.status = 'inQA'
      set(collection, 'technicalChecks.token', v4())
      set(collection, 'technicalChecks.eqa', false)
    /* if the EiC returns the manuscript to the HE after the EQA has been performed
       then remove all properties from the technicalChecks property so that the manuscript
       can go through the EQA process again
    */
    if (
      isEditorInChief &&
      recommendation === 'return-to-handling-editor' &&
    ) {
      collection.technicalChecks = {}
      await collection.save()
    }

      fragment,
      collection,
      newRecommendation,
      UserModel: models.User,
      baseUrl: services.getBaseUrl(req),
    const hasPeerReview = !isEmpty(collection.handlingEditor)
      if (recommendation === 'publish' && collection.status === 'inQA') {
        notification.notifyEAWhenEiCRequestsEQAApproval()
      }

      if (recommendation === 'publish' && collection.status === 'accepted') {
        notification.notifyEAWhenEiCMakesFinalDecision()
      if (hasPeerReview && (recommendation !== 'publish' || hasEQA)) {
        if (recommendation === 'return-to-handling-editor') {
          notification.notifyHEWhenEiCReturnsToHE()
        } else {
          notification.notifyHEWhenEiCMakesDecision()
          notification.notifyReviewersWhenEiCMakesDecision()
        }
      }
      if (
        recommendation !== 'return-to-handling-editor' &&
        (recommendation !== 'publish' || hasEQA)
      ) {
        notification.notifyAuthorsWhenEiCMakesDecision()
      if (collection.status === 'revisionRequested') {
        notification.notifySAWhenHERequestsRevision()
      }
      if (hasPeerReview) {
        notification.notifyReviewersWhenHEMakesRecommendation()
        notification.notifyEiCWhenHEMakesRecommendation()
  fragment.recommendations.push(newRecommendation)
  return res.status(200).json(newRecommendation)
}
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,
    ftpConfig: ftp,
    config: journal,
    options: xmlParser,
    fragment: packageFragment,
  })
}