diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js index 34004073c406e0772e9ea95b4279de08db844a09..48e7b41cec509a81de2695019f5a5f0067cd57c7 100644 --- a/packages/component-fixture-manager/src/fixtures/fragments.js +++ b/packages/component-fixture-manager/src/fixtures/fragments.js @@ -532,17 +532,9 @@ fragments.noInvitesFragment = { invites: [], id: chance.guid(), } -fragments.noInvitesFragment = { - ...fragments.fragment1, - recommendations: [], - invites: [], - id: chance.guid(), -} - fragments.noInvitesFragment1 = { ...fragments.fragment, recommendations: [], - invites: [], id: chance.guid(), } fragments.minorRevisionWithoutReview = { diff --git a/packages/component-helper-service/src/services/Collection.js b/packages/component-helper-service/src/services/Collection.js index 70efac8ded420595e62bc16fa271b90a74fb741d..6e05d9a584f61eddc5a63a7ad309ac81bea1edb6 100644 --- a/packages/component-helper-service/src/services/Collection.js +++ b/packages/component-helper-service/src/services/Collection.js @@ -10,6 +10,7 @@ class Collection { async updateStatusByRecommendation({ recommendation, isHandlingEditor = false, + fragments, }) { let newStatus if (isHandlingEditor) { @@ -19,7 +20,9 @@ class Collection { } } else { if (recommendation === 'minor') { - newStatus = 'reviewCompleted' + newStatus = this.hasAtLeastOneReviewReport(fragments) + ? 'reviewCompleted' + : 'heAssigned' } if (recommendation === 'major') { @@ -27,7 +30,7 @@ class Collection { } } - this.updateStatus({ newStatus }) + return this.updateStatus({ newStatus }) } async updateFinalStatusByRecommendation({ recommendation }) { @@ -89,18 +92,16 @@ class Collection { async updateStatusOnRecommendation({ isEditorInChief, recommendation }) { if (isEditorInChief) { if (recommendation === 'return-to-handling-editor') { - this.updateStatus({ newStatus: 'reviewCompleted' }) - } else { - this.updateFinalStatusByRecommendation({ - recommendation, - }) + return this.updateStatus({ newStatus: 'reviewCompleted' }) } - } else { - this.updateStatusByRecommendation({ + return this.updateFinalStatusByRecommendation({ recommendation, - isHandlingEditor: true, }) } + return this.updateStatusByRecommendation({ + recommendation, + isHandlingEditor: true, + }) } getHELastName() { @@ -137,6 +138,14 @@ class Collection { return fragmentHelper.hasReviewReport() } } + + async getAllFragments({ FragmentModel }) { + return Promise.all( + this.collection.fragments.map(async fragment => + FragmentModel.find(fragment), + ), + ) + } } module.exports = Collection diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js index 1c294af21f0a50bc14fbe9de6ab254134f0c708d..7a0f27ae03d656269c6e5c757c094dd083f1ddb8 100644 --- a/packages/component-helper-service/src/services/Fragment.js +++ b/packages/component-helper-service/src/services/Fragment.js @@ -145,7 +145,7 @@ class Fragment { hasReviewReport() { const { fragment: { recommendations = [] } } = this - return recommendations.find( + return recommendations.some( rec => rec.recommendationType === 'review' && rec.submittedOn, ) } diff --git a/packages/component-helper-service/src/tests/collection.test.js b/packages/component-helper-service/src/tests/collection.test.js new file mode 100644 index 0000000000000000000000000000000000000000..41c9f0ed6481079f790df50fc83584af62f2d1c4 --- /dev/null +++ b/packages/component-helper-service/src/tests/collection.test.js @@ -0,0 +1,180 @@ +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' +process.env.SUPPRESS_NO_CONFIG_WARNING = true + +const { cloneDeep } = require('lodash') +const fixturesService = require('pubsweet-component-fixture-service') + +const { fixtures, Model } = fixturesService +const { Collection, Fragment } = require('../Helper') + +describe('Collection helper', () => { + let testFixtures = {} + let models + beforeEach(() => { + testFixtures = cloneDeep(fixtures) + models = Model.build(testFixtures) + }) + + describe('hasAtLeastOneReviewReport', () => { + it('should return true if collection has at least one report from reviewers.', async () => { + const { collection } = testFixtures.collections + const collectionHelper = new Collection({ collection }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const hasReviewReport = await collectionHelper.hasAtLeastOneReviewReport( + fragments, + ) + expect(hasReviewReport).toBe(true) + }) + it('should return false if collection has at least one report from reviewers.', async () => { + const { noInvitesFragment } = testFixtures.fragments + const { collection } = testFixtures.collections + collection.fragments = [noInvitesFragment.id] + const collectionHelper = new Collection({ collection }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const hasReviewReport = await collectionHelper.hasAtLeastOneReviewReport( + fragments, + ) + expect(hasReviewReport).toBe(false) + }) + }) + + describe('canHEMakeRecommendation', () => { + it('should return true when creating a recommendation as a HE when there is a single version with at least one review.', async () => { + const { collection } = testFixtures.collections + const { fragment } = testFixtures.fragments + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ fragment }) + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(true) + }) + it('should return false when creating a recommendation with publish as a HE when there is a single version and there are no reviews.', async () => { + const { collection } = testFixtures.collections + const { fragment } = testFixtures.fragments + fragment.recommendations = undefined + + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ fragment }) + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(false) + }) + it('should return true when creating a recommendation as a HE after minor revision and we have at least one review on collection.', async () => { + const { collection } = testFixtures.collections + const { + minorRevisionWithReview, + noInvitesFragment1, + } = testFixtures.fragments + collection.fragments = [minorRevisionWithReview.id, noInvitesFragment1.id] + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ fragment: noInvitesFragment1 }) + + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(true) + }) + it('should return false when creating a recommendation as a HE after minor revision and there are no reviews.', async () => { + const { collection } = testFixtures.collections + const { + minorRevisionWithoutReview, + noInvitesFragment1, + } = testFixtures.fragments + collection.fragments = [ + minorRevisionWithoutReview.id, + noInvitesFragment1.id, + ] + + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ noInvitesFragment1 }) + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(false) + }) + it('should return true when creating a recommendation as a HE after major revision and there are least one review on fragment.', async () => { + const { collection } = testFixtures.collections + const { + majorRevisionWithReview, + reviewCompletedFragment, + } = testFixtures.fragments + + reviewCompletedFragment.collectionId = collection.id + collection.fragments = [ + majorRevisionWithReview.id, + reviewCompletedFragment.id, + ] + + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ fragment: reviewCompletedFragment }) + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(true) + }) + it('should return false when creating a recommendation as a HE after major revision there are no reviews on fragment.', async () => { + const { collection } = testFixtures.collections + const { + majorRevisionWithReview, + noInvitesFragment1, + } = testFixtures.fragments + collection.fragments = [majorRevisionWithReview.id, noInvitesFragment1.id] + const collectionHelper = new Collection({ + collection, + }) + const FragmentModel = models.Fragment + const fragments = await collectionHelper.getAllFragments({ + FragmentModel, + }) + const fragmentHelper = new Fragment({ fragment: noInvitesFragment1 }) + const canHEMakeRecommendation = await collectionHelper.canHEMakeRecommendation( + fragments, + fragmentHelper, + ) + expect(canHEMakeRecommendation).toBe(false) + }) + }) +}) diff --git a/packages/component-invite/src/routes/fragmentsInvitations/post.js b/packages/component-invite/src/routes/fragmentsInvitations/post.js index 1a441531473daef14c295e408fc86e7d57fed96d..0e45b83faac29aef7b05b2ca588cf07b6dc7fb0e 100644 --- a/packages/component-invite/src/routes/fragmentsInvitations/post.js +++ b/packages/component-invite/src/routes/fragmentsInvitations/post.js @@ -4,6 +4,7 @@ const { services, Collection, Invitation, + Fragment, authsome: authsomeHelper, } = require('pubsweet-component-helper-service') @@ -116,7 +117,12 @@ module.exports = models => async (req, res) => { }) } - if (collection.status === 'heAssigned') { + const fragmentHelper = new Fragment({ fragment }) + if ( + collection.status === 'heAssigned' || + (collection.status === 'reviewCompleted' && + !fragmentHelper.hasReviewReport()) + ) { collectionHelper.updateStatus({ newStatus: 'reviewersInvited' }) } diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js index 396672ff07542005238642045ebe226e45d8fa3c..acd037254ddb9ada6417d99980a2a30588799d08 100644 --- a/packages/component-manuscript-manager/src/routes/fragments/patch.js +++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js @@ -103,8 +103,13 @@ module.exports = models => async (req, res) => { await authorsTeam.save() } - collectionHelper.updateStatusByRecommendation({ + const fragments = await collectionHelper.getAllFragments({ + FragmentModel: models.Fragment, + }) + + await collectionHelper.updateStatusByRecommendation({ recommendation: heRecommendation.recommendation, + fragments, }) newFragment.submitted = Date.now() diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js index 6221128db3ad56a31f659d1294051313ebbf7cd1..41cf22755681413e2d34e03473804a48e9daf1d1 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js @@ -1,4 +1,3 @@ -/* eslint-disable no-return-await */ const uuid = require('uuid') const { pick, get, set, has, isEmpty, last } = require('lodash') const config = require('config') @@ -45,11 +44,9 @@ module.exports = models => async (req, res) => { const collectionHelper = new Collection({ collection }) try { - fragments = await Promise.all( - collection.fragments.map( - async fragment => await models.Fragment.find(fragment), - ), - ) + fragments = await collectionHelper.getAllFragments({ + FragmentModel: models.Fragment, + }) } catch (e) { const notFoundError = await services.handleNotFoundError(e, 'Item') fragments = [] @@ -149,7 +146,7 @@ module.exports = models => async (req, res) => { newRecommendation.comments = comments || undefined if (recommendationType === 'editorRecommendation') { - collectionHelper.updateStatusOnRecommendation({ + await collectionHelper.updateStatusOnRecommendation({ isEditorInChief, recommendation, })