Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
index.js 7.77 KiB
import { get, has, last, chain } from 'lodash'
import { selectCurrentUser } from 'xpub-selectors'

export const isHEToManuscript = (state, collectionId) => {
  const currentUserId = get(state, 'currentUser.user.id', '')
  const collections = get(state, 'collections', [])
  const collection = collections.find(c => c.id === collectionId) || {}
  return get(collection, 'handlingEditor.id') === currentUserId
}

export const currentUserIs = ({ currentUser: { user } }, role) => {
  const isAdmin = get(user, 'admin')
  const isEic = get(user, 'editorInChief')
  const isHe = get(user, 'handlingEditor')
  switch (role) {
    case 'isHE':
      return isHe
    case 'staff':
      return isAdmin || isEic || isHe
    case 'isEiC':
      return isEic
    case 'isAdmin':
      return isAdmin
    case 'adminEiC':
      return isAdmin || isEic
    default:
      return false
  }
}

const cannotInviteReviewersStatuses = ['draft', 'rejected', 'published']
export const canInviteReviewers = (state, collection) => {
  if (
    cannotInviteReviewersStatuses.includes(get(collection, 'status', 'draft'))
  )
    return false

  const user = selectCurrentUser(state)
  const isStaff = currentUserIs(state, 'isAdmin')
  const { isAccepted, id: heId } = get(collection, 'handlingEditor', {})

  return isAccepted && (user.id === heId || isStaff)
}

export const getUserToken = ({ currentUser }) =>
  get(currentUser, 'user.token', '')

export const getHERecommendation = (state, collectionId, fragmentId) => {
  const heId = chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .get('handlingEditor.id', '')
    .value()

  return (
    chain(state)
      .get(`fragments.${fragmentId}.recommendations`, [])
      .find(r => r.rec === 'editorRecommendation' && r.userId === heId)
      .value() || {}
  )
}

const canMakeDecisionStatuses = ['submitted', 'pendingApproval']
export const canMakeDecision = (state, collection, fragment = {}) => {
  if (fragment.id !== last(get(collection, 'fragments', []))) return false
  const status = get(collection, 'status', 'draft')

  const isEIC = currentUserIs(state, 'adminEiC')
  return isEIC && canMakeDecisionStatuses.includes(status)
}

const canEditManuscriptStatuses = ['draft', 'technicalChecks', 'inQA']
export const canEditManuscript = (state, collection, fragment = {}) => {
  const isAdmin = currentUserIs(state, 'isAdmin')
  if (!isAdmin || fragment.id !== last(get(collection, 'fragments', [])))
    return false
  const status = get(collection, 'status', 'draft')

  return canEditManuscriptStatuses.includes(status)
}

const canOverrideTechnicalChecksStatuses = ['technicalChecks', 'inQA']
export const canOverrideTechnicalChecks = (state, collection) => {
  const isAdmin = currentUserIs(state, 'isAdmin')
  if (!isAdmin) return false
  const status = get(collection, 'status', 'draft')

  return canOverrideTechnicalChecksStatuses.includes(status)
}

export const canViewReports = (state, collectionId) => {
  const isHE = isHEToManuscript(state, collectionId)
  const isEiC = currentUserIs(state, 'adminEiC')
  return isHE || isEiC
}

export const canMakeRevision = (state, collection, fragment) => {
  const currentUserId = get(state, 'currentUser.user.id')
  return (
    get(fragment, 'revision') &&
    collection.status === 'revisionRequested' &&
    fragment.owners.map(o => o.id).includes(currentUserId)
  )
}

export const currentUserIsAuthor = (state, id) => {
  const permissions = getUserPermissions(state)

  return permissions
    .filter(f => f.role === 'author')
    .map(p => p.objectId)
    .includes(id)
}

export const getUserPermissions = ({ currentUser }) =>
  get(currentUser, 'user.teams', []).map(t => ({
    objectId: t.object.id,
    objectType: t.object.type,
    role: t.teamType.permissions,
  }))

export const userNotConfirmed = ({ currentUser }) =>
  get(currentUser, 'isAuthenticated') &&
  !currentUserIs({ currentUser }, 'staff') &&
  !get(currentUser, 'user.isConfirmed')

export const pendingReviewerInvitation = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.invitations`, [])
    .find(
      inv =>
        inv.userId === get(state, 'currentUser.user.id', '') &&
        !inv.hasAnswer &&
        inv.role === 'reviewer',
    )
    .value()

export const currentUserIsReviewer = (state, fragmentId) => {
  const currentUser = selectCurrentUser(state)
  const invitations = get(state, `fragments.${fragmentId}.invitations`, [])
  return !!invitations.find(
    i =>
      i.userId === currentUser.id &&
      i.role === 'reviewer' &&
      i.hasAnswer &&
      i.isAccepted,
  )
}

export const getAdminUsers = state =>
  chain(state)
    .get('users.users')
    .map(u => {
      let sortValue = -1
      if (u.isActive) sortValue = 1
      if (!u.isConfirmed) sortValue = 0
      return {
        user: u,
        sortValue,
      }
    })
    .sortBy('sortValue')
    .map(s => s.user)
    .reverse()
    .value()

export const pendingHEInvitation = (state, collectionId) =>
  chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .get('invitations', [])
    .find(
      i =>
        i.userId === get(state, 'currentUser.user.id', '') &&
        i.role === 'handlingEditor' &&
        !i.hasAnswer,
    )
    .value()

const parseInvitedHE = (handlingEditor, state, collectionId) =>
  handlingEditor && {
    ...handlingEditor,
    name: pendingHEInvitation(state, collectionId)
      ? 'Invited'
      : handlingEditor.name,
  }

const hideCustomIdStatuses = ['draft', 'technicalChecks']

export const parseCollectionDetails = (state, collection = {}) => ({
  ...collection,
  customId:
    !hideCustomIdStatuses.includes(get(collection, 'status', 'draft')) &&
    collection.customId,
  handlingEditor: parseInvitedHE(
    collection.handlingEditor,
    state,
    collection.id,
  ),
})

export const newestFirstParseDashboard = (state = {}) =>
  chain(state.collections)
    .orderBy(['created'], ['desc'])
    .map(item => parseCollectionDetails(state, item))
    .value()

export const getInvitationsWithReviewersForFragment = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.invitations`, [])
    .filter(invitation => invitation.role === 'reviewer')
    .map(invitation => ({
      ...invitation,
      person: get(state, 'users.users', []).find(
        reviewer => reviewer.id === invitation.userId,
      ),
    }))
    .value()

// #region Editorial and reviewer recommendations
export const getFragmentRecommendations = (state, fragmentId) =>
  get(state, `fragments.${fragmentId}.recommendations`, [])

export const getFragmentReviewerRecommendations = (state, fragmentId) =>
  getFragmentRecommendations(state, fragmentId).filter(
    r => r.recommendationType === 'review',
  )

const getOwnRecommendations = (state, fragmentId) =>
  chain(state)
    .get(`fragments.${fragmentId}.recommendations`, [])
    .filter(r => r.userId === get(state, 'currentUser.user.id', ''))
    .value()

export const getOwnPendingRecommendation = (state, fragmentId) =>
  chain(getOwnRecommendations(state, fragmentId))
    .find(
      r =>
        r.userId === get(state, 'currentUser.user.id', '') &&
        !has(r, 'submittedOn'),
    )
    .value()

export const getOwnSubmittedRecommendation = (state, fragmentId) =>
  chain(getOwnRecommendations(state, fragmentId))
    .find(
      r =>
        r.userId === get(state, 'currentUser.user.id', '') &&
        has(r, 'submittedOn'),
    )
    .value()

const canMakeRecommendationStatuses = [
  'heAssigned',
  'underReview',
  'reviewCompleted',
]
export const canMakeRecommendation = (state, collection, fragment = {}) => {
  if (fragment.id !== last(get(collection, 'fragments', []))) return false
  const isHE = isHEToManuscript(state, get(collection, 'id', ''))
  const status = get(collection, 'status', 'draft')
  return isHE && canMakeRecommendationStatuses.includes(status)
}
// #endregion