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, ) 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 (lastEditorRecommendation.recommendation === 'major') { 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