diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index 8a6ef140784a77427e9da1f5095a39a3148efaea..d3b5aecc615ed47a5f8ff9b977b19401690c5112 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -1,5 +1,5 @@ -import { get, has, last, chain, some } from 'lodash' import { selectCurrentUser } from 'xpub-selectors' +import { get, has, last, chain, some } from 'lodash' export const isHEToManuscript = (state, collectionId = '') => { const { id = '', isAccepted = false } = chain(state) @@ -450,3 +450,14 @@ export const getVersionOptions = (state, collection = {}) => { .reverse() .value() } + +export const canReview = (state, collection = {}, fragment = {}) => { + const fragmentId = get(fragment, 'id', false) + + if (!fragmentId) return false + + const isReviewer = currentUserIsReviewer(state, fragmentId) + if (!isReviewer) return false + + return get(collection, 'status', 'draft') === 'underReview' +} diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js index 95a0afc1d89dc6ee606f422d1ccef90b6aeec97e..3feb6ce116b9b5dc18aacbbb4f2225cbe455c630 100644 --- a/packages/component-manuscript/src/components/ManuscriptLayout.js +++ b/packages/component-manuscript/src/components/ManuscriptLayout.js @@ -54,7 +54,6 @@ const ManuscriptLayout = ({ pendingOwnRecommendation, toggleReviewerRecommendations, reviewerRecommendationExpanded, - shouldReview, submittedOwnRecommendation, reviewerReports, reviewerRecommendations, @@ -128,7 +127,7 @@ const ManuscriptLayout = ({ /> )} - {shouldReview && ( + {get(currentUser, 'permissions.canReview', false) && ( <ReviewerReportForm changeForm={changeForm} expanded={reviewerRecommendationExpanded} diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index 5b902498b9605887e88436f3968b1faa2e3492bc..91529c903020eb1de3085af83c175c8326738a33 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -31,6 +31,7 @@ import { selectEditorialRecommendations, } from 'pubsweet-components-faraday/src/redux/recommendations' import { + canReview, getUserToken, currentUserIs, canViewReports, @@ -161,6 +162,7 @@ export default compose( isReviewer: currentUserIsReviewer(state, get(fragment, 'id', '')), isHEToManuscript: isHEToManuscript(state, get(collection, 'id', '')), permissions: { + canReview: canReview(state, collection, fragment), canSubmitRevision: canSubmitRevision(state, fragment), canMakeHERecommendation: canMakeHERecommendation(state, { collection, @@ -282,15 +284,10 @@ export default compose( toggleEditorialComments: toggle, editorialCommentsExpanded: expanded, })), - withProps( - ({ currentUser, collection, submittedOwnRecommendation, fragment }) => ({ - getSignedUrl, - shouldReview: - get(currentUser, 'isReviewer', false) && - isUndefined(submittedOwnRecommendation), - isLatestVersion: isLatestVersion(collection, fragment), - }), - ), + withProps(({ collection, fragment }) => ({ + getSignedUrl, + isLatestVersion: isLatestVersion(collection, fragment), + })), withInviteHandlingEditor, withInviteReviewer, withSubmitRevision, @@ -302,7 +299,6 @@ export default compose( history, setError, location, - shouldReview, reviewerReports, setEditorInChief, clearCustomError, @@ -315,7 +311,7 @@ export default compose( isInvitedHE, isInvitedToReview, isHEToManuscript, - permissions: { canInviteReviewers, canSubmitRevision }, + permissions: { canInviteReviewers, canSubmitRevision, canReview }, }, } = this.props @@ -350,7 +346,7 @@ export default compose( this.props.toggleReviewerResponse() } - if (shouldReview) { + if (canReview) { this.props.toggleReviewerRecommendations() } diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js index c92571ecc8808a78710f8631b5fff43629b0d60b..500a6a103fc300331121a175465c9b18534487d3 100644 --- a/packages/xpub-faraday/config/authsome-helpers.js +++ b/packages/xpub-faraday/config/authsome-helpers.js @@ -1,65 +1,11 @@ -const { omit, get, last } = require('lodash') const config = require('config') const logger = require('@pubsweet/logger') +const { omit, get, last, chain } = require('lodash') const statuses = config.get('statuses') -const publicStatusesPermissions = ['author', 'reviewer'] const authorAllowedStatuses = ['revisionRequested', 'rejected', 'accepted'] -const parseAuthorsData = (coll, matchingCollPerm) => { - if (['reviewer'].includes(matchingCollPerm.permission)) { - coll.authors = coll.authors.map(a => omit(a, ['email'])) - } -} - -const setPublicStatuses = (coll, matchingCollPerm) => { - const status = get(coll, 'status', 'draft') - // coll.visibleStatus = statuses[status].public - if (publicStatusesPermissions.includes(matchingCollPerm.permission)) { - coll.visibleStatus = statuses[status].public - } -} - -const filterRefusedInvitations = (coll, user) => { - const matchingInv = coll.invitations.find(inv => inv.userId === user.id) - if (matchingInv === undefined) return null - if (matchingInv.hasAnswer === true && !matchingInv.isAccepted) return null - return coll -} - -const filterObjectData = ( - collectionsPermissions = [], - object = {}, - user = {}, -) => { - if (object.type === 'fragment') { - const matchingCollPerm = collectionsPermissions.find( - collPerm => object.id === collPerm.fragmentId, - ) - if (matchingCollPerm === undefined) return null - if (['reviewer'].includes(matchingCollPerm.permission)) { - object.files = omit(object.files, ['coverLetter']) - if (object.recommendations) - object.recommendations = object.recommendations.filter( - rec => rec.userId === user.id, - ) - } - parseAuthorsData(object, matchingCollPerm) - if (['reviewer', 'handlingEditor'].includes(matchingCollPerm.permission)) { - return filterRefusedInvitations(object, user) - } - return object - } - const matchingCollPerm = collectionsPermissions.find( - collPerm => object.id === collPerm.id, - ) - if (matchingCollPerm === undefined) return null - setPublicStatuses(object, matchingCollPerm) - - return object -} - const getTeamsByPermissions = async ( teamIds = [], permissions = [], @@ -75,12 +21,6 @@ const getTeamsByPermissions = async ( }), )).filter(Boolean) -const heIsInvitedToFragment = async ({ user, Team, collectionId }) => - (await getTeamsByPermissions(user.teams, ['handlingEditor'], Team)).some( - // user is a member of the team with access to the fragment's parent collection - t => t.members.includes(user.id) && t.object.id === collectionId, - ) - const getUserPermissions = async ({ user, Team, @@ -119,12 +59,6 @@ const isHandlingEditor = ({ user, object }) => const isInDraft = fragment => !get(fragment, 'submitted') -const hasFragmentInDraft = async ({ object, Fragment }) => { - const lastFragmentId = last(get(object, 'fragments')) - const fragment = await Fragment.find(lastFragmentId) - return isInDraft(fragment) -} - const filterAuthorRecommendations = (recommendations, status, isLast) => { const canViewRecommendations = authorAllowedStatuses.includes(status) if (canViewRecommendations || !isLast) { @@ -236,70 +170,105 @@ const getCollections = async ({ user, models }) => { collection.visibleStatus = get(statuses, `${status}.${up.role}.label`) const role = get(up, 'role', 'author') - - let visibleStatus = get(statuses, `${status}.${role}.label`) - - if (role === 'reviewer' && status !== 'reviewersInvited') { - visibleStatus = await updateReviewerVisibleStatusByInvitation({ - collection, - FragmentModel: models.Fragment, - user, - }) - } - + const parsedStatuses = await setCollectionStatus({ + role, + user, + collection, + FragmentModel: models.Fragment, + }) return { ...collection, - visibleStatus, + ...parsedStatuses, } }), )).filter(Boolean) } -async function updateReviewerVisibleStatusByInvitation({ +const reviewerActionStatuses = [ + 'underReview', + 'reviewCompleted', + 'reviewersInvited', +] +const setCollectionStatus = async ({ + role, + user, collection, FragmentModel, - user, -}) { - const fragmentId = last(collection.fragments) - const fragment = await FragmentModel.find(fragmentId) - const invitation = get(fragment, 'invitations', []).find( - inv => inv.userId === user.id, - ) - const recommendationDone = - fragment.recommendations && - fragment.recommendations.some( - rec => - rec.recommendationType === 'review' && - rec.userId === user.id && - rec.submittedOn, - ) +}) => { + const status = get(collection, 'status', 'draft') + + if (role !== 'reviewer') { + return { + status, + visibleStatus: get(statuses, `${status}.${role}.label`), + } + } + + if (reviewerActionStatuses.includes(status)) { + const fragmentId = last(collection.fragments) + const fragment = await FragmentModel.find(fragmentId) + + const hasPendingInvitation = !chain(fragment) + .get('invitations', []) + .find(i => i.userId === user.id && !i.hasAnswer) + .isUndefined() + .value() + + if (hasPendingInvitation) { + return { + status: 'reviewersInvited', + visibleStatus: get(statuses, 'reviewersInvited.reviewer.label'), + } + } - if (recommendationDone) { - return get(statuses, `${collection.status}.reviewer.label`) + const hasSubmittedReport = !chain(fragment) + .get('recommendations', []) + .find( + r => + r.userId === user.id && + r.recommendationType === 'review' && + r.submittedOn, + ) + .isUndefined() + .value() + + if (hasSubmittedReport) { + return { + status: 'reviewCompleted', + visibleStatus: get(statuses, 'reviewCompleted.reviewer.label'), + } + } + + const hasAcceptedInvitation = !chain(fragment) + .get('invitations', []) + .find(i => i.userId === user.id && i.hasAnswer && i.isAccepted) + .isUndefined() + .value() + + if (hasAcceptedInvitation) { + return { + status: 'underReview', + visibleStatus: get(statuses, 'underReview.reviewer.label'), + } + } } - return get(invitation, 'hasAnswer', false) && - get(invitation, 'isAccepted', false) - ? get(statuses, `underReview.reviewer.label`) - : get(statuses, `reviewersInvited.reviewer.label`) + return { + status, + visibleStatus: get(statuses, `${status}.reviewer.label`), + } } module.exports = { - filterObjectData, - parseAuthorsData, - setPublicStatuses, - getTeamsByPermissions, - filterRefusedInvitations, isOwner, - isHandlingEditor, - getUserPermissions, - heIsInvitedToFragment, - hasPermissionForObject, isInDraft, - hasFragmentInDraft, - stripeFragmentByRole, - getUsersList, parseUser, + getUsersList, getCollections, - updateReviewerVisibleStatusByInvitation, + isHandlingEditor, + getUserPermissions, + setCollectionStatus, + stripeFragmentByRole, + getTeamsByPermissions, + hasPermissionForObject, } diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js index 2bb207ebd4264f3d3210d226bb0134e25e0b1bff..67ab2326468688fca900b38bc23be699e69940d6 100644 --- a/packages/xpub-faraday/config/authsome-mode.js +++ b/packages/xpub-faraday/config/authsome-mode.js @@ -67,7 +67,6 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { if (get(object, 'type') === 'collection') { return { filter: async collection => { - const status = get(collection, 'status', 'draft') const userPermissions = await helpers.getUserPermissions({ user, Team: context.models.Team, @@ -79,10 +78,6 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { ) .map(up => up.objectId) - // if (collection.owners.map(o => o.id).includes(user.id)) { - // return collection - // } - // TODO: check why collPermission can be undefined const collPermission = userPermissions.find( p => p.objectId === collection.id || @@ -90,27 +85,22 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { ) const role = get(collPermission, 'role', 'author') - let visibleStatus = get(statuses, `${status}.${role}.label`) - - if (role === 'reviewer' && status !== 'reviewersInvited') { - visibleStatus = await helpers.updateReviewerVisibleStatusByInvitation( - { - collection, - FragmentModel: context.models.Fragment, - user, - }, - ) - } + const parsedStatuses = await helpers.setCollectionStatus({ + role, + user, + collection, + FragmentModel: context.models.Fragment, + }) return { ...collection, + ...parsedStatuses, fragments: role !== 'reviewer' ? collection.fragments : collection.fragments.filter(fragId => fragmentPermissions.includes(fragId), ), - visibleStatus, } }, } diff --git a/packages/xpub-faraday/tests/config/authsome-helpers.test.js b/packages/xpub-faraday/tests/config/authsome-helpers.test.js index 0e51ce6aed419d58cda2bf016f2bbc09d821e8b5..a15e1f9852337441114611dcc2a0e426bf904c5c 100644 --- a/packages/xpub-faraday/tests/config/authsome-helpers.test.js +++ b/packages/xpub-faraday/tests/config/authsome-helpers.test.js @@ -195,42 +195,4 @@ 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') - }) - }) })