-
Tania Fecheta authored5a13c7ee
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
const config = require('config')
const { v4 } = require('uuid')
const logger = require('@pubsweet/logger')
const {
findLast,
isEmpty,
maxBy,
get,
flatMap,
last,
has,
set,
} = require('lodash')
const Fragment = require('./Fragment')
class Collection {
constructor({ collection = {} }) {
this.collection = collection
}
async updateStatusByRecommendation({
recommendation,
isHandlingEditor = false,
fragments,
}) {
let newStatus
if (isHandlingEditor) {
newStatus = 'pendingApproval'
if (['minor', 'major'].includes(recommendation)) {
newStatus = 'revisionRequested'
}
} else {
if (recommendation === 'minor') {
newStatus = this.hasAtLeastOneReviewReport(fragments)
? 'reviewCompleted'
: 'heAssigned'
}
if (recommendation === 'major') {
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' })
}
getHELastName() {
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,
).filter(Boolean)
const allNumberedInvitationsForUser = allCollectionInvitations
.filter(invite => invite.userId === userId)
.filter(invite => invite.reviewerNumber)
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)
) {
return fragmentHelper.hasReviewReport()
}
return false
}
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,
})
}
module.exports = Collection