From aa55f7484977e7335760293018913c9646c5ecd4 Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munt@gmail.com>
Date: Thu, 21 Jun 2018 14:45:25 +0300
Subject: [PATCH] feat(submit-revision): update authsome to get the correct
 version, create new version

---
 .../component-faraday-selectors/src/index.js  |  11 +-
 .../src/components/SideBarActions.js          |  41 ++++++-
 .../component-wizard/src/redux/conversion.js  |  23 +++-
 .../src/components/Dashboard/DashboardCard.js | 106 +++++++++---------
 .../xpub-faraday/config/authsome-helpers.js   |  14 ++-
 packages/xpub-faraday/config/authsome-mode.js |  20 +++-
 6 files changed, 153 insertions(+), 62 deletions(-)

diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 2ad7a635b..cde4ed57f 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -56,10 +56,11 @@ export const getHERecommendation = (state, collectionId, fragmentId) => {
   )
 }
 
+const cantMakeDecisionStatuses = ['rejected', 'published', 'draft']
 export const canMakeDecision = (state, collection) => {
   const status = get(collection, 'status')
 
-  if (!status || status === 'rejected' || status === 'published') return false
+  if (!status || cantMakeDecisionStatuses.includes(status)) return false
 
   const isEIC = currentUserIs(state, 'adminEiC')
   return isEIC && status
@@ -72,3 +73,11 @@ export const canSeeReviewersReports = (state, collectionId) => {
 }
 
 export const canSeeEditorialComments = canSeeReviewersReports
+
+export const canMakeRevision = (state, collection) => {
+  const currentUserId = get(state, 'currentUser.user.id')
+  return (
+    collection.status === 'revisionRequested' &&
+    collection.owners.map(o => o.id).includes(currentUserId)
+  )
+}
diff --git a/packages/component-manuscript/src/components/SideBarActions.js b/packages/component-manuscript/src/components/SideBarActions.js
index 01f60511f..c85422bad 100644
--- a/packages/component-manuscript/src/components/SideBarActions.js
+++ b/packages/component-manuscript/src/components/SideBarActions.js
@@ -2,13 +2,19 @@ import React from 'react'
 import { compose } from 'recompose'
 import { connect } from 'react-redux'
 import styled from 'styled-components'
-import { th, Icon } from '@pubsweet/ui'
+import { th } from '@pubsweet/ui-toolkit'
+import { Icon, Button } from '@pubsweet/ui'
+import { withRouter } from 'react-router-dom'
 import ZipFiles from 'pubsweet-components-faraday/src/components/Files/ZipFiles'
 import {
   Decision,
   Recommendation,
 } from 'pubsweet-components-faraday/src/components'
+
+import { createRevision } from 'pubsweet-component-wizard/src/redux/conversion'
+
 import {
+  canMakeRevision,
   canMakeDecision,
   canMakeRecommendation,
 } from '../../../component-faraday-selectors'
@@ -16,10 +22,15 @@ import {
 const SideBarActions = ({
   project,
   version,
+  createRevision,
+  canMakeRevision,
   canMakeDecision,
   canMakeRecommendation,
 }) => (
   <Root>
+    {canMakeRevision && (
+      <DecisionButton onClick={createRevision}>Submit revision</DecisionButton>
+    )}
     {canMakeDecision && (
       <Decision
         collectionId={project.id}
@@ -48,10 +59,17 @@ const SideBarActions = ({
 )
 
 export default compose(
-  connect((state, { project }) => ({
-    canMakeDecision: canMakeDecision(state, project),
-    canMakeRecommendation: canMakeRecommendation(state, project),
-  })),
+  withRouter,
+  connect(
+    (state, { project }) => ({
+      canMakeDecision: canMakeDecision(state, project),
+      canMakeRevision: canMakeRevision(state, project),
+      canMakeRecommendation: canMakeRecommendation(state, project),
+    }),
+    (dispatch, { project, version, history }) => ({
+      createRevision: () => dispatch(createRevision(project, version, history)),
+    }),
+  ),
 )(SideBarActions)
 
 // #region styled-components
@@ -68,4 +86,17 @@ const ClickableIcon = styled.div`
     opacity: 0.7;
   }
 `
+
+const DecisionButton = styled(Button)`
+  align-items: center;
+  background-color: ${th('colorPrimary')};
+  color: ${th('colorTextReverse')};
+  display: flex;
+  font-family: ${th('fontReading')};
+  font-size: ${th('fontSizeBaseSmall')};
+  height: calc(${th('subGridUnit')} * 5);
+  padding: calc(${th('subGridUnit')} / 2) ${th('subGridUnit')};
+  text-align: center;
+  white-space: nowrap;
+`
 // #endregion
diff --git a/packages/component-wizard/src/redux/conversion.js b/packages/component-wizard/src/redux/conversion.js
index 7b28e5644..87f5ac384 100644
--- a/packages/component-wizard/src/redux/conversion.js
+++ b/packages/component-wizard/src/redux/conversion.js
@@ -1,5 +1,5 @@
-import { pick } from 'lodash'
 import moment from 'moment'
+import { pick } from 'lodash'
 import { actions } from 'pubsweet-client'
 import { create } from 'pubsweet-client/src/helpers/api'
 
@@ -77,6 +77,27 @@ export const createDraftSubmission = history => (dispatch, getState) => {
   })
 }
 
+export const createRevision = (
+  collection,
+  previousVersion,
+  history,
+) => dispatch => {
+  const { id, submitted, ...prev } = previousVersion
+  return dispatch(
+    actions.createFragment(collection, {
+      ...prev,
+      created: new Date(),
+      version: previousVersion.version + 1,
+    }),
+  ).then(({ fragment }) => {
+    const route = `/projects/${collection.id}/versions/${fragment.id}/submit`
+    window.setTimeout(() => {
+      history.push(route)
+    }, 10)
+    return fragment
+  })
+}
+
 /* reducer */
 const initialState = {
   complete: undefined,
diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js
index afa389aea..ae4c120f5 100644
--- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js
+++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js
@@ -85,18 +85,19 @@ const DashboardCard = ({
                   <Icon>download</Icon>
                 </ClickableIcon>
               </ZipFiles>
-              {!project.status && (
-                <ActionButtons
-                  data-test="button-resume-submission"
-                  onClick={() =>
-                    history.push(
-                      `/projects/${project.id}/versions/${version.id}/submit`,
-                    )
-                  }
-                >
-                  RESUME SUBMISSION
-                </ActionButtons>
-              )}
+              {!project.status ||
+                (project.status === 'draft' && (
+                  <ActionButtons
+                    data-test="button-resume-submission"
+                    onClick={() =>
+                      history.push(
+                        `/projects/${project.id}/versions/${version.id}/submit`,
+                      )
+                    }
+                  >
+                    RESUME SUBMISSION
+                  </ActionButtons>
+                ))}
             </RightDetails>
           </LeftDetails>
         </Top>
@@ -117,7 +118,7 @@ const DashboardCard = ({
             <ManuscriptType title={manuscriptMeta}>
               {manuscriptMeta}
             </ManuscriptType>
-            {project.status ? (
+            {project.status && project.status !== 'draft' ? (
               <Details
                 data-test="button-details"
                 onClick={() =>
@@ -138,47 +139,48 @@ const DashboardCard = ({
           </RightDetails>
         </Bottom>
       </ListView>
-      {project.status && (
-        <DetailsView>
-          <Top>
-            <AuthorsWithTooltip authors={project.authors} />
-          </Top>
-          <Bottom>
-            <LeftDetails flex={4}>
-              <HandlingEditorSection
-                currentUser={currentUser}
-                isHE={isHE}
-                project={project}
-              />
-            </LeftDetails>
-            {canInviteReviewers && (
-              <RightDetails flex={4}>
-                <ReviewerBreakdown
-                  collectionId={project.id}
-                  compact
-                  versionId={version.id}
-                />
-                <InviteReviewers
-                  modalKey={`invite-reviewers-${project.id}`}
-                  project={project}
-                  version={version}
-                />
-              </RightDetails>
-            )}
-            {invitation && (
-              <RightDetails flex={4}>
-                <ReviewerText>Invited to review</ReviewerText>
-                <ReviewerDecision
-                  invitation={invitation}
-                  modalKey={`reviewer-decision-${project.id}`}
+      {project.status &&
+        project.status !== 'draft' && (
+          <DetailsView>
+            <Top>
+              <AuthorsWithTooltip authors={project.authors} />
+            </Top>
+            <Bottom>
+              <LeftDetails flex={4}>
+                <HandlingEditorSection
+                  currentUser={currentUser}
+                  isHE={isHE}
                   project={project}
-                  version={version}
                 />
-              </RightDetails>
-            )}
-          </Bottom>
-        </DetailsView>
-      )}
+              </LeftDetails>
+              {canInviteReviewers && (
+                <RightDetails flex={4}>
+                  <ReviewerBreakdown
+                    collectionId={project.id}
+                    compact
+                    versionId={version.id}
+                  />
+                  <InviteReviewers
+                    modalKey={`invite-reviewers-${project.id}`}
+                    project={project}
+                    version={version}
+                  />
+                </RightDetails>
+              )}
+              {invitation && (
+                <RightDetails flex={4}>
+                  <ReviewerText>Invited to review</ReviewerText>
+                  <ReviewerDecision
+                    invitation={invitation}
+                    modalKey={`reviewer-decision-${project.id}`}
+                    project={project}
+                    version={version}
+                  />
+                </RightDetails>
+              )}
+            </Bottom>
+          </DetailsView>
+        )}
     </Card>
   ) : null
 }
diff --git a/packages/xpub-faraday/config/authsome-helpers.js b/packages/xpub-faraday/config/authsome-helpers.js
index 658f47bb6..ad75355dd 100644
--- a/packages/xpub-faraday/config/authsome-helpers.js
+++ b/packages/xpub-faraday/config/authsome-helpers.js
@@ -1,6 +1,6 @@
-const omit = require('lodash/omit')
+const { omit, get, last } = require('lodash')
+
 const config = require('config')
-const get = require('lodash/get')
 
 const statuses = config.get('statuses')
 
@@ -116,6 +116,14 @@ const hasPermissionForObject = async ({ user, object, Team, roles = [] }) => {
 const isHandlingEditor = ({ user, object }) =>
   get(object, 'collection.handlingEditor.id') === user.id
 
+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)
+}
+
 module.exports = {
   filterObjectData,
   parseAuthorsData,
@@ -127,4 +135,6 @@ module.exports = {
   getUserPermissions,
   heIsInvitedToFragment,
   hasPermissionForObject,
+  isInDraft,
+  hasFragmentInDraft,
 }
diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js
index dae38b3e1..31cd3f415 100644
--- a/packages/xpub-faraday/config/authsome-mode.js
+++ b/packages/xpub-faraday/config/authsome-mode.js
@@ -91,6 +91,20 @@ async function authenticatedUser(user, operation, object, context) {
 
     if (get(object, 'type') === 'collection') {
       if (helpers.isOwner({ user, object })) {
+        if (
+          await helpers.hasFragmentInDraft({
+            object,
+            Fragment: context.models.Fragment,
+          })
+        ) {
+          return {
+            filter: collection => ({
+              ...collection,
+              status: 'draft',
+              visibleStatus: statuses.draft.public,
+            }),
+          }
+        }
         return true
       }
       return {
@@ -124,6 +138,10 @@ async function authenticatedUser(user, operation, object, context) {
         return true
       }
 
+      if (helpers.isInDraft(object)) {
+        return false
+      }
+
       const userPermissions = await helpers.getUserPermissions({
         user,
         Team: context.models.Team,
@@ -252,7 +270,7 @@ const authsomeMode = async (userId, operation, object, context) => {
   const user = await context.models.User.find(userId)
 
   // Admins and editor in chiefs can do anything
-  if (user && (user.admin || user.editorInChief)) return true
+  // if (user && (user.admin || user.editorInChief)) return true
 
   if (user) {
     return authenticatedUser(user, operation, object, context)
-- 
GitLab