diff --git a/packages/component-fixture-manager/src/fixtures/collections.js b/packages/component-fixture-manager/src/fixtures/collections.js index 444a73674f7de665c2228f5540c40de491754ad8..fd83ed23b1d978e33a686785f14d08b64ea8d34c 100644 --- a/packages/component-fixture-manager/src/fixtures/collections.js +++ b/packages/component-fixture-manager/src/fixtures/collections.js @@ -1,6 +1,6 @@ const Chance = require('chance') const { user, handlingEditor, answerHE } = require('./userData') -const { fragment } = require('./fragments') +const { fragment, reviewCompletedFragment } = require('./fragments') const { standardCollID } = require('./collectionIDs') const chance = new Chance() @@ -89,6 +89,36 @@ const collections = { }, status: 'pendingApproval', }, + collectionReviewCompleted: { + type: 'collection', + owners: [user.id], + status: 'reviewCompleted', + created: chance.timestamp(), + customId: '0000001', + fragments: [reviewCompletedFragment.id], + invitations: [ + { + id: chance.guid(), + role: 'handlingEditor', + type: 'invitation', + userId: handlingEditor.id, + hasAnswer: true, + invitedOn: chance.timestamp(), + isAccepted: true, + respondedOn: chance.timestamp(), + }, + ], + handlingEditor: { + id: handlingEditor.id, + name: handlingEditor.name, + email: handlingEditor.email, + hasAnswer: true, + invitedOn: chance.timestamp(), + isAccepted: true, + respondedOn: chance.timestamp(), + }, + technicalChecks: {}, + }, } module.exports = collections diff --git a/packages/component-fixture-manager/src/fixtures/fragments.js b/packages/component-fixture-manager/src/fixtures/fragments.js index 4efbe9b38ed5e07754ecb38fe86f277cb73744d5..719d65b46ac17088cd5932d6610fda53d6cdd8ef 100644 --- a/packages/component-fixture-manager/src/fixtures/fragments.js +++ b/packages/component-fixture-manager/src/fixtures/fragments.js @@ -171,6 +171,112 @@ const fragments = { owners: [user.id], type: 'fragment', }, + reviewCompletedFragment: { + id: chance.guid(), + type: 'fragment', + files: { + coverLetter: [], + manuscripts: [ + { + id: + '28ca8f73-2dcb-4a93-97c9-24d474d54691/a1107517-1d19-445d-90ee-315a026469c4', + name: 'LinkedInProfileDemystified.pdf', + size: 804871, + originalName: 'LinkedInProfileDemystified.pdf', + }, + ], + supplementary: [], + }, + owners: [user.id], + authors: [ + { + id: user.id, + email: user.email, + title: user.title, + lastName: user.lastName, + firstName: user.firstName, + affiliation: user.affiliation, + isSubmitting: true, + isCorresponding: true, + }, + ], + created: '2018-10-08T12:01:46.384Z', + version: 1, + metadata: { + type: 'research', + title: chance.sentence(), + journal: 'Bioinorganic Chemistry and Applications', + abstract: chance.paragraph(), + }, + conflicts: { + hasFunding: 'yes', + hasConflicts: 'no', + hasDataAvailability: 'yes', + }, + submitted: 1539000486993, + invitations: [ + { + id: chance.guid(), + role: 'reviewer', + type: 'invitation', + userId: answerReviewer.id, + hasAnswer: true, + invitedOn: chance.timestamp(), + isAccepted: true, + respondedOn: chance.timestamp(), + }, + { + id: chance.guid(), + role: 'reviewer', + type: 'invitation', + userId: recReviewer.id, + hasAnswer: false, + invitedOn: chance.timestamp(), + isAccepted: false, + respondedOn: null, + }, + { + id: chance.guid(), + role: 'reviewer', + type: 'invitation', + userId: reviewer.id, + hasAnswer: true, + invitedOn: chance.timestamp(), + isAccepted: true, + respondedOn: chance.timestamp(), + }, + ], + collectionId: standardCollID, + declarations: { + agree: true, + }, + fragmentType: 'version', + recommendations: [ + { + id: chance.guid(), + userId: answerReviewer.id, + comments: [ + { + files: [ + { + id: chance.guid(), + name: 'file.pdf', + size: chance.natural(), + }, + ], + public: true, + content: 'A not so nice manuscript', + }, + ], + createdOn: chance.timestamp(), + updatedOn: chance.timestamp(), + submittedOn: chance.timestamp(), + recommendation: 'publish', + recommendationType: 'review', + }, + ], + save: jest.fn(() => fragments.fragment), + }, } module.exports = fragments diff --git a/packages/component-manuscript-manager/src/tests/collections/get.test.js b/packages/component-manuscript-manager/src/tests/collections/get.test.js index f9dc3d2380c0d39d75690bd02b41229ea7d645f8..f072e2693638e8f954d1d061e446a15b7f1cd8d3 100644 --- a/packages/component-manuscript-manager/src/tests/collections/get.test.js +++ b/packages/component-manuscript-manager/src/tests/collections/get.test.js @@ -1,7 +1,7 @@ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' process.env.SUPPRESS_NO_CONFIG_WARNING = true -const cloneDeep = require('lodash/cloneDeep') +const { cloneDeep, size } = require('lodash') const fixturesService = require('pubsweet-component-fixture-service') const requests = require('../requests') @@ -88,7 +88,7 @@ describe('Get collections route handler', () => { expect(res.statusCode).toBe(200) const data = JSON.parse(res._getData()) - expect(data).toHaveLength(2) + expect(data).toHaveLength(size(testFixtures.collections)) expect(data[0].type).toEqual('collection') expect(data[0]).toHaveProperty('visibleStatus') expect(data[0].currentVersion.recommendations).toHaveLength(3) diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js index c028d702ddb9099bec210d1a2c46f79bd8ed0509..3670d1e709f37f933de0e61f68d2a6ee59b1b4d0 100644 --- a/packages/xpub-faraday/config/authsome-helpers.js +++ b/packages/xpub-faraday/config/authsome-helpers.js @@ -244,6 +244,30 @@ const getCollections = async ({ user, models }) => { )).filter(Boolean) } +async function updateReviewerVisibleStatusByInvitation({ + collection, + FragmentModel, + user, +}) { + const fragmentId = last(collection.fragments) + const fragment = await FragmentModel.find(fragmentId) + const invitation = fragment.invitations.find(inv => inv.userId === user.id) + const recommendationDone = fragment.recommendations.some( + rec => + rec.recommendationType === 'review' && + rec.userId === user.id && + rec.submittedOn, + ) + + if (recommendationDone) { + return get(statuses, `${collection.status}.reviewer.label`) + } + + return invitation.hasAnswer && invitation.isAccepted + ? get(statuses, `underReview.reviewer.label`) + : get(statuses, `reviewersInvited.reviewer.label`) +} + module.exports = { filterObjectData, parseAuthorsData, @@ -262,4 +286,5 @@ module.exports = { getUsersList, parseUser, getCollections, + updateReviewerVisibleStatusByInvitation, } diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js index d37ba41057abea6e3a3e4fe036510dcdc341469f..89c0caf14801a234d20013a8d2e16ec10fdeceb6 100644 --- a/packages/xpub-faraday/config/authsome-mode.js +++ b/packages/xpub-faraday/config/authsome-mode.js @@ -78,13 +78,9 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { return true } - const fragmentPermission = userPermissions.find(p => + return userPermissions.find(p => collection.fragments.includes(p.objectId), ) - if (fragmentPermission) { - return true - } - return false }) }, } @@ -113,7 +109,19 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { collection.fragments.includes(p.objectId), ) const role = get(collPermission, 'role', 'author') - const visibleStatus = get(statuses, `${status}.${role}.label`) + + let visibleStatus = get(statuses, `${status}.${role}.label`) + + if (role === 'reviewer' && status !== 'reviewersInvited') { + visibleStatus = await helpers.updateReviewerVisibleStatusByInvitation( + { + collection, + FragmentModel: context.models.Fragment, + user, + }, + ) + } + const parsedCollection = helpers.stripeCollectionByRole( collection, role, diff --git a/packages/xpub-faraday/tests/config/authsome-helpers.test.js b/packages/xpub-faraday/tests/config/authsome-helpers.test.js index de8005598a8dc3f7f16b51727e561248daf7521a..82e6978c47a3d5f509dae9d86b9f14d6b377eccd 100644 --- a/packages/xpub-faraday/tests/config/authsome-helpers.test.js +++ b/packages/xpub-faraday/tests/config/authsome-helpers.test.js @@ -208,4 +208,42 @@ describe('Authsome Helpers', () => { expect(parsedUser).toHaveProperty('email') expect(parsedUser).toHaveProperty('username') }) + describe('updateReviewerVisibleStatusByInvitation', () => { + it('should return the fragment status for reviewer when they have done the review', async () => { + const { answerReviewer } = testFixtures.users + const { collectionReviewCompleted } = testFixtures.collections + + const visibleStatus = await ah.updateReviewerVisibleStatusByInvitation({ + collection: collectionReviewCompleted, + FragmentModel: models.Fragment, + user: answerReviewer, + }) + + expect(visibleStatus).toEqual('Review Completed') + }) + it('should return the underReview status for reviewer when they have accepted the review', async () => { + const { reviewer } = testFixtures.users + const { collectionReviewCompleted } = testFixtures.collections + + const visibleStatus = await ah.updateReviewerVisibleStatusByInvitation({ + collection: collectionReviewCompleted, + FragmentModel: models.Fragment, + user: reviewer, + }) + + expect(visibleStatus).toEqual('Complete Review') + }) + it('should return the reviewersInvited status for reviewer when they have to accept the review', async () => { + const { recReviewer } = testFixtures.users + const { collectionReviewCompleted } = testFixtures.collections + + const visibleStatus = await ah.updateReviewerVisibleStatusByInvitation({ + collection: collectionReviewCompleted, + FragmentModel: models.Fragment, + user: recReviewer, + }) + + expect(visibleStatus).toEqual('Respond to Invite') + }) + }) })