diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js index 80b38b4b6caafc3a5f96ac36253fa9f44cfd239b..b0ac3d3190021aa390fffefdeb35e894fa5d0a2b 100644 --- a/packages/component-helper-service/src/services/Fragment.js +++ b/packages/component-helper-service/src/services/Fragment.js @@ -46,9 +46,9 @@ class Fragment { const submittingAuthorData = authors.find( author => author.isSubmitting === true, ) - const submittingAuthor = await UserModel.find(submittingAuthorData.userId) + const submittingAuthor = await UserModel.find(submittingAuthorData.id) const authorsPromises = authors.map(async author => { - const user = await UserModel.find(author.userId) + const user = await UserModel.find(author.id) return `${user.firstName} ${user.lastName}` }) const authorsList = await Promise.all(authorsPromises) diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index df4b1eaac76cebaf609b4b5fe0d5768e25eb2979..9289bd24896b42155ba1ec14286b0beeaefe2911 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -53,7 +53,10 @@ export default compose( hasManuscriptFailure: hasManuscriptFailure(state), version: selectFragment(state, match.params.version), project: selectCollection(state, match.params.project), - editorialRecommendations: selectEditorialRecommendations(state), + editorialRecommendations: selectEditorialRecommendations( + state, + match.params.version, + ), canSeeEditorialComments: canSeeEditorialComments( state, match.params.project, diff --git a/packages/component-manuscript/src/components/ReviewsAndReports.js b/packages/component-manuscript/src/components/ReviewsAndReports.js index b498bf92a2eab8ad79f3071057a1adf539c29efd..7248a6a1502bef9da4171683a8b09b8eb161981a 100644 --- a/packages/component-manuscript/src/components/ReviewsAndReports.js +++ b/packages/component-manuscript/src/components/ReviewsAndReports.js @@ -100,18 +100,18 @@ const ReviewsAndReports = ({ export default compose( connect( - (state, { project }) => ({ + (state, { project, version }) => ({ reviewers: selectReviewers(state), - recommendations: selectRecommendations(state), fetchingReviewers: selectFetchingReviewers(state), - isReviewer: currentUserIsReviewer(state, project.id), + isReviewer: currentUserIsReviewer(state, version.id), + recommendations: selectRecommendations(state, version.id), canSeeReviewersReports: canSeeReviewersReports(state, project.id), }), { getCollectionReviewers }, ), withHandlers({ - getReviewers: ({ project, getCollectionReviewers }) => () => { - getCollectionReviewers(project.id) + getReviewers: ({ project, version, getCollectionReviewers }) => () => { + getCollectionReviewers(project.id, version.id) }, mappedRecommendations: ({ recommendations, reviewers }) => () => recommendations.filter(r => r.submittedOn).map(r => ({ diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js index f773064fb9af6d65f85921d6e28d653aa53a9e2a..9ba22a5d7524d0159f9b9827d6a235b8bf2fb329 100644 --- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js +++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js @@ -171,6 +171,7 @@ const DashboardCard = ({ invitation={invitation} modalKey={`reviewer-decision-${project.id}`} project={project} + version={version} /> </RightDetails> )} @@ -185,9 +186,9 @@ export default compose( setDisplayName('DashboardCard'), getContext({ journal: PropTypes.object, currentUser: PropTypes.object }), withTheme, - connect((state, { project }) => ({ + connect((state, { project, version }) => ({ isHE: currentUserIs(state, 'handlingEditor'), - invitation: selectInvitation(state, project.id), + invitation: selectInvitation(state, version.id), canMakeDecision: canMakeDecision(state, project), canInviteReviewers: canInviteReviewers(state, project), canMakeRecommendation: canMakeRecommendation(state, project), diff --git a/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js b/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js index 7037dbebfdfebb3884315b8f9fb030920100eb61..c4d020c9a5ac49a0ed5b160476429a3f64b640de 100644 --- a/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js +++ b/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js @@ -30,20 +30,21 @@ const ModalComponent = connect(state => ({ export default compose( connect(null, { reviewerDecision, - getCollections: actions.getCollections, + getFragments: actions.getFragments, }), withModal(props => ({ modalComponent: ModalComponent, })), withHandlers({ - decisionSuccess: ({ getCollections, hideModal }) => () => { - getCollections() + decisionSuccess: ({ getFragments, hideModal }) => () => { + getFragments() hideModal() }, }), withHandlers({ showAcceptModal: ({ project, + version, showModal, invitation, setModalError, @@ -54,7 +55,7 @@ export default compose( title: 'Agree to review Manuscript?', confirmText: 'Agree', onConfirm: () => { - reviewerDecision(invitation.id, project.id, true).then( + reviewerDecision(invitation.id, project.id, version.id, true).then( decisionSuccess, handleError(setModalError), ) @@ -63,6 +64,7 @@ export default compose( }, showDeclineModal: ({ project, + version, showModal, invitation, setModalError, @@ -73,7 +75,7 @@ export default compose( title: 'Decline to review Manuscript?', confirmText: 'Decline', onConfirm: () => { - reviewerDecision(invitation.id, project.id, false).then( + reviewerDecision(invitation.id, project.id, version.id, false).then( decisionSuccess, handleError(setModalError), ) diff --git a/packages/components-faraday/src/components/Invitations/ReviewerBreakdown.js b/packages/components-faraday/src/components/Invitations/ReviewerBreakdown.js index 6ced230390ad0b30dc5de6af1d9ff6baf53ef5be..d67820dc3764e31d5e71fd0ce0275185d662427d 100644 --- a/packages/components-faraday/src/components/Invitations/ReviewerBreakdown.js +++ b/packages/components-faraday/src/components/Invitations/ReviewerBreakdown.js @@ -31,7 +31,7 @@ export default compose( collection: selectCollection(state, collectionId), })), withHandlers({ - getCompactReport: ({ collection: { invitations = [] } }) => () => { + getCompactReport: ({ fragment: { invitations = [] } }) => () => { const reviewerInvitations = invitations.filter(roleFilter('reviewer')) const accepted = reviewerInvitations.filter(acceptedInvitationFilter) .length diff --git a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js index fe8f3f38b9d92fd7d7b43bc282aa31509a469a7c..262a8cfbe8297cd9a0ca7e3c18c2d5241a3e73fc 100644 --- a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js +++ b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js @@ -124,7 +124,11 @@ export default compose( recommendationError: selectError(state), heRecommendation: getHERecommendation(state, collectionId, fragmentId), }), - { createRecommendation, getCollections: actions.getCollections }, + { + createRecommendation, + getFragments: actions.getFragments, + getCollections: actions.getCollections, + }, ), withProps(({ heRecommendation: { recommendation = '', comments = [] } }) => ({ heRecommendation: { @@ -142,21 +146,25 @@ export default compose( hideModal, fragmentId, collectionId, + getFragments, getCollections, createRecommendation, }, ) => { const recommendation = parseFormValues(values) - createRecommendation(collectionId, fragmentId, recommendation).then(r => { - showModal({ - onCancel: () => { - getCollections() - hideModal() - }, - title: 'Decision submitted', - cancelText: 'OK', - }) - }) + createRecommendation(collectionId, fragmentId, recommendation).then( + () => { + showModal({ + onCancel: () => { + getCollections() + getFragments() + hideModal() + }, + title: 'Decision submitted', + cancelText: 'OK', + }) + }, + ) }, }), )(DecisionForm) diff --git a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js index 3ef84572bbad69a7e64ecb89dd16d60586f5f8dc..555a8979f77c7987940721aaa25d2be1e0c2b570 100644 --- a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js +++ b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js @@ -60,6 +60,7 @@ export default compose( { resetForm, createRecommendation, + getFragments: actions.getFragments, getCollections: actions.getCollections, }, ), @@ -77,6 +78,7 @@ export default compose( resetForm, fragmentId, collectionId, + getFragments, getCollections, createRecommendation, }) => values => { @@ -88,6 +90,7 @@ export default compose( cancelText: 'OK', onCancel: () => { getCollections() + getFragments() hideModal() }, }) diff --git a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js index b17b7d65b6bcd38bd26baeeff50e58ad583795e6..b6087f87534c4a756da957e77144c91b7d026286 100644 --- a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js +++ b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js @@ -36,11 +36,12 @@ const InviteReviewersModal = compose( ), withHandlers({ getReviewers: ({ + versionId, collectionId, setReviewers, getCollectionReviewers, }) => () => { - getCollectionReviewers(collectionId) + getCollectionReviewers(collectionId, versionId) }, closeModal: ({ getCollections, hideModal }) => () => { getCollections() @@ -81,6 +82,7 @@ const InviteReviewersModal = compose( isFetching={fetchingInvite} reviewerError={reviewerError} reviewers={reviewers} + versionId={versionId} /> <Row> diff --git a/packages/components-faraday/src/components/Reviewers/ReviewerForm.js b/packages/components-faraday/src/components/Reviewers/ReviewerForm.js index 0a26dbfc5feb7a55a1fd1c4572af780ea6912a56..0c24f66472c8abf9fb6e049472776bb3966699e9 100644 --- a/packages/components-faraday/src/components/Reviewers/ReviewerForm.js +++ b/packages/components-faraday/src/components/Reviewers/ReviewerForm.js @@ -60,7 +60,7 @@ export default compose( onSubmit: ( values, dispatch, - { inviteReviewer, collectionId, getReviewers, reset }, + { inviteReviewer, collectionId, versionId, getReviewers, reset }, ) => { const reviewerData = pick(values, [ 'email', @@ -68,7 +68,7 @@ export default compose( 'firstName', 'affiliation', ]) - inviteReviewer(reviewerData, collectionId).then(() => { + inviteReviewer(reviewerData, collectionId, versionId).then(() => { reset() getReviewers() }) diff --git a/packages/components-faraday/src/index.js b/packages/components-faraday/src/index.js index 0eb9c3b474d2da621536bec68cbe2541141b9544..b40accf6eaee709b192b849b8ab1290c47363428 100644 --- a/packages/components-faraday/src/index.js +++ b/packages/components-faraday/src/index.js @@ -7,7 +7,6 @@ module.exports = { editors: () => require('./redux/editors').default, files: () => require('./redux/files').default, reviewers: () => require('./redux/reviewers').default, - recommendations: () => require('./redux/recommendations').default, }, }, } diff --git a/packages/components-faraday/src/redux/recommendations.js b/packages/components-faraday/src/redux/recommendations.js index 3314f901decb5254b8c5d943163c7b3dbd3517d7..9936ff3d16989380edfa015d086c45a37ed8dafe 100644 --- a/packages/components-faraday/src/redux/recommendations.js +++ b/packages/components-faraday/src/redux/recommendations.js @@ -41,10 +41,10 @@ export const updateRecommendationSuccess = recommendation => ({ export const selectFetching = state => get(state, 'recommendations.fetching') || false export const selectError = state => get(state, 'recommendations.error') -export const selectRecommendations = state => - get(state, 'recommendations.recommendations') || [] -export const selectEditorialRecommendations = state => - selectRecommendations(state).filter( +export const selectRecommendations = (state, fragmentId) => + get(state, `fragments.${fragmentId}.recommendations`) || [] +export const selectEditorialRecommendations = (state, fragmentId) => + selectRecommendations(state, fragmentId).filter( r => r.recommendationType === 'editorRecommendation' && r.comments, ) // #endregion diff --git a/packages/components-faraday/src/redux/reviewers.js b/packages/components-faraday/src/redux/reviewers.js index e21dae2a3fa17e369ffcae12f83dbc01b7b8c7d0..8611d6f38baac2ca0ca350661136651b85942a93 100644 --- a/packages/components-faraday/src/redux/reviewers.js +++ b/packages/components-faraday/src/redux/reviewers.js @@ -81,19 +81,17 @@ export const selectFetchingInvite = state => export const selectFetchingDecision = state => get(state, 'reviewers.fetching.decision') || false -export const selectInvitation = (state, collectionId) => { +export const selectInvitation = (state, fragmentId) => { const currentUser = selectCurrentUser(state) - const collection = state.collections.find(c => c.id === collectionId) - const invitations = get(collection, 'invitations') || [] + const invitations = get(state, `fragments.${fragmentId}.invitations`) || [] return invitations.find( i => i.userId === currentUser.id && i.role === 'reviewer' && !i.hasAnswer, ) } -export const currentUserIsReviewer = (state, collectionId) => { +export const currentUserIsReviewer = (state, fragmentId) => { const currentUser = selectCurrentUser(state) - const collection = state.collections.find(c => c.id === collectionId) - const invitations = get(collection, 'invitations') || [] + const invitations = get(state, `fragments.${fragmentId}.invitations`) || [] return !!invitations.find( i => i.userId === currentUser.id && @@ -103,22 +101,37 @@ export const currentUserIsReviewer = (state, collectionId) => { ) } -export const getCollectionReviewers = collectionId => dispatch => { +export const getCollectionReviewers = ( + collectionId, + fragmentId, +) => dispatch => { dispatch(getReviewersRequest()) - return apiGet(`/collections/${collectionId}/invitations?role=reviewer`).then( + return apiGet( + `/collections/${collectionId}/fragments/${fragmentId}/invitations?role=reviewer`, + ).then( r => dispatch(getReviewersSuccess(orderBy(r, orderReviewers))), - err => dispatch(getReviewersError(err)), + err => { + dispatch(getReviewersError(err)) + throw err + }, ) } // #endregion // #region Actions - invitations -export const inviteReviewer = (reviewerData, collectionId) => dispatch => { +export const inviteReviewer = ( + reviewerData, + collectionId, + fragmentId, +) => dispatch => { dispatch(inviteRequest()) - return create(`/collections/${collectionId}/invitations`, { - ...reviewerData, - role: 'reviewer', - }).then( + return create( + `/collections/${collectionId}/fragments/${fragmentId}/invitations`, + { + ...reviewerData, + role: 'reviewer', + }, + ).then( () => dispatch(inviteSuccess()), err => { dispatch(inviteError(get(JSON.parse(err.response), 'error'))) @@ -153,12 +166,16 @@ export const revokeReviewer = (invitationId, collectionId) => dispatch => { export const reviewerDecision = ( invitationId, collectionId, + fragmentId, agree = true, ) => dispatch => { dispatch(reviewerDecisionRequest()) - return update(`/collections/${collectionId}/invitations/${invitationId}`, { - isAccepted: agree, - }).then( + return update( + `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}`, + { + isAccepted: agree, + }, + ).then( res => { dispatch(reviewerDecisionSuccess()) return res diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js index 164a9ce8ae550d9cd1709543ceb852169220cdc6..cdd620a0dba9f91aabbab31568fbeaa3ee5e6f40 100644 --- a/packages/xpub-faraday/config/authsome-helpers.js +++ b/packages/xpub-faraday/config/authsome-helpers.js @@ -59,8 +59,12 @@ const filterObjectData = ( return object } -const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => { - const teams = await Promise.all( +const getTeamsByPermissions = async ( + teamIds = [], + permissions = [], + TeamModel, +) => + (await Promise.all( teamIds.map(async teamId => { const team = await TeamModel.find(teamId) if (!permissions.includes(team.teamType.permissions)) { @@ -68,15 +72,20 @@ const getTeamsByPermissions = async (teamIds = [], permissions, TeamModel) => { } return team }), - ) + )).filter(Boolean) - return teams.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, + ) module.exports = { + filterObjectData, parseAuthorsData, setPublicStatuses, - filterRefusedInvitations, - filterObjectData, getTeamsByPermissions, + filterRefusedInvitations, + // + heIsInvitedToFragment, } diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js index 8a92a1301df7ea1bed2dc105beb44834cdb9b16f..8a3475b041620f06df5a15832e2a19225f547274 100644 --- a/packages/xpub-faraday/config/authsome-mode.js +++ b/packages/xpub-faraday/config/authsome-mode.js @@ -119,6 +119,28 @@ async function authenticatedUser(user, operation, object, context) { } } + // get fragments for invited reviewers + if ( + operation === 'GET' && + get(object, 'type') === 'fragment' && + get(object, 'invitations').some(i => i.userId === user.id) + ) { + return true + } + + // TODO: in the future give him the non draft version of the fragment + if ( + operation === 'GET' && + get(object, 'type') === 'fragment' && + user.handlingEditor + ) { + return helpers.heIsInvitedToFragment({ + user, + Team: context.models.Team, + collectionId: object.collectionId, + }) + } + if ( operation === 'POST' && object.path === '/collections/:collectionId/fragments'