Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
delete.js 5.07 KiB
const config = require('config')

const {
  Team,
  Fragment,
  services,
  authsome: authsomeHelper,
} = require('pubsweet-component-helper-service')
const {
  deleteFilesS3,
} = require('pubsweet-component-mts-package/src/PackageManager')

const Job = require('pubsweet-component-jobs')

const { last, get, chain, difference } = require('lodash')

const s3Config = get(config, 'pubsweet-component-aws-s3', {})

const notifications = require('./emails/notifications')

module.exports = models => async (req, res) => {
  const { collectionId, invitationId } = req.params
  const teamHelper = new Team({ TeamModel: models.Team, collectionId })

  try {
    const collection = await models.Collection.find(collectionId)

    const authsome = authsomeHelper.getAuthsome(models)
    const target = {
      collection,
      path: req.route.path,
    }
    const canDelete = await authsome.can(req.user, 'DELETE', target)
    if (!canDelete)
      return res.status(403).json({
        error: 'Unauthorized.',
      })

    collection.invitations = collection.invitations || []
    const invitation = collection.invitations.find(
      invitation => invitation.id === invitationId,
    )
    if (!invitation)
      return res.status(404).json({
        error: `Invitation ${invitationId} not found`,
      })

    const team = await teamHelper.getTeam({
      role: invitation.role,
      objectType: 'collection',
    })

    collection.invitations = collection.invitations.filter(
      inv => inv.id !== invitation.id,
    )

    collection.status = 'submitted'
    delete collection.handlingEditor
    await collection.save()

    await teamHelper.removeTeamMember({
      teamId: team.id,
      userId: invitation.userId,
    })

    const UserModel = models.User
    const user = await UserModel.find(invitation.userId)
    user.teams = user.teams.filter(userTeamId => team.id !== userTeamId)
    await user.save()
    if (invitation.hasAnswer && invitation.isAccepted) {
      const FragmentModel = models.Fragment
      const fragment = await FragmentModel.find(
        last(get(collection, 'fragments', [])),
      )
      const fragmentHelper = new Fragment({ fragment })

      const fragmentId = fragment.id
      const teamHelperForFragment = new Team({
        TeamModel: models.Team,
        collectionId,
        fragmentId,
      })

      const teams = await teamHelperForFragment.getTeams('fragment')
      const reviewerTeam = teams.find(
        team => team.object.id === fragmentId && team.group === 'reviewer',
      )
      if (reviewerTeam) {
        reviewerTeam.delete()
      }

      const fileKeys = []
      fragment.recommendations &&
        fragment.recommendations.forEach(recommendation => {
          recommendation.comments.forEach(comment => {
            comment.files &&
              comment.files.forEach(file => {
                fileKeys.push(file.id)
              })
          })
        })

      const revision = get(fragment, 'revision', false)
      if (revision) {
        const fragmentFilesIds = chain(get(fragment, 'files', []))
          .flatMap(item => item)
          .map(item => item.id)
          .value()
        const revisionFilesIds = chain(get(fragment, 'revision.files', []))
          .flatMap(item => item)
          .map(item => item.id)
          .value()
        const revisionFileIds = difference(revisionFilesIds, fragmentFilesIds)
        fileKeys.concat(revisionFileIds)
      }
      if (fileKeys.length > 1) {
        await deleteFilesS3({ fileKeys, s3Config })
      }

      let shouldAuthorBeNotified
      if (fragment.invitations.length > 0) {
        shouldAuthorBeNotified = true
      }

      const reviewers = [
        ...(await fragmentHelper.getReviewers({
          UserModel,
          type: 'accepted',
        })),
        ...(await fragmentHelper.getReviewers({
          UserModel,
          type: 'submitted',
        })),
      ]

      fragment.invitations.forEach(inv => {
        Job.cancelQueue(`removal-${inv.userId}-${inv.id}`)
        Job.cancelQueue(`reminders-${inv.userId}-${inv.id}`)
      })

      fragment.invitations = []
      fragment.recommendations = []
      fragment.revision && delete fragment.revision
      await fragment.save()

      notifications.notifyInvitedHEWhenRemoved({
        models,
        collection,
        invitedHE: user,
        baseUrl: services.getBaseUrl(req),
      })

      notifications.notifyReviewersWhenHERemoved({
        models,
        collection,
        reviewers,
        baseUrl: services.getBaseUrl(req),
      })

      if (shouldAuthorBeNotified) {
        notifications.notifyAuthorWhenHERemoved({
          models,
          collection,
          baseUrl: services.getBaseUrl(req),
        })
      }
    } else {
      notifications.sendInvitedHEEmail({
        models,
        collection,
        invitedHE: user,
        isCanceled: true,
        baseUrl: services.getBaseUrl(req),
      })
    }

    return res.status(200).json({})
  } catch (e) {
    const notFoundError = await services.handleNotFoundError(e, 'Collection')
    return res.status(notFoundError.status).json({
      error: notFoundError.message,
    })
  }
}