diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c2c4a42c4525c9a0e89418749f816bfa12b65c2c..ce94dec3cf1c5bbb4c78a48efd8ada77edc0478c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,12 +16,12 @@ build: - docker:19.03.12-dind stage: build script: - - docker version - - docker build -t $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA . - if [ -z "$DOCKERHUB_USERNAME" ] || [ -z "$DOCKERHUB_PASSWORD" ]; then echo "Not pushing" && exit 0; fi - docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD - - echo "Ignore warning! Cannot perform an interactive login from a non TTY device" + - docker pull $IMAGE_ORG/$IMAGE_NAME:latest || true + - docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA --tag $IMAGE_ORG/$IMAGE_NAME:latest . - docker push $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA + - docker push $IMAGE_ORG/$IMAGE_NAME:latest lint: image: $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA @@ -32,7 +32,7 @@ lint: - cd ${HOME} - npm run lint -test: +test-chrome: image: $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA stage: test variables: @@ -49,4 +49,25 @@ test: script: - cd ${HOME} # specify host here else it confuses the linked postgres image - - PGHOST=postgres yarn test:all + - PGHOST=postgres yarn test:all:chrome + + +test-firefox: + allow_failure: true # at this point Cypress' support for Firefox is not stable + image: $IMAGE_ORG/$IMAGE_NAME:$CI_COMMIT_SHA + stage: test + variables: + GIT_STRATEGY: none + # setup data for postgres image + POSTGRES_USER: test + POSTGRES_PASSWORD: pw + # connection details for tests + PGUSER: test + PGPASSWORD: pw + NODE_ENV: test + services: + - postgres + script: + - cd ${HOME} + # specify host here else it confuses the linked postgres image + - PGHOST=postgres yarn test:all:firefox diff --git a/Dockerfile b/Dockerfile index f76e8697c4626a8e74f9ee45ed27f753a3193b70..7992d9c6e0d025ade4417c1890a1ee041b6cf2ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12 +FROM cypress/browsers:node12.18.0-chrome83-ff77 ENV HOME "/home/simplej" RUN mkdir -p ${HOME} @@ -6,18 +6,19 @@ WORKDIR ${HOME} ENV NODE_ENV "development" -# Install dependencies for Cypress -RUN apt-get -y update && apt-get -y install xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 - -COPY . . +# Only copy things needed for the yarn install +COPY package.json yarn.lock ./ # We do a development install because react-styleguidist is a dev dependency and we want to run tests RUN [ "yarn", "install", "--frozen-lockfile" ] ENV NODE_ENV ${NODE_ENV} -RUN [ "npx", "pubsweet", "build"] +# Disabling the build for now, as it runs in the test server again +# RUN [ "npx", "pubsweet", "build"] +# The copy everything else that changes frequently +COPY . . EXPOSE ${PORT} CMD [] diff --git a/app/components/AdminPage.js b/app/components/AdminPage.js index 1db40bc5a12a2bb20cf5deb786f9289d84ba4945..b0f1f8e3bc992dcba479c0428d9b26dd2a600032 100644 --- a/app/components/AdminPage.js +++ b/app/components/AdminPage.js @@ -20,7 +20,6 @@ import SubmitPage from '../components/component-submit/src/components/SubmitPage import ManuscriptPage from '../components/component-manuscript/src/components/ManuscriptPage' import ReviewersPage from '../components/component-review/src/components/ReviewersPage' import ReviewPage from '../components/component-review/src/components/ReviewPage' -import TeamPage from '../components/component-teams-manager/src/components/TeamsManagerPage' import DecisionPage from '../components/component-review/src/components/DecisionPage' import FormBuilderPage from '../components/component-formbuilder/src/components/FormBuilderPage' import NewSubmissionPage from '../components/component-submit/src/components/NewSubmissionPage' @@ -164,7 +163,6 @@ const AdminPage = ({ children, history, match }) => { exact path="/journal/versions/:version/submit" /> - <PrivateRoute component={TeamPage} exact path="/journal/admin/teams" /> <PrivateRoute component={FormBuilderPage} exact @@ -183,12 +181,12 @@ const AdminPage = ({ children, history, match }) => { <PrivateRoute component={ReviewPage} exact - path="/journal/versions/:version/reviews/:review" + path="/journal/versions/:version/review" /> <PrivateRoute component={DecisionPage} exact - path="/journal/versions/:version/decisions/:decision" + path="/journal/versions/:version/decision" /> <PrivateRoute component={Profile} exact path="/journal/profile" /> <PrivateRoute component={UsersManager} path="/journal/admin/users" /> diff --git a/app/components/component-dashboard/src/components/Dashboard.js b/app/components/component-dashboard/src/components/Dashboard.js index 899780e5f54c8e17dc9f24885d091077f2a20d64..ff23f5449eb3523618468b0fdb7da69d9cb4d038 100644 --- a/app/components/component-dashboard/src/components/Dashboard.js +++ b/app/components/component-dashboard/src/components/Dashboard.js @@ -41,7 +41,7 @@ const Dashboard = ({ history, ...props }) => { }) if (loading) return <Spinner /> - if (error) return error + if (error) return JSON.stringify(error) const dashboard = (data && data.manuscripts) || [] const currentUser = data && data.currentUser diff --git a/app/components/component-dashboard/src/components/Reviews.js b/app/components/component-dashboard/src/components/Reviews.js index c53d7a1f0506401d442fa6e6fac7a1e3be2a6ab6..66bd855f6ee05d4d173f88c88054893763539348 100644 --- a/app/components/component-dashboard/src/components/Reviews.js +++ b/app/components/component-dashboard/src/components/Reviews.js @@ -29,20 +29,10 @@ const getUserFromTeam = (version, role) => { } const countStatus = (version, status) => { - const teamMember = getUserFromTeam(version, 'reviewer') - - if (status === 'rejected' || status === 'invited') { - return sumBy(teamMember, member => (member.status === status ? 1 : 0)) - } - - if (status === 'accepted') { - return sumBy(version.reviews, review => (review.recommendation ? 0 : 1)) + const teamMembers = getUserFromTeam(version, 'reviewer') + if (teamMembers) { + return sumBy(teamMembers, member => (member.status === status ? 1 : 0)) } - - if (status === 'completed') { - return sumBy(version.reviews, review => (review.recommendation ? 1 : 0)) - } - return 0 } diff --git a/app/components/component-dashboard/src/components/sections/EditorItem.js b/app/components/component-dashboard/src/components/sections/EditorItem.js index b6abd5d49a4f11c221ff25e104bd5bffa70c0754..35e17175110c16a34cf587d4fc0dd605434eecc6 100644 --- a/app/components/component-dashboard/src/components/sections/EditorItem.js +++ b/app/components/component-dashboard/src/components/sections/EditorItem.js @@ -28,7 +28,7 @@ const EditorItemLinks = ({ version }) => ( <Action to={`/journal/versions/${version.id}/submit`}>Summary Info</Action> <Action data-testid="control-panel" - to={`/journal/versions/${version.id}/decisions/${version.id}`} + to={`/journal/versions/${version.id}/decision`} > {version.decision && version.decision.status === 'submitted' ? `Decision: ${version.decision.recommendation}` diff --git a/app/components/component-dashboard/src/components/sections/ReviewerItem.js b/app/components/component-dashboard/src/components/sections/ReviewerItem.js index 01a8fceafe9b51e023d4cbf2a19bdf5b68376258..7856a9e98fb7187774a6ce40325491b1287f3645 100644 --- a/app/components/component-dashboard/src/components/sections/ReviewerItem.js +++ b/app/components/component-dashboard/src/components/sections/ReviewerItem.js @@ -24,7 +24,7 @@ const ReviewerItem = ({ version, journals, currentUser, reviewerRespond }) => { {(status === 'accepted' || status === 'completed') && ( <ActionGroup> - <Action to={`/journal/versions/${version.id}/reviews`}> + <Action to={`/journal/versions/${version.id}/review`}> {status === 'completed' ? 'Completed' : 'Do Review'} </Action> </ActionGroup> diff --git a/app/components/component-dashboard/src/graphql/mutations/index.js b/app/components/component-dashboard/src/graphql/mutations/index.js index 019eceb78ba1b28f61adcd3fa8ef7334c72aabd3..cd9b489b448ae0f4560b78e5c8c8685a4da63b43 100644 --- a/app/components/component-dashboard/src/graphql/mutations/index.js +++ b/app/components/component-dashboard/src/graphql/mutations/index.js @@ -16,9 +16,8 @@ export default { id role name - object { - objectId - objectType + manuscript { + id } members { id @@ -50,9 +49,8 @@ export default { id role name - object { - objectId - objectType + manuscript { + id } members { id diff --git a/app/components/component-dashboard/src/graphql/queries/index.js b/app/components/component-dashboard/src/graphql/queries/index.js index 14952c20c8e356ccac9810bb8931904ce3a9aa3d..f4c9a923cc0549f844ebf44c0611999cbd13f4bc 100644 --- a/app/components/component-dashboard/src/graphql/queries/index.js +++ b/app/components/component-dashboard/src/graphql/queries/index.js @@ -15,6 +15,7 @@ export default { id } reviews { + id open recommendation created @@ -28,9 +29,8 @@ export default { id role name - object { - objectId - objectType + manuscript { + id } members { id diff --git a/app/components/component-manuscripts/src/Manuscript.jsx b/app/components/component-manuscripts/src/Manuscript.jsx index 40ee291243c384716a9050955d278d038e398612..f1b4113583d0343a2eb256c35d382ab08d037740 100644 --- a/app/components/component-manuscripts/src/Manuscript.jsx +++ b/app/components/component-manuscripts/src/Manuscript.jsx @@ -51,7 +51,7 @@ const User = ({ manuscript }) => { )} </Cell> <LastCell> - <Action to={`/journal/versions/${manuscript.id}/decisions/1`}> + <Action to={`/journal/versions/${manuscript.id}/decision`}> Control </Action> <Action to={`/journal/versions/${manuscript.id}/manuscript`}> diff --git a/app/components/component-review/src/components/DecisionPage.js b/app/components/component-review/src/components/DecisionPage.js index cbb412e57fe6d250203fd9ba976759c5f82b849a..bb7a6c97b8e528890f038484e6ea30975bc94dc6 100644 --- a/app/components/component-review/src/components/DecisionPage.js +++ b/app/components/component-review/src/components/DecisionPage.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useRef, useEffect } from 'react' import moment from 'moment' import { Tabs } from '@pubsweet/ui' @@ -15,7 +15,6 @@ import { AdminSection, Columns, Manuscript, Chat } from './style' import { Spinner } from '../../../shared' -import { getCommentContent } from './review/util' import MessageContainer from '../../../component-chat/src' const addEditor = (manuscript, label) => ({ @@ -24,23 +23,34 @@ const addEditor = (manuscript, label) => ({ label, }) +const commentFields = ` + id + commentType + content + files { + id + created + label + filename + fileType + mimeType + size + url + } +` + const reviewFields = ` id created updated - comments { - type - content - files { - id - created - label - filename - fileType - mimeType - size - url - } + decisionComment { + ${commentFields} + } + reviewComment { + ${commentFields} + } + confidentialComment { + ${commentFields} } isDecision recommendation @@ -71,9 +81,8 @@ const fragmentFields = ` id name role - object { - objectId - objectType + manuscript { + id } members { id @@ -153,29 +162,6 @@ const updateReviewMutationQuery = gql` } ` -const uploadReviewFilesMutation = gql` - mutation($file: Upload!) { - upload(file: $file) { - url - } - } -` - -// const createFileMutation = gql` -// mutation($file: Upload!) { -// createFile(file: $file) { -// id -// created -// label -// filename -// fileType -// mimeType -// size -// url -// } -// } -// ` - const makeDecisionMutation = gql` mutation($id: ID!, $decision: String) { makeDecision(id: $id, decision: $decision) { @@ -184,41 +170,6 @@ const makeDecisionMutation = gql` } } ` - -// const updateCacheForFileCreation = (proxy, { data: { createFile } }) => { -// const data = proxy.readQuery({ -// query, -// variables: { -// id: match.params.version, -// }, -// }) - -// data.manuscript.reviews.map(review => { -// if (review.id === file.objectId) { -// review.comments.map(comment => { -// if (comment.type === createFile.fileType) { -// comment.files = [createFile] -// } -// return comment -// }) -// } -// return review -// }) - -// proxy.writeQuery({ query, data }) -// } - -// const createFile = file => { - -// mutate({ -// variables: { -// file, -// }, -// update: -// }, - -// - const dateLabel = date => moment(date).format('YYYY-MM-DD') const decisionSections = ({ @@ -227,6 +178,9 @@ const decisionSections = ({ isValid, updateReview, uploadFile, + isSubmitting, + submitCount, + dirty, }) => { const decisionSections = [] const manuscriptVersions = manuscript.manuscriptVersions || [] @@ -263,8 +217,11 @@ const decisionSections = ({ </AdminSection> <AdminSection key="decision-form"> <DecisionForm + dirty={dirty} handleSubmit={handleSubmit} + isSubmitting={isSubmitting} isValid={isValid} + submitCount={submitCount} updateReview={updateReview} uploadFile={uploadFile} /> @@ -335,21 +292,33 @@ const decisionSections = ({ const DecisionPage = ({ match }) => { // Hooks from the old world - const [makeDecision] = useMutation(makeDecisionMutation, { - // refetchQueries: [query], - }) + const [makeDecision] = useMutation(makeDecisionMutation) const [updateReviewMutation] = useMutation(updateReviewMutationQuery) - // File upload - const [uploadReviewFiles] = useMutation(uploadReviewFilesMutation) - const { loading, error, data } = useQuery(query, { variables: { id: match.params.version, }, - fetchPolicy: 'network-only', + // fetchPolicy: 'cache-and-network', }) + const reviewOrInitial = manuscript => + (manuscript && + manuscript.reviews && + manuscript.reviews.find(review => review.isDecision)) || { + decisionComment: {}, + isDecision: true, + recommendation: null, + } + + // Find an existing review or create a placeholder, and hold a ref to it + const existingReview = useRef(reviewOrInitial(data?.manuscript)) + + // Update the value of that ref if the manuscript object changes + useEffect(() => { + existingReview.current = reviewOrInitial(data?.manuscript) + }, [data?.manuscript?.reviews]) + if (loading) return <Spinner /> if (error) return `Error! ${error.message}` @@ -361,41 +330,21 @@ const DecisionPage = ({ match }) => { channelId = manuscript.channels.find(c => c.type === 'editorial').id } - const uploadFile = (file, updateReview, type) => - uploadReviewFiles({ - variables: { - file, - }, - }).then(({ data }) => { - // const newFile = { - // url: data.upload.url, - // filename: file.name, - // size: file.size, - // object: 'Review', - // objectId: updateReview.id, - // fileType: type, - // } - // createFile(newFile) - }) - - const updateReview = (data, file) => { + const updateReview = review => { const reviewData = { - isDecision: true, + recommendation: review.recommendation, manuscriptId: manuscript.id, + isDecision: true, + decisionComment: review.decisionComment && { + id: existingReview.current.decisionComment?.id, + commentType: 'decision', + content: review.decisionComment.content, + }, } - if (data.comment) { - reviewData.comments = [data.comment] - } - - if (data.recommendation) { - reviewData.recommendation = data.recommendation - } - - const review = manuscript.reviews.find(review => review.isDecision) || {} return updateReviewMutation({ variables: { - id: review.id || undefined, + id: existingReview.current.id || undefined, input: reviewData, }, update: (cache, { data: { updateReview } }) => { @@ -427,52 +376,52 @@ const DecisionPage = ({ match }) => { }, }) } - - const initialValues = (manuscript.reviews && - manuscript.reviews.find(review => review.isDecision)) || { - comments: [], - recommendation: null, - } - // const editorSectionsResult = editorSections({ manuscript }) + const sections = props => + decisionSections({ + manuscript, + handleSubmit: props.handleSubmit, + isValid: props.isValid, + updateReview, + isSubmitting: props.isSubmitting, + submitCount: props.submitCount, + dirty: props.dirty, + }) + return ( <Columns> <Manuscript> <Formik displayName="decision" - initialValues={initialValues} - // isInitialValid={({ manuscript }) => { - // const rv = - // manuscript.reviews.find(review => review.isDecision) || {} - // const isRecommendation = rv.recommendation != null - // const isCommented = getCommentContent(rv, 'note') !== '' - - // return isCommented && isRecommendation - // }} - onSubmit={() => { + initialValues={reviewOrInitial(data.manuscript)} + onSubmit={values => makeDecision({ variables: { id: manuscript.id, - decision: manuscript.reviews.find(review => review.isDecision) - .recommendation, + decision: values.recommendation, }, }) - }} + } validate={(values, props) => { const errors = {} - if (getCommentContent(values, 'note') === '') { - errors.comments = 'Required' + if ( + ['', '<p></p>', undefined].includes( + values.decisionComment?.content, + ) + ) { + errors.decisionComment = 'Decision letter is required' } if (values.recommendation === null) { - errors.recommendation = 'Required' + errors.recommendation = 'Decision is required' } return errors }} + // validateOnMount > {props => ( - // Temp + // TODO: Find a nicer way to display the contents of a manuscript <> {/* <Tabs activeKey={ @@ -482,22 +431,8 @@ const DecisionPage = ({ match }) => { title="Versions" /> */} <Tabs - activeKey={ - decisionSections({ - manuscript, - handleSubmit: props.handleSubmit, - isValid: props.isValid, - updateReview, - uploadFile, - })[decisionSections.length - 1].key - } - sections={decisionSections({ - manuscript, - handleSubmit: props.handleSubmit, - isValid: props.isValid, - updateReview, - uploadFile, - })} + activeKey={sections(props)[decisionSections.length - 1].key} + sections={sections(props)} title="Versions" /> </> diff --git a/app/components/component-review/src/components/ReviewPage.js b/app/components/component-review/src/components/ReviewPage.js index d9c0e28f99c4af304912a4416abc3fd3bb734ec0..399c0a4ddcb60811387dd960e5265ce4450b9e68 100644 --- a/app/components/component-review/src/components/ReviewPage.js +++ b/app/components/component-review/src/components/ReviewPage.js @@ -1,30 +1,37 @@ -import React from 'react' +import React, { useRef, useEffect } from 'react' import { useMutation, useQuery } from '@apollo/client' import gql from 'graphql-tag' import { Formik } from 'formik' // import { cloneDeep } from 'lodash' -import { getCommentContent } from './review/util' import ReviewLayout from '../components/review/ReviewLayout' import { Spinner } from '../../../shared' import useCurrentUser from '../../../../hooks/useCurrentUser' +const commentFields = ` +id +commentType +content +files { + id + created + label + filename + fileType + mimeType + size + url +} +` + const reviewFields = ` id created updated - comments { - type - content - files { - id - created - label - filename - fileType - mimeType - size - url - } + reviewComment { + ${commentFields} + } + confidentialComment { + ${commentFields} } isDecision recommendation @@ -34,23 +41,6 @@ const reviewFields = ` } ` -// const teamFields = ` -// id -// name -// role -// object { -// objectId -// objectType -// } -// members { -// id -// user { -// id -// username -// } -// } -// ` - const fragmentFields = ` id created @@ -72,9 +62,8 @@ const fragmentFields = ` id name role - object { - objectId - objectType + manuscript { + id } members { id @@ -163,87 +152,39 @@ const updateReviewMutationQuery = gql` } ` -const uploadReviewFilesMutation = gql` - mutation($file: Upload!) { - upload(file: $file) { - url - } - } -` - -const createFileMutation = gql` - mutation($file: Upload!) { - createFile(file: $file) { - id - created - label - filename - fileType - mimeType - size - url - } - } -` - export default ({ match, ...props }) => { const currentUser = useCurrentUser() const [updateReviewMutation] = useMutation(updateReviewMutationQuery) const [completeReview] = useMutation(completeReviewMutation) - // File upload - // const [uploadReviewFiles] = useMutation(uploadReviewFilesMutation) - - const [createFileM] = useMutation(createFileMutation) - const createFile = file => - createFileM({ - variables: { - file, - }, - update: (proxy, { data: { createFile } }) => { - const data = proxy.readQuery({ - query, - variables: { - id: match.params.version, - }, - }) - - data.manuscript.reviews.map(review => { - if (review.id === file.objectId) { - review.comments.map(comment => { - if (comment.type === createFile.fileType) { - comment.files = [createFile] - } - return comment - }) - } - return review - }) - - proxy.writeQuery({ query, data }) - }, - }) - const { loading, error, data } = useQuery(query, { variables: { id: match.params.version, }, - fetchPolicy: 'network-only', }) + const reviewOrInitial = manuscript => + (manuscript && + manuscript.reviews && + manuscript.reviews.find( + review => review?.user?.id === currentUser.id && !review.isDecision, + )) || + {} + + // Find an existing review or create a placeholder, and hold a ref to it + const existingReview = useRef(reviewOrInitial(data?.manuscript)) + + // Update the value of that ref if the manuscript object changes + useEffect(() => { + existingReview.current = reviewOrInitial(data?.manuscript) + }, [data?.manuscript?.reviews]) + if (loading) return <Spinner /> if (error) return `Error! ${error.message}` const { manuscript } = data const channelId = manuscript.channels.find(c => c.type === 'editorial').id - const review = - (manuscript.reviews && - manuscript.reviews.find( - review => review.user.id === currentUser.id && !review.isDecision, - )) || - {} - // eslint-disable-next-line const status = ( ( @@ -253,61 +194,55 @@ export default ({ match, ...props }) => { ).status const updateReview = (review, file) => { - ;(review.comments || []).map(comment => { - delete comment.files - delete comment.__typename - return comment - }) - const reviewData = { recommendation: review.recommendation, - comments: review.comments, manuscriptId: manuscript.id, + reviewComment: review.reviewComment && { + id: existingReview.current.reviewComment?.id, + commentType: 'review', + content: review.reviewComment.content, + }, + confidentialComment: review.confidentialComment && { + id: existingReview.current.confidentialComment?.id, + commentType: 'confidential', + content: review.confidentialComment.content, + }, } return updateReviewMutation({ variables: { - id: review.id || undefined, + id: existingReview.current.id || undefined, input: reviewData, }, - // update: (proxy, { data: { updateReview } }) => { - // const data = JSON.parse( - // JSON.stringify( - // proxy.readQuery({ - // query, - // variables: { - // id: manuscript.id, - // }, - // }), - // ), - // ) - // let reviewIndex = data.manuscript.reviews.findIndex( - // review => review.id === updateReview.id, - // ) - // reviewIndex = reviewIndex < 0 ? 0 : reviewIndex - // data.manuscript.reviews[reviewIndex] = updateReview - // proxy.writeQuery({ query, data }) - // }, - }) - } + update: (cache, { data: { updateReview } }) => { + cache.modify({ + id: cache.identify(manuscript), + fields: { + reviews(existingReviewRefs = [], { readField }) { + const newReviewRef = cache.writeFragment({ + data: updateReview, + fragment: gql` + fragment NewReview on Review { + id + } + `, + }) + + if ( + existingReviewRefs.some( + ref => readField('id', ref) === updateReview.id, + ) + ) { + return existingReviewRefs + } - const uploadFile = (file, updateReview, type) => - uploadReviewFilesMutation({ - variables: { - file, + return [...existingReviewRefs, newReviewRef] + }, + }, + }) }, - }).then(({ data }) => { - const newFile = { - url: data.upload.url, - filename: file.name, - mimeType: file.type, - size: file.size, - object: 'Review', - objectId: updateReview.id, - fileType: type, - } - createFile(newFile) }) + } const handleSubmit = async ({ reviewId, history }) => { await completeReview({ @@ -324,7 +259,7 @@ export default ({ match, ...props }) => { initialValues={ (manuscript.reviews && manuscript.reviews.find( - review => review.user.id === currentUser.id && !review.isDecision, + review => review?.user?.id === currentUser.id && !review.isDecision, )) || { id: null, comments: [], @@ -332,12 +267,15 @@ export default ({ match, ...props }) => { } } onSubmit={values => - handleSubmit({ reviewId: review.id, history: props.history }) + handleSubmit({ + reviewId: existingReview.current.id, + history: props.history, + }) } validateOnMount={review => { if (!review.id) return false const hasRecommendation = review.recommendation !== null - const comment = getCommentContent(review, 'note') + const comment = review.decisionComment?.content const isCommented = comment !== null && comment !== '' return isCommented && hasRecommendation @@ -348,183 +286,12 @@ export default ({ match, ...props }) => { channelId={channelId} currentUser={currentUser} manuscript={manuscript} - review={review} + review={existingReview} status={status} updateReview={updateReview} - uploadFile={uploadFile} {...formikProps} /> )} </Formik> ) } - -// export default compose( -// graphql(query, { -// options: ({ match }) => ({ -// variables: { -// id: match.params.version, -// }, -// }), -// }), -// graphql(uploadReviewFilesMutation, { name: 'uploadReviewFilesMutation' }), -// graphql(updateReviewMutation, { name: 'updateReviewMutation' }), -// graphql(updateTeam, { name: 'updateTeam' }), -// graphql(createFileMutation, { -// props: ({ mutate, ownProps: { match } }) => ({ -// createFile: file => { -// mutate({ -// variables: { -// file, -// }, -// update: (proxy, { data: { createFile } }) => { -// const data = proxy.readQuery({ -// query, -// variables: { -// id: match.params.version, -// }, -// }) - -// data.manuscript.reviews.map(review => { -// if (review.id === file.objectId) { -// review.comments.map(comment => { -// if (comment.type === createFile.fileType) { -// comment.files = [createFile] -// } -// return comment -// }) -// } -// return review -// }) - -// proxy.writeQuery({ query, data }) -// }, -// }) -// }, -// }), -// }), -// withLoader(), -// withProps( -// ({ -// manuscript, -// currentUser, -// match: { -// params: { journal }, -// }, -// updateReviewMutation, -// uploadReviewFilesMutation, -// updateTeam, -// createFile, -// }) => ({ -// journal: { id: journal }, -// review: -// manuscript.reviews.find( -// review => review.user.id === currentUser.id && !review.isDecision, -// ) || {}, -// status: ( -// ( -// (manuscript.teams.find(team => team.role === 'reviewer') || {}) -// .status || [] -// ).find(status => status.user === currentUser.id) || {} -// ).status, -// updateReview: (review, file) => { -// ;(review.comments || []).map(comment => { -// delete comment.files -// delete comment.__typename -// return comment -// }) - -// const reviewData = { -// recommendation: review.recommendation, -// comments: review.comments, -// manuscriptId: manuscript.id, -// } - -// return updateReviewMutation({ -// variables: { -// id: review.id || undefined, -// input: reviewData, -// }, -// update: (proxy, { data: { updateReview } }) => { -// const data = JSON.parse( -// JSON.stringify( -// proxy.readQuery({ -// query, -// variables: { -// id: manuscript.id, -// }, -// }), -// ), -// ) -// let reviewIndex = data.manuscript.reviews.findIndex( -// review => review.id === updateReview.id, -// ) -// reviewIndex = reviewIndex < 0 ? 0 : reviewIndex -// data.manuscript.reviews[reviewIndex] = updateReview -// proxy.writeQuery({ query, data }) -// }, -// }) -// }, -// uploadFile: (file, updateReview, type) => -// uploadReviewFilesMutation({ -// variables: { -// file, -// }, -// }).then(({ data }) => { -// const newFile = { -// url: data.upload.url, -// filename: file.name, -// mimeType: file.type, -// size: file.size, -// object: 'Review', -// objectId: updateReview.id, -// fileType: type, -// } -// createFile(newFile) -// }), -// completeReview: history => { -// const team = cloneDeep(manuscript.teams).find( -// team => team.role === 'reviewer', -// ) -// team.members = team.members.map(m => { -// if (m.user.id === currentUser.id) { -// return { user: { id: m.user.id }, status: 'completed' } -// } -// return { user: { id: m.user.id }, status: m.status } -// }) - -// updateTeam({ -// variables: { -// id: team.id, -// input: { -// members: team.members, -// }, -// }, -// }).then(() => { -// history.push('/dashboard') -// }) -// }, -// }), -// ), -// withFormik({ -// mapPropsToValues: props => -// props.manuscript.reviews.find( -// review => review.user.id === props.currentUser.id && !review.isDecision, -// ) || { -// id: null, -// comments: [], -// recommendation: null, -// }, -// isInitialValid: ({ review }) => { -// if (!review.id) return false -// const hasRecommendation = review.recommendation !== null -// const comment = getCommentContent(review, 'note') -// const isCommented = comment !== null && comment !== '' - -// return isCommented && hasRecommendation -// }, -// displayName: 'review', -// handleSubmit: (props, { props: { completeReview, history } }) => -// completeReview(history), -// }), -// )(ReviewLayout) diff --git a/app/components/component-review/src/components/ReviewersPage.js b/app/components/component-review/src/components/ReviewersPage.js index 33ae162f81c2cde8fd1a89cf0aa5ee23a150687d..3c60c1b671a1ce4dc5a269eb26d5bb6d887d5860 100644 --- a/app/components/component-review/src/components/ReviewersPage.js +++ b/app/components/component-review/src/components/ReviewersPage.js @@ -9,9 +9,8 @@ const teamFields = ` id role name - object { - objectId - objectType + manuscript { + id } members { id @@ -46,17 +45,6 @@ const fragmentFields = ` open recommendation created - comments { - type - content - files { - fileType - id - label - url - filename - } - } user { id username @@ -114,8 +102,8 @@ const ReviewersPage = ({ match, history }) => { update: (cache, { data: { addReviewer } }) => { cache.modify({ id: cache.identify({ - __typename: addReviewer.object.objectType, - id: addReviewer.object.objectId, + __typename: 'Manuscript', + id: addReviewer.manuscript.id, }), fields: { teams(existingTeamRefs = []) { diff --git a/app/components/component-review/src/components/assignEditors/AssignEditor.js b/app/components/component-review/src/components/assignEditors/AssignEditor.js index f40d62c40715c1f6661e4ded7be794b2380b6714..d90c4328bc0ca22991ca52039ac5abbdfb945167 100644 --- a/app/components/component-review/src/components/assignEditors/AssignEditor.js +++ b/app/components/component-review/src/components/assignEditors/AssignEditor.js @@ -16,9 +16,8 @@ const teamFields = ` id name role - object { - objectId - objectType + manuscript { + id } members { id @@ -81,7 +80,7 @@ const AssignEditor = ({ } }} options={options} - placeholder="Assign an editor…" + placeholder={`Assign ${teamName}…`} value={value} /> ) @@ -113,8 +112,7 @@ export default compose( props: ({ mutate, ownProps }) => { const createTeam = (userId, teamRole) => { const input = { - objectId: ownProps.manuscript.id, - objectType: 'Manuscript', + manuscriptId: ownProps.manuscript.id, name: teamRole === 'seniorEditor' ? 'Senior Editor' : 'Handling Editor', role: teamRole, diff --git a/app/components/component-review/src/components/decision/DecisionForm.js b/app/components/component-review/src/components/decision/DecisionForm.js index fb0b035a64a8126e3ddad2903687eda9bfca2f46..cb5ae93c57495d6942b9ec80b9c01bcf1b3ece70 100644 --- a/app/components/component-review/src/components/decision/DecisionForm.js +++ b/app/components/component-review/src/components/decision/DecisionForm.js @@ -1,23 +1,19 @@ import React, { useContext } from 'react' import { NoteEditor } from 'xpub-edit' -import { cloneDeep, omit } from 'lodash' -import { Field } from 'formik' +// import { cloneDeep, omit } from 'lodash' +import { Field, ErrorMessage } from 'formik' import { Button, - Flexbox, + // Flexbox, RadioGroup, - UploadButton, - UploadingFile, + // UploadButton, + // UploadingFile, } from '@pubsweet/ui' import { JournalContext } from '../../../../xpub-journal/src' import { required } from '../../../../xpub-validators/src' +import { FilesUpload } from '../../../../shared' -import { - getCommentFiles, - getCommentContent, - stripHtml, - createComments, -} from '../review/util' +import { reviewWithComment } from '../review/util' import { Container, @@ -26,138 +22,158 @@ import { SectionRowGrid, SectionRow, SectionAction, + FormStatus, + ErrorText, + ErrorWrap, } from '../style' -const NoteDecision = ({ updateReview, uploadFile }) => ( +// import Wax from '../../../../wax-collab/src/Editoria' + +const NoteDecision = ({ updateReview }) => ( <> - <Field - component={NoteInput} - key="commentinput" - name="comments" - updateReview={updateReview} - validate={required} - /> - <Field - component={AttachmentsInput('note')} - key="attachmentinput" - updateReview={updateReview} - uploadFile={uploadFile} - /> + <Field key="noteField" name="decisionComment"> + {formikBag => ( + <> + <NoteInput updateReview={updateReview} {...formikBag} /> + <FilesUpload + containerId={formikBag.field.value?.id} + containerName="reviewComment" + fieldName="decisionComment.files" + initializeContainer={async () => { + const review = reviewWithComment({ + commentType: 'decision', + isDecision: true, + values: formikBag.form.values, + name: 'decisionComment', + }) + const { data } = await updateReview(review) + return data.updateReview.decisionComment.id + }} + /> + </> + )} + </Field> </> ) const NoteInput = ({ field, - form: { values, setFieldValue }, + form: { errors, setFieldValue, setFieldTouched }, updateReview, }) => ( - <NoteEditor - key="note-input" - onBlur={() => {}} - onChange={value => { - const { updateIndex, comment } = createComments( - values, - { - type: 'note', - content: stripHtml(value), - }, - 'note', - ) - - setFieldValue(`comments.${updateIndex}`, comment) - updateReview( - cloneDeep(omit({ comment }, ['comment.files', 'comment.__typename'])), - ) - }} - placeholder="Write/paste your decision letter here, or upload it using the upload button on the right." - value={getCommentContent({ comments: field.value }, 'note')} - /> -) + // const review = useState() -const AttachmentsInput = type => ({ - field, - form: { values, setFieldValue }, - updateReview, - uploadFile, -}) => ( - <> - <UploadButton - buttonText="↑ Upload files" - key="note-attachment" - onChange={event => { - const val = event.target.files[0] - const file = cloneDeep(val) - file.filename = val.name - file.type = type + // const review = useRef({}) - const { updateIndex, comment } = createComments( - field.value, - { files: [file] }, - type, - ) + // useEffect(() => { + // review.current = reviewWithComment({ + // id: values.decisionComment?.id, + // values, + // commentType: 'decision', + // name: 'decisionComment', + // isDecision: true, + // }) + // }, [values]) - setFieldValue(`comments.${updateIndex}.files`, comment.files) + // console.log('Rendering', review.current) + <ErrorWrap error={errors.decisionComment}> + { + // TODO: Use the best text editor there is! + /* <Wax + // fileUpload={fileUpload} + // onChange={source => updateManuscript({ source })} + content={field.value?.content} + /> */ + } - updateReview({}).then(({ data: { updateReview } }) => { - uploadFile(val, updateReview, type) + <NoteEditor + data-testid="decisionComment" + debounceDelay={300} + key="note-input" + onBlur={() => setFieldTouched('decisionComment')} + onChange={value => { + setFieldValue('decisionComment', { content: value }) + updateReview({ + decisionComment: { content: value }, }) }} + placeholder="Write/paste your decision letter here, or upload it using the upload button on the right." + value={field.value?.content || ''} /> - <Flexbox> - {getCommentFiles(field.value, 'note').map(val => { - const file = cloneDeep(val) - file.name = file.filename - return <UploadingFile file={file} key={file.name} uploaded /> - })} - </Flexbox> - </> + <ErrorText> + <ErrorMessage name="decisionComment" /> + </ErrorText> + </ErrorWrap> ) const RecommendationInput = ({ field, - form: { setFieldValue }, + form: { setFieldValue, errors }, updateReview, }) => { const journal = useContext(JournalContext) return ( - <RadioGroup - {...field} - inline - onChange={val => { - setFieldValue(`recommendation`, val) - updateReview({ recommendation: val }) - }} - options={journal.recommendations} - value={field.value === '' ? null : field.value} - /> + <div> + <RadioGroup + {...field} + inline + onChange={val => { + setFieldValue('recommendation', val) + updateReview({ recommendation: val }) + }} + options={journal.recommendations} + value={field.value === '' ? null : field.value} + /> + <ErrorMessage name="recommendation" /> + </div> ) } -const DecisionForm = ({ handleSubmit, uploadFile, updateReview, isValid }) => ( - <Container key="decisionform"> - <form onSubmit={handleSubmit}> - <SectionHeader> - <Title>Decision</Title> - </SectionHeader> - <SectionRow key="note"> - <NoteDecision updateReview={updateReview} uploadFile={uploadFile} /> - </SectionRow> - <SectionRowGrid> - <Field - component={RecommendationInput} - name="recommendation" - updateReview={updateReview} - validate={required} - /> +const DecisionForm = ({ + handleSubmit, + updateReview, + isValid, + isSubmitting, + submitCount, + dirty, +}) => { + let status = null + if (isSubmitting) { + status = 'Your decision is submitting...' + } else if (submitCount) { + status = 'Your decision has been saved.' + } - <SectionAction key="submit"> - <Button disabled={!isValid} primary type="submit"> - Submit - </Button> - </SectionAction> - </SectionRowGrid> - </form> - </Container> -) + return ( + <Container key="decisionform"> + <form onSubmit={handleSubmit}> + <SectionHeader> + <Title>Decision</Title> + </SectionHeader> + <SectionRow key="note"> + <NoteDecision updateReview={updateReview} /> + </SectionRow> + <SectionRowGrid> + <Field + component={RecommendationInput} + name="recommendation" + updateReview={updateReview} + validate={required} + /> + <FormStatus>{status}</FormStatus> + <SectionAction key="submit"> + <Button + disabled={!isValid || isSubmitting || !dirty} + primary + type="submit" + > + Submit + </Button> + </SectionAction> + </SectionRowGrid> + </form> + </Container> + ) +} export default DecisionForm diff --git a/app/components/component-review/src/components/decision/DecisionReviews.js b/app/components/component-review/src/components/decision/DecisionReviews.js index b7bcab3bd4252b71f56f752800d75ed56aff5d5e..5e689ae81834c98f89f746345cc97d54515fbc88 100644 --- a/app/components/component-review/src/components/decision/DecisionReviews.js +++ b/app/components/component-review/src/components/decision/DecisionReviews.js @@ -15,7 +15,7 @@ const getCompletedReviews = (manuscript, currentUser) => { if (!team.members) { return null } - const currentMember = team.members.find(m => m.user.id === currentUser.id) + const currentMember = team.members.find(m => m.user?.id === currentUser?.id) return currentMember && currentMember.status } diff --git a/app/components/component-review/src/components/review/Review.js b/app/components/component-review/src/components/review/Review.js index e8e3c65dc6850e54f3fdc01d13de77d0ea4ce077..596489beebfb1a7bb5c1a1d18f3e7f9726602a72 100644 --- a/app/components/component-review/src/components/review/Review.js +++ b/app/components/component-review/src/components/review/Review.js @@ -3,7 +3,6 @@ import styled from 'styled-components' import { NoteViewer } from 'xpub-edit' import { Attachment } from '@pubsweet/ui' import { th, grid } from '@pubsweet/ui-toolkit' -import { getCommentFiles } from './util' const Heading = styled.div`` const Note = styled.div` @@ -23,17 +22,12 @@ const filesToAttachment = file => ({ url: file.url, }) -const findComments = (review = {}, type) => { - const comments = review.comments || [] - return comments.find(comment => comment.type === type) -} - const ReviewComments = (review, type) => ( <Note> <Content> - <NoteViewer value={findComments(review, type).content} /> + <NoteViewer value={review[`${type}Comment`].content} /> </Content> - {getCommentFiles(review, type).map(attachment => ( + {review[`${type}Comment`].files.map(attachment => ( <Attachment file={filesToAttachment(attachment)} key={attachment.url} @@ -45,14 +39,14 @@ const ReviewComments = (review, type) => ( const Review = ({ review }) => ( <Container> - {findComments(review, 'note') && ( + {review.reviewComment && ( <div> - <Heading>Note</Heading> + <Heading>Review</Heading> - {ReviewComments(review, 'note')} + {ReviewComments(review, 'review')} </div> )} - {findComments(review, 'confidential') && ( + {review.confidentialComment && ( <div> <Heading>Confidential</Heading> diff --git a/app/components/component-review/src/components/review/ReviewForm.js b/app/components/component-review/src/components/review/ReviewForm.js index 006bf2dbef454c685e951e185facc6e5a2628746..d68150650124824d4a09169ca4ffb1ae48efa03d 100644 --- a/app/components/component-review/src/components/review/ReviewForm.js +++ b/app/components/component-review/src/components/review/ReviewForm.js @@ -1,17 +1,10 @@ import React, { useContext } from 'react' -import { cloneDeep, set } from 'lodash' import { Field } from 'formik' import { NoteEditor } from 'xpub-edit' -import { - Button, - Flexbox, - RadioGroup, - UploadButton, - UploadingFile, -} from '@pubsweet/ui' +import { Button, RadioGroup } from '@pubsweet/ui' import { JournalContext } from '../../../../xpub-journal/src' -import { getCommentFiles, stripHtml, createComments } from './util' +import { reviewWithComment } from './util' import { AdminSection, Container, @@ -21,46 +14,47 @@ import { SectionRow, SectionAction, } from '../style' +import { FilesUpload } from '../../../../shared' -const AttachmentsInput = ({ - field, - form: { values }, - updateReview, - uploadFile, - type, -}) => ( - <> - <UploadButton - buttonText="↑ Upload files" - onChange={event => { - const val = event.target.files[0] - const file = cloneDeep(val) - file.filename = val.name - file.type = type +// const AttachmentsInput = ({ +// field, +// form: { values }, +// updateReview, +// uploadFile, +// type, +// }) => ( +// <> +// <UploadButton +// buttonText="↑ Upload files" +// onChange={event => { +// const val = event.target.files[0] +// const file = cloneDeep(val) +// file.filename = val.name +// file.type = type - const { updateIndex, comment } = createComments( - values, - { files: [file] }, - type, - ) +// const { updateIndex, comment } = createComments( +// values, +// { files: [file] }, +// type, +// ) - const data = cloneDeep(values) - set(data, `comments.${updateIndex}`, comment) +// const data = cloneDeep(values) +// set(data, `comments.${updateIndex}`, comment) - updateReview(data).then(({ data: { updateReview } }) => { - uploadFile(val, updateReview, type) - }) - }} - /> - <Flexbox> - {getCommentFiles(values, type).map(val => { - const file = cloneDeep(val) - file.name = file.filename - return <UploadingFile file={file} key={file.name} uploaded /> - })} - </Flexbox> - </> -) +// updateReview(data).then(({ data: { updateReview } }) => { +// uploadFile(val, updateReview, type) +// }) +// }} +// /> +// <Flexbox> +// {getCommentFiles(values, type).map(val => { +// const file = cloneDeep(val) +// file.name = file.filename +// return <UploadingFile file={file} key={file.name} uploaded /> +// })} +// </Flexbox> +// </> +// ) const NoteInput = ({ field, @@ -69,26 +63,22 @@ const NoteInput = ({ ...rest }) => ( <NoteEditor + data-testid="reviewComment" key="note-comment" placeholder="Enter your review…" title="Comments to the Author" {...field} onBlur={value => { - const { comment } = createComments( - values, - { - type: 'note', - content: stripHtml(value), - }, - 'note', - ) - - setFieldValue(`comments.0`, comment) - const data = cloneDeep(values) - set(data, `comments.0`, comment) - updateReview(data) + // const review = reviewWithComment({ + // id: values.reviewComment?.id, + // value, + // values, + // commentType: 'review', + // name: 'reviewComment', + // }) + updateReview({ reviewComment: { content: value } }) }} - value={field.value || ''} + value={field.value?.content || ''} /> ) @@ -98,26 +88,22 @@ const ConfidentialInput = ({ updateReview, }) => ( <NoteEditor + data-testid="confidentialComment" key="confidential-comment" placeholder="Enter a confidential note to the editor (optional)…" title="Confidential Comments to Editor (Optional)" {...field} onBlur={value => { - const { comment } = createComments( - values, - { - type: 'confidential', - content: stripHtml(value), - }, - 'confidential', - ) - - setFieldValue(`comments.1`, comment) - const data = cloneDeep(values) - set(data, `comments.1`, comment) - updateReview(data) + // const review = reviewWithComment({ + // id: values.confidentialComment?.id, + // value, + // values, + // commentType: 'confidential', + // name: 'confidentialComment', + // }) + updateReview({ confidentialComment: { content: value } }) }} - value={field.value || ''} + value={field.value?.content || ''} /> ) @@ -127,39 +113,76 @@ const RecommendationInput = ({ field, form: { values }, updateReview }) => { <RadioGroup inline {...field} + data-testid="recommendation" onChange={val => { - const data = cloneDeep(values) - set(data, 'recommendation', val) - updateReview(data) + updateReview({ recommendation: val }) }} options={journal.recommendations} /> ) } -const ReviewComment = props => ( +const ReviewComment = ({ updateReview }) => ( <> <AdminSection> <div name="note"> - <Field key="noteField" name="comments.0.content"> - {extraProps => <NoteInput {...props} {...extraProps} />} - </Field> - <Field - component={extraProps => ( - <AttachmentsInput type="note" {...props} {...extraProps} /> + <Field key="noteField" name="reviewComment"> + {formikBag => ( + <> + <NoteInput updateReview={updateReview} {...formikBag} /> + <FilesUpload + containerId={formikBag.field.value?.id} + containerName="reviewComment" + fieldName="reviewComment.files" + initializeContainer={async () => { + // If the container for the uploaded files is not present, + // we have to create it. InitializeContainer will be called + // if containerId is undefined + const review = reviewWithComment({ + commentType: 'review', + values: formikBag.form.values, + name: 'reviewComment', + }) + // This is an upsert + const { data } = await updateReview(review) + // And we the return the file container id, so + // that we have somewhere to attach uploaded files + return data.updateReview.reviewComment.id + }} + /> + </> )} - /> + </Field> </div> </AdminSection> <AdminSection> <div name="confidential"> - <Field key="confidentialField" name="comments.1.content"> - {extraProps => <ConfidentialInput {...props} {...extraProps} />} - </Field> - <Field - component={extraProps => ( - <AttachmentsInput type="confidential" {...props} {...extraProps} /> + <Field key="confidentialField" name="confidentialComment"> + {formikBag => ( + <> + <ConfidentialInput updateReview={updateReview} {...formikBag} /> + <FilesUpload + containerId={formikBag.field.value?.id} + containerName="reviewComment" + fieldName="confidentialComment.files" + initializeContainer={async () => { + // If the container for the uploaded files is not present, + // we have to create it. InitializeContainer will be called + // if containerId is undefined + const review = reviewWithComment({ + commentType: 'confidential', + values: formikBag.form.values, + name: 'confidentialComment', + }) + // This is an upsert + const { data } = await updateReview(review) + // And we the return the file container id, so + // that we have somewhere to attach uploaded files + return data.updateReview.confidentialComment.id + }} + /> + </> )} - /> + </Field> </div> </AdminSection> </> @@ -181,11 +204,7 @@ const ReviewForm = ({ <Title>Review</Title> </SectionHeader> <SectionRow key="note"> - <ReviewComment - review={review} - updateReview={updateReview} - uploadFile={uploadFile} - /> + <ReviewComment review={review} updateReview={updateReview} /> </SectionRow> <SectionHeader> <Title>Recommendation</Title> diff --git a/app/components/component-review/src/components/review/util.js b/app/components/component-review/src/components/review/util.js index a760b1ba6da04d9e430ba7cbd223e6fe334d8364..b382a482636feb3f3e950e37866c7410aac0dd5c 100644 --- a/app/components/component-review/src/components/review/util.js +++ b/app/components/component-review/src/components/review/util.js @@ -4,35 +4,21 @@ export const stripHtml = htmlString => { return temp.textContent } -export const getCommentFiles = (review = {}, type) => { - const comments = - (review.comments || []).find(comment => (comment || {}).type === type) || {} - return comments.files || [] -} - -export const getCommentContent = (review = {}, type) => { - const comments = - (review.comments || []).find(comment => (comment || {}).type === type) || {} - return comments.content || '' -} - -export const createComments = (values, val, type) => { - let updateIndex = (values.comments || []).findIndex( - comment => (comment || {}).type === type, - ) - updateIndex = - (values.comments || []).length > 0 && updateIndex < 0 ? 1 : updateIndex - updateIndex = updateIndex < 0 ? 0 : updateIndex - - const comment = Object.assign( - { - type, - content: '', - files: [], - }, - (values.comments || [])[updateIndex], - val, - ) +export const reviewWithComment = ({ + id, + value, + values, + commentType, + name, + isDecision, +}) => { + const data = { id: values.id } - return { updateIndex, comment } + data.isDecision = isDecision + data[name] = { + id, + commentType, + content: value ? stripHtml(value) : '', + } + return data } diff --git a/app/components/component-review/src/components/reviewers/Reviewers.js b/app/components/component-review/src/components/reviewers/Reviewers.js index 7935205aaf4f36260233d9db89b11d8d6df84bec..5ff9ad3024d1df2a45274171f193e96e9f320f56 100644 --- a/app/components/component-review/src/components/reviewers/Reviewers.js +++ b/app/components/component-review/src/components/reviewers/Reviewers.js @@ -43,9 +43,7 @@ const Reviewers = ({ <Heading>Reviewers</Heading> <Button onClick={() => - history.push( - `/journal/versions/${manuscript.id}/decisions/${manuscript.id}`, - ) + history.push(`/journal/versions/${manuscript.id}/decision`) } primary > diff --git a/app/components/component-review/src/components/style.js b/app/components/component-review/src/components/style.js index c4b49a22d76b59e398ad3565f80a04fcd111dfa7..97ac3ec29fa133d9479466d57424f991254997c8 100644 --- a/app/components/component-review/src/components/style.js +++ b/app/components/component-review/src/components/style.js @@ -1,4 +1,4 @@ -import styled from 'styled-components' +import styled, { css } from 'styled-components' import { th, grid } from '@pubsweet/ui-toolkit' export const Columns = styled.div` @@ -77,6 +77,36 @@ export const Container = styled.div` } ` +export const FormStatus = styled.div` + line-height: ${grid(5)}; + text-align: center; + color: ${th('colorSecondary')}; +` + +export const ErrorWrap = styled.div` + .ProseMirror { + margin-bottom: ${grid(4)}; + } + ${({ error }) => + error && + css` + .ProseMirror { + border-color: red; + } + ${ErrorText} { + margin-top: ${grid(-4)}; + margin-bottom: ${grid(1)}; + } + `} + + [class*="MenuBar"] { + margin-top: 0; + } +` +export const ErrorText = styled.div` + color: red; +` + export { Title, SectionHeader, diff --git a/app/components/component-submit/src/components/FormTemplate.js b/app/components/component-submit/src/components/FormTemplate.js index 092be22b20b10b94f065ae32c2e9b364f37a0317..f23d8e4ee663a89668791247bbb69b054c8be5c2 100644 --- a/app/components/component-submit/src/components/FormTemplate.js +++ b/app/components/component-submit/src/components/FormTemplate.js @@ -12,10 +12,9 @@ import { } from '@pubsweet/ui' import * as validators from 'xpub-validators' import { AbstractEditor } from 'xpub-edit' -import { Section as Container, Select } from '../../../shared' +import { Section as Container, Select, FilesUpload } from '../../../shared' import { Heading1, Section, Legend, SubNote } from '../style' import AuthorsInput from './AuthorsInput' -import Supplementary from './Supplementary' import Confirm from './Confirm' // TODO: https://github.com/formium/formik/issues/146#issuecomment-474775723 @@ -267,8 +266,10 @@ export default ({ {/* <p>{JSON.stringify(element)}</p> */} <Legend dangerouslySetInnerHTML={createMarkup(element.title)} /> {element.component === 'SupplementaryFiles' && ( - <Supplementary - createSupplementaryFile={createSupplementaryFile} + <FilesUpload + containerId={manuscript.id} + containerName="manuscript" + fileType="supplementary" onChange={onChange} /> )} diff --git a/app/components/component-submit/src/components/SubmitPage.js b/app/components/component-submit/src/components/SubmitPage.js index c510504b92d171e1d410ae6b3df910f63d339f59..4da4c390a62708307b6e50156851e2e87826c011 100644 --- a/app/components/component-submit/src/components/SubmitPage.js +++ b/app/components/component-submit/src/components/SubmitPage.js @@ -25,9 +25,6 @@ const fragmentFields = ` recommendation created isDecision - comments { - content - } user { id username @@ -125,21 +122,6 @@ const updateMutation = gql` // } // ` -const createFileMutation = gql` - mutation($file: Upload!, $meta: FileMetaInput) { - createFile(file: $file, meta: $meta) { - id - created - label - filename - fileType - mimeType - size - url - } - } -` - const SubmitPage = ({ match, history, ...props }) => { const [confirming, setConfirming] = useState(false) @@ -151,26 +133,6 @@ const SubmitPage = ({ match, history, ...props }) => { variables: { id: match.params.version, form: 'submit' }, }) - const [createFile] = useMutation(createFileMutation) - - const createSupplementaryFile = file => { - const meta = { - filename: file.name, - mimeType: file.type, - size: file.size, - fileType: 'supplementary', - object: 'Manuscript', - objectId: match.params.version, - } - - createFile({ - variables: { - file, - meta, - }, - }) - } - const [update] = useMutation(updateMutation) if (loading) return <Spinner /> @@ -226,7 +188,6 @@ const SubmitPage = ({ match, history, ...props }) => { {props => ( <Submit confirming={confirming} - createSupplementaryFile={createSupplementaryFile} forms={cloneDeep(getFile)} manuscript={manuscript} onChange={handleChange} diff --git a/app/components/component-submit/src/components/Supplementary.js b/app/components/component-submit/src/components/Supplementary.js deleted file mode 100644 index 0432c9488da0896b8e7e21522fc7629516d82cc2..0000000000000000000000000000000000000000 --- a/app/components/component-submit/src/components/Supplementary.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react' -import { cloneDeep } from 'lodash' -import { FieldArray } from 'formik' -import { Flexbox, UploadButton, UploadingFile } from '@pubsweet/ui' - -const renderFilesUpload = (onChange, createSupplementaryFile) => ({ - form: { values, setFieldValue }, - push, - insert, -}) => ( - <> - <UploadButton - buttonText="↑ Upload files" - onChange={event => { - const fileArray = Array.from(event.target.files).map(file => { - const fileUpload = { - fileType: 'supplementary', - filename: file.name, - } - return fileUpload - }) - setFieldValue('files', fileArray.concat(values.files)) - Array.from(event.target.files).forEach(file => { - createSupplementaryFile(file) - }) - }} - /> - <Flexbox> - {cloneDeep(values.files || []) - .filter(val => val.fileType === 'supplementary') - .map(val => { - val.name = val.filename - return <UploadingFile file={val} key={val.name} uploaded /> - })} - </Flexbox> - </> -) - -const Supplementary = ({ onChange, createSupplementaryFile }) => ( - <FieldArray - name="files" - render={renderFilesUpload(onChange, createSupplementaryFile)} - /> -) - -export default Supplementary diff --git a/app/components/component-submit/src/components/UploadButton.js b/app/components/component-submit/src/components/UploadButton.js new file mode 100644 index 0000000000000000000000000000000000000000..fb6c96449dceff7ad115457742617e4072406a7d --- /dev/null +++ b/app/components/component-submit/src/components/UploadButton.js @@ -0,0 +1,33 @@ +import React from 'react' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' + +const Button = styled.button.attrs(() => ({ + type: 'button', +}))` + background: transparent; + border: ${th('borderWidth')} dashed ${th('colorBorder')}; + height: calc(${th('gridUnit')} * 3); + cursor: pointer; + margin-bottom: calc(${th('gridUnit')} * 3); + padding: ${th('gridUnit')}; +` + +const UploadButton = ({ name, buttonText, onChange }) => { + let fileInput + return ( + <React.Fragment> + <Button onClick={() => fileInput.click()}>{buttonText}</Button> + <input + multiple + name={name} + onChange={onChange} + ref={input => (fileInput = input)} + style={{ display: 'none' }} + type="file" + /> + </React.Fragment> + ) +} + +export default UploadButton diff --git a/app/components/component-submit/src/components/UploadManuscript.js b/app/components/component-submit/src/components/UploadManuscript.js index cdb5e7e0bed5cceb05818b51c8313b0736ebd587..807e004c4350ab54642dd32e46261722fb931738 100644 --- a/app/components/component-submit/src/components/UploadManuscript.js +++ b/app/components/component-submit/src/components/UploadManuscript.js @@ -2,17 +2,9 @@ import React, { useContext } from 'react' import styled, { keyframes, withTheme } from 'styled-components' import { Icon, Action } from '@pubsweet/ui' import { th } from '@pubsweet/ui-toolkit' -import Dropzone from 'react-dropzone' import { XpubContext } from '../../../xpub-with-context/src' import upload from '../upload' - -const StyledDropzone = styled(({ disableUpload, ...props }) => ( - <Dropzone {...props} /> -))` - border: none; - cursor: pointer; - ${({ disableUpload }) => disableUpload && 'pointer-events: none;'}; -` +import { Dropzone } from '../../../shared' const StatusIcon = withTheme(({ children, theme }) => ( <Icon color={theme.colorPrimary}>{children}</Icon> @@ -188,7 +180,7 @@ const UploadManuscript = ({ acceptFiles, ...props }) => { return ( <> - <StyledDropzone + <Dropzone accept={acceptFiles} data-testid="dropzone" disableUpload={converting ? 'disableUpload' : null} @@ -222,7 +214,7 @@ const UploadManuscript = ({ acceptFiles, ...props }) => { </SubInfo> </Root> )} - </StyledDropzone> + </Dropzone> <Action onClick={() => uploadManuscript()}>Submit a URL instead</Action> </> ) diff --git a/app/components/component-submit/src/upload.js b/app/components/component-submit/src/upload.js index 3a733062e9901182411a6d9212f342a7b835814f..2a33bc2cddca6daa657d46249bbb2e2d3e43754a 100644 --- a/app/components/component-submit/src/upload.js +++ b/app/components/component-submit/src/upload.js @@ -1,6 +1,7 @@ import config from 'config' import request from 'pubsweet-client/src/helpers/api' import gql from 'graphql-tag' +import currentRolesVar from '../../../shared/currentRolesVar' const generateTitle = name => name @@ -35,9 +36,8 @@ const createManuscriptMutation = gql` id role name - object { - objectId - objectType + manuscript { + id } members { id @@ -154,6 +154,11 @@ const createManuscriptPromise = ( mutation: createManuscriptMutation, variables: { input: manuscript }, update: (cache, { data: { createManuscript } }) => { + const currentRoles = currentRolesVar() + currentRolesVar([ + ...currentRoles, + { id: createManuscript.id, roles: ['author'] }, + ]) cache.modify({ fields: { manuscripts(existingManuscriptRefs = []) { diff --git a/app/components/component-teams-manager/src/components/Team.jsx b/app/components/component-teams-manager/src/components/Team.jsx deleted file mode 100644 index 66535822dfae39ab2d1e612b7141ca26b1721575..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/Team.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import styled from 'styled-components' -import { Button, Menu } from '@pubsweet/ui' -import { TeamTableCell } from './molecules/Table' - -const StyledMenu = styled(Menu)` - width: 100%; -` - -const Team = ({ team, number, userOptions, deleteTeam, updateTeam }) => ( - <> - <TeamTableCell width={5}>{number}</TeamTableCell> - <TeamTableCell> - {team.name} {team.role} - </TeamTableCell> - <TeamTableCell> - {team.object && team.object.objectType}{' '} - {team.object && team.object.objectId} - </TeamTableCell> - <TeamTableCell width={40}> - <StyledMenu - inline - multi - name="members" - onChange={members => updateTeam(members, team)} - options={userOptions} - value={team.members.map(member => member.user && member.user.id)} - /> - </TeamTableCell> - <TeamTableCell width={15}> - <Button onClick={() => deleteTeam(team)}>Delete</Button> - </TeamTableCell> - </> -) - -export default Team diff --git a/app/components/component-teams-manager/src/components/TeamCreator.jsx b/app/components/component-teams-manager/src/components/TeamCreator.jsx deleted file mode 100644 index 1fb0aab0d6860db8017acd57dfbd3644882ebf10..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/TeamCreator.jsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react' -import { find } from 'lodash' -import { compose, withHandlers, withState } from 'recompose' -import { Button, Menu } from '@pubsweet/ui' - -const TeamCreator = ({ - teamTypeSelected, - manuscriptSelected, - manuscriptsOptions, - typesOptions, - onChangeManuscript, - onChangeType, - onSave, -}) => ( - <form onSubmit={onSave}> - <h3>Create a new team</h3> - <h4>Team type</h4> - <Menu - name="teamType" - onChange={onChangeType} - options={typesOptions} - required - reset={teamTypeSelected} - value={teamTypeSelected} - /> - <h4>Manuscript</h4> - <Menu - name="collection" - onChange={onChangeManuscript} - options={manuscriptsOptions} - required - reset={manuscriptSelected} - value={manuscriptSelected} - /> - <Button primary type="submit"> - Create - </Button> - </form> -) - -export default compose( - withState('manuscriptSelected', 'onManuscriptSelect', false), - withState('teamTypeSelected', 'onTeamTypeSelect', false), - withHandlers({ - onChangeManuscript: ({ onManuscriptSelect }) => collectionId => - onManuscriptSelect(() => collectionId || false), - onChangeType: ({ onTeamTypeSelect }) => teamType => - onTeamTypeSelect(() => teamType || false), - onSave: ({ - teamTypeSelected, - manuscriptSelected, - create, - typesOptions, - onTeamTypeSelect, - onManuscriptSelect, - }) => event => { - event.preventDefault() - const role = teamTypeSelected - - let objectId - let objectType - - if (manuscriptSelected) { - objectId = manuscriptSelected - objectType = 'Manuscript' - } - - if (role && objectId && objectType) { - create({ - name: find(typesOptions, types => types.value === role).label, - role, - objectId, - objectType, - members: [], - }) - - onTeamTypeSelect(() => true) - onManuscriptSelect(() => true) - } - }, - }), -)(TeamCreator) diff --git a/app/components/component-teams-manager/src/components/TeamsManager.jsx b/app/components/component-teams-manager/src/components/TeamsManager.jsx deleted file mode 100644 index a7e75164e88770b167da1b3bd52e8e7ecea3009b..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/TeamsManager.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react' -import { Page } from './molecules/Page' -import { TeamTableCell, TeamTable } from './molecules/Table' -import Team from './Team' -import TeamCreator from './TeamCreator' - -const TeamsManager = ({ - teams = [], - updateTeam, - deleteTeam, - createTeam, - error, - userOptions, - manuscriptsOptions, - typesOptions, -}) => ( - <Page> - {error ? <div>{error}</div> : null} - {teams.length > 0 && ( - <TeamTable> - <TeamTableCell width={5}>#</TeamTableCell> - <TeamTableCell>Type</TeamTableCell> - <TeamTableCell>Object</TeamTableCell> - <TeamTableCell width={40}>Members</TeamTableCell> - <TeamTableCell width={15}>Actions</TeamTableCell> - - {teams.map((team, i) => ( - <Team - deleteTeam={deleteTeam} - key={team.id} - number={i + 1} - team={team} - updateTeam={updateTeam} - userOptions={userOptions} - /> - ))} - </TeamTable> - )} - <TeamCreator - create={createTeam} - manuscriptsOptions={manuscriptsOptions} - typesOptions={typesOptions} - /> - </Page> -) - -export default TeamsManager diff --git a/app/components/component-teams-manager/src/components/TeamsManager.test.js b/app/components/component-teams-manager/src/components/TeamsManager.test.js deleted file mode 100644 index dd22df93a54aa3d0cc1aa6e457e75d55f13f681e..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/TeamsManager.test.js +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react' -import Enzyme, { shallow } from 'enzyme' -import Adapter from 'enzyme-adapter-react-16' - -import TeamsManager from './TeamsManager' - -import Team from './Team' -import TeamCreator from './TeamCreator' - -// this should be elsewhere -Enzyme.configure({ adapter: new Adapter() }) - -jest.mock('config', () => ({ - 'pubsweet-client': {}, - authsome: { - mode: 'authsome', - teams: { - seniorEditor: { - name: 'Senior Editors', - permissions: '', - }, - handlingEditor: { - name: 'Handling Editors', - permissions: '', - }, - managingEditor: { - name: 'Managing Editors', - permissions: '', - }, - reviewer: { - name: 'Reviewer', - permissions: '', - }, - }, - }, -})) - -describe('TeamsManager', () => { - const makeWrapper = (props = {}) => { - props = Object.assign( - { - teams: [], - userOptions: [ - { id: '1', username: 'author' }, - { id: '2', username: 'managing Editor' }, - ], - }, - props, - ) - - return shallow(<TeamsManager {...props} />) - } - - it('shows nothing when there are no teams', () => { - const teammanager = makeWrapper() - expect(teammanager.find(Team)).toHaveLength(0) - expect(teammanager.find(TeamCreator)).toHaveLength(1) - }) - - it('shows a list of teams created', () => { - const teammanager = makeWrapper({ - teams: [ - { - id: 1, - name: 'team1', - teamType: { - name: 'Senior Editors', - permissions: '', - }, - object: { - type: 'collection', - id: '1', - }, - members: [], - }, - { - id: 1, - name: 'team2', - teamType: { - name: 'Handling Editors', - permissions: '', - }, - object: { - type: 'collection', - id: '1', - }, - members: [], - }, - ], - }) - - expect(teammanager.find(Team)).toHaveLength(2) - }) -}) diff --git a/app/components/component-teams-manager/src/components/TeamsManagerPage.js b/app/components/component-teams-manager/src/components/TeamsManagerPage.js deleted file mode 100644 index 9a4c7cd09b5e6a982bbc196665cd1bc6813261ae..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/TeamsManagerPage.js +++ /dev/null @@ -1,161 +0,0 @@ -import { compose } from 'recompose' -import { omit } from 'lodash' -import config from 'config' -import { graphql } from '@apollo/client/react/hoc' -import gql from 'graphql-tag' - -import queries from './graphql/queries' -import TeamsManager from './TeamsManager' - -const deleteTeamMutation = gql` - mutation($id: ID) { - deleteTeam(id: $id) { - id - } - } -` - -const createTeamMutation = gql` - mutation($input: TeamInput!) { - createTeam(input: $input) { - id - type - role - name - object { - objectId - objectType - } - members { - user { - id - username - } - } - } - } -` - -const updateTeamMutation = gql` - mutation($id: ID, $input: TeamInput) { - updateTeam(id: $id, input: $input) { - id - type - role - name - object { - objectId - objectType - } - members { - user { - id - username - } - } - } - } -` - -export default compose( - graphql(queries.teamManager, { - props: ({ data }) => { - const userOptions = ((data || {}).users || []).map(user => ({ - value: user.id, - label: user.username, - })) - - const manuscriptsOptions = ((data || {}).manuscripts || []).map(manu => ({ - value: manu.id, - label: manu.meta.title, - })) - - const types = config.authsome.teams - const typesOptions = Object.keys(types).map(type => ({ - value: type, - label: `${types[type].name} ${types[type].permissions}`, - })) - return { - teams: (data || {}).teams, - manuscriptsOptions, - userOptions, - typesOptions, - } - }, - }), - graphql(updateTeamMutation, { - props: ({ mutate }) => { - const updateTeam = (members, team) => { - let input = { - ...team, - objectId: team.object.objectId, - objectType: team.object.objectType, - object: undefined, - } - - input.members = members.map(m => ({ user: { id: m } })) - input = omit(input, ['id', 'object.__typename', '__typename']) - - mutate({ - variables: { - id: team.id, - input, - }, - }) - } - - return { - updateTeam, - } - }, - }), - graphql(deleteTeamMutation, { - props: ({ mutate }) => { - const deleteTeam = data => { - mutate({ - variables: { - id: data.id, - }, - }) - } - - return { - deleteTeam, - } - }, - options: { - update: (proxy, { data: { deleteTeam } }) => { - const data = proxy.readQuery({ query: queries.teamManager }) - const teamsIndex = data.teams.findIndex( - team => team.id === deleteTeam.id, - ) - if (teamsIndex > -1) { - data.teams.splice(teamsIndex, 1) - proxy.writeQuery({ query: queries.teamManager, data }) - } - }, - }, - }), - graphql(createTeamMutation, { - props: ({ mutate }) => { - const createTeam = input => { - mutate({ - variables: { - input, - }, - }) - } - - return { - createTeam, - } - }, - options: { - update: (proxy, { data: { createTeam } }) => { - const data = proxy.readQuery({ query: queries.teamManager }) - data.teams.push(createTeam) - proxy.writeQuery({ query: queries.teamManager, data }) - }, - }, - }), -)(TeamsManager) diff --git a/app/components/component-teams-manager/src/components/graphql/queries/index.js b/app/components/component-teams-manager/src/components/graphql/queries/index.js deleted file mode 100644 index 5f31211a9a822ee407c42ee44f00561366bf183b..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/graphql/queries/index.js +++ /dev/null @@ -1,44 +0,0 @@ -import gql from 'graphql-tag' - -const fragmentFields = ` - id - created - meta { - manuscriptId - title - } -` - -export default { - teamManager: gql` - query { - teams { - id - role - name - object { - objectId - objectType - } - members { - user { - id - } - } - } - - users { - id - username - admin - } - - manuscripts { - ${fragmentFields} - manuscriptVersions { - ${fragmentFields} - } - } - } - `, -} diff --git a/app/components/component-teams-manager/src/components/molecules/Page.js b/app/components/component-teams-manager/src/components/molecules/Page.js deleted file mode 100644 index 26240d8774892d07923e907f5a20580062dbca68..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/molecules/Page.js +++ /dev/null @@ -1,29 +0,0 @@ -import styled from 'styled-components' -import { th, grid } from '@pubsweet/ui-toolkit' - -const Page = styled.div` - padding: ${grid(2)}; -` - -const Section = styled.div` - margin: ${th('gridUnit')} 0; - - &:not(:last-of-type) { - margin-bottom: calc(${th('gridUnit')} * 2); - } -` - -const Heading = styled.div` - color: ${th('colorPrimary')}; - font-family: ${th('fontReading')}; - font-size: ${th('fontSizeHeading3')}; - margin: ${th('gridUnit')} 0; - text-transform: uppercase; -` - -const UploadContainer = styled.div` - display: flex; - justify-content: center; -` - -export { Page, Section, Heading, UploadContainer } diff --git a/app/components/component-teams-manager/src/components/molecules/Table.js b/app/components/component-teams-manager/src/components/molecules/Table.js deleted file mode 100644 index 4e7c813148d4f07c73b3b385e2fb94dfd85e638d..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/components/molecules/Table.js +++ /dev/null @@ -1,26 +0,0 @@ -import styled from 'styled-components' - -const TeamTable = styled.div` - display: flex; - flex-wrap: wrap; - margin: 0 0 3px 0; - padding: 0; -` - -const TeamTableCell = styled.div` - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - flex-grow: 1; - padding: 20px 10px 0 0; - list-style: none; - border: solid @bw white; - background: fade(slategrey, 20%); - width: ${props => props.width || 20}%; - > h4 { - margin: 0; - } -` - -export { TeamTable, TeamTableCell } diff --git a/app/components/component-teams-manager/src/index.js b/app/components/component-teams-manager/src/index.js deleted file mode 100644 index 0b91ce74b9fa94404bcd77c1b1784b65875382e1..0000000000000000000000000000000000000000 --- a/app/components/component-teams-manager/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - frontend: { - components: [() => require('./components/TeamsManagerPage')], - }, -} diff --git a/app/components/shared/Dropzone.jsx b/app/components/shared/Dropzone.jsx new file mode 100644 index 0000000000000000000000000000000000000000..29f979895c8b23e1da7ae91c4551ecc3737c6a7c --- /dev/null +++ b/app/components/shared/Dropzone.jsx @@ -0,0 +1,11 @@ +import React from 'react' +import styled from 'styled-components' +import ReactDropzone from 'react-dropzone' + +export const Dropzone = styled(({ disableUpload, ...props }) => ( + <ReactDropzone {...props} /> +))` + border: none; + cursor: pointer; + ${({ disableUpload }) => disableUpload && 'pointer-events: none;'}; +` diff --git a/app/components/shared/FilesUpload.js b/app/components/shared/FilesUpload.js new file mode 100644 index 0000000000000000000000000000000000000000..6fc7c38dbf316c77ad71feed744bbb2536d49760 --- /dev/null +++ b/app/components/shared/FilesUpload.js @@ -0,0 +1,139 @@ +import React from 'react' +import { cloneDeep, get } from 'lodash' +import { FieldArray } from 'formik' +import { grid, th } from '@pubsweet/ui-toolkit' +import styled from 'styled-components' +import { useMutation, gql } from '@apollo/client' +import UploadingFile from './UploadingFile' +import { Dropzone } from './Dropzone' +import { Icon } from './Icon' + +const Root = styled.div` + border: 1px dashed ${th('colorBorder')}; + height: ${grid(8)}; + border-radius: ${th('borderRadius')}; + text-align: center; + line-height: ${grid(8)}; +` + +const Files = styled.div` + margin-top: ${grid(2)}; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-gap: ${grid(2)}; +` + +const Message = styled.div` + display: flex; + width: 100%; + align-items: center; + justify-content: center; + svg { + margin-left: ${grid(1)}; + } +` + +const createFileMutation = gql` + mutation($file: Upload!, $meta: FileMetaInput) { + createFile(file: $file, meta: $meta) { + id + created + label + filename + fileType + mimeType + size + url + } + } +` + +const DropzoneAndList = ({ + form: { values, setFieldValue }, + push, + insert, + createFile, + deleteFile, + fileType, + fieldName, +}) => ( + <> + <Dropzone + onDrop={async files => { + Array.from(files).forEach(async file => { + const data = await createFile(file) + push(data.createFile) + }) + }} + > + {({ getRootProps, getInputProps }) => ( + <Root {...getRootProps()} data-testid="dropzone"> + <input {...getInputProps()} /> + <Message> + Drag and drop your files here + <Icon color={th('colorPrimary')} inline> + file-plus + </Icon> + </Message> + </Root> + )} + </Dropzone> + <Files> + {cloneDeep(get(values, fieldName) || []) + .filter(val => (fileType ? val.fileType === fileType : true)) + .map(val => { + val.name = val.filename + return <UploadingFile file={val} key={val.name} uploaded /> + })} + </Files> + </> +) + +const FilesUpload = ({ + fileType, + fieldName = 'files', + containerId, + containerName, + initializeContainer, +}) => { + const [createFile] = useMutation(createFileMutation) + // const [deleteFile] = useMutation(deleteFileMutation) + + const createFileWithMeta = async file => { + const meta = { + filename: file.name, + mimeType: file.type, + size: file.size, + fileType, + } + + // Create a container/parent for these files if one doesn't exist + const localContainerId = containerId || (await initializeContainer()) + + meta[`${containerName}Id`] = localContainerId + + const { data } = await createFile({ + variables: { + file, + meta, + }, + }) + return data + } + + return ( + <FieldArray + name={fieldName} + render={formikProps => ( + <DropzoneAndList + createFile={createFileWithMeta} + // deleteFile={deleteFile} + fieldName={fieldName} + fileType={fileType} + {...formikProps} + /> + )} + /> + ) +} +export { FilesUpload } diff --git a/app/components/shared/Icon.jsx b/app/components/shared/Icon.jsx index 9ffcb79c7f23c2a0b48e2bba5d5956ed09cd935e..311230387ec34741d874b7c81f37dec7963776be 100644 --- a/app/components/shared/Icon.jsx +++ b/app/components/shared/Icon.jsx @@ -6,15 +6,13 @@ import styled from 'styled-components' import { th } from '@pubsweet/ui-toolkit' const IconWrapper = styled.div` - display: flex; - -webkit-box-align: center; + display: ${({ inline }) => (inline ? 'inline-flex' : 'flex')}; align-items: center; - -webkit-box-pack: center; justify-content: center; opacity: 1; position: relative; border-radius: 6px; - padding: ${props => (props.noPadding ? '0' : '8px 12px')}; + padding: ${props => (props.noPadding || props.inline ? '0' : '8px 12px')}; svg { stroke: ${props => props.color || props.theme.colorText}; @@ -29,6 +27,7 @@ export const Icon = ({ color, size = 3, noPadding, + inline, ...props }) => { const name = _.upperFirst(_.camelCase(children)) @@ -37,6 +36,7 @@ export const Icon = ({ <IconWrapper className={className} color={color} + inline={inline} noPadding={noPadding} role="img" size={size} diff --git a/app/components/shared/UploadingFile.js b/app/components/shared/UploadingFile.js new file mode 100644 index 0000000000000000000000000000000000000000..5c7e9ab16caf1ec5577f84b795e08e79d493c559 --- /dev/null +++ b/app/components/shared/UploadingFile.js @@ -0,0 +1,121 @@ +import React from 'react' +import styled from 'styled-components' +import { th, grid } from '@pubsweet/ui-toolkit' + +const Icon = styled.div` + background: ${th('colorFurniture')}; + height: ${grid(10)}; + margin-bottom: ${th('gridUnit')}; + opacity: 0.5; + position: relative; + width: ${grid(10)}; + overflow: hidden; + padding: ${grid(1)}; + img { + width: ${grid(8)}; + } +` + +// const Progress = styled.div` +// color: ${th('colorTextReverse')}; +// display: block; +// position: absolute; +// bottom: ${th('gridUnit')}; +// left: ${grid(4)}; +// ` + +const Extension = styled.div` + background: ${th('colorText')}; + color: ${th('colorTextReverse')}; + font-size: ${th('fontSizeBaseSmall')}; + line-height: ${th('lineHeightBaseSmall')}; + left: ${grid(2)}; + position: absolute; + right: 0; + text-align: center; + text-transform: uppercase; + top: ${grid(2)}; +` + +const Filename = styled.div` + color: ${th('colorText')}; + font-size: ${th('fontSizeBaseSmall')}; + line-height: ${th('lineHeightBaseSmall')}; + font-style: italic; + max-width: ${grid(30)}; + text-overflow: ellipsis; + overflow: hidden; +` + +const Uploading = styled.div` + align-items: center; + display: block; + flex-direction: column; + margin-bottom: ${grid(3)}; + margin-right: ${grid(3)}; + position: relative; +` + +const Uploaded = styled(Uploading)` + &:hover ${Extension} { + background: ${th('colorTextReverse')}; + color: ${th('colorPrimary')}; + } + + &:hover ${Icon} { + opacity: 1; + background: ${th('colorPrimary')}; + // transform: skewY(6deg) rotate(-6deg); + } + + &:hover::after, + &:hover::before { + transform: scaleX(1); + } +` + +const ErrorWrapper = styled.div` + background: ${th('colorError')}; + border: calc(${th('borderWidth')} * 2) ${th('borderStyle')} + ${th('colorTextReverse')}; + color: ${th('colorTextReverse')}; + font-size: ${th('fontSizeBaseSmall')}; + line-height: ${th('lineHeightBaseSmall')}; + letter-spacing: 0.01em; + opacity: 1; + padding: ${th('gridUnit')} ${th('gridUnit')}; + position: absolute; + top: 25%; + z-index: 4; +` + +const getFileExtension = ({ name }) => name.replace(/^.+\./, '') + +const UploadingFile = ({ file, progress, error, uploaded }) => { + const Root = uploaded ? Uploaded : Uploading + + const extension = getFileExtension(file) + const isImage = file?.mimeType.startsWith('image/') + + return ( + <Root> + {!!error && <ErrorWrapper>{error}</ErrorWrapper>} + <Icon> + {isImage && <img alt={file.name} src={file.url} />} + {/* {!!progress && <Progress>{progress * 100}%</Progress>} */} + <Extension>{extension}</Extension> + </Icon> + <Filename> + {uploaded ? ( + <a download={file.name} href={file.url} title={file.name}> + {file.name} + </a> + ) : ( + file.name + )} + </Filename> + </Root> + ) +} + +export default UploadingFile diff --git a/app/components/shared/index.js b/app/components/shared/index.js index 9c03d0839662980df9d89035eb141a227f8a089b..beaf45b435875c15e1dd26d777a72b14deb3cd1c 100644 --- a/app/components/shared/index.js +++ b/app/components/shared/index.js @@ -8,3 +8,5 @@ export * from './Table' export * from './General' export * from './Badge' export * from './Select' +export * from './Dropzone' +export * from './FilesUpload' diff --git a/cypress/dumps/decision_completed.sql b/cypress/dumps/decision_completed.sql new file mode 100644 index 0000000000000000000000000000000000000000..131e3333d986432395c5488837c6c94cbd0f1a5b --- /dev/null +++ b/cypress/dumps/decision_completed.sql @@ -0,0 +1,886 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 10.5 +-- Dumped by pg_dump version 10.5 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: pgboss; Type: SCHEMA; Schema: -; Owner: test +-- + +CREATE SCHEMA pgboss; + + +ALTER SCHEMA pgboss OWNER TO test; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +-- +-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public; + + +-- +-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; + + +-- +-- Name: job_state; Type: TYPE; Schema: pgboss; Owner: test +-- + +CREATE TYPE pgboss.job_state AS ENUM ( + 'created', + 'retry', + 'active', + 'completed', + 'expired', + 'cancelled', + 'failed' +); + + +ALTER TYPE pgboss.job_state OWNER TO test; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: archive; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.archive ( + id uuid NOT NULL, + name text NOT NULL, + priority integer NOT NULL, + data jsonb, + state pgboss.job_state NOT NULL, + retrylimit integer NOT NULL, + retrycount integer NOT NULL, + retrydelay integer NOT NULL, + retrybackoff boolean NOT NULL, + startafter timestamp with time zone NOT NULL, + startedon timestamp with time zone, + singletonkey text, + singletonon timestamp without time zone, + expirein interval NOT NULL, + createdon timestamp with time zone NOT NULL, + completedon timestamp with time zone, + archivedon timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE pgboss.archive OWNER TO test; + +-- +-- Name: job; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.job ( + id uuid DEFAULT public.gen_random_uuid() NOT NULL, + name text NOT NULL, + priority integer DEFAULT 0 NOT NULL, + data jsonb, + state pgboss.job_state DEFAULT 'created'::pgboss.job_state NOT NULL, + retrylimit integer DEFAULT 0 NOT NULL, + retrycount integer DEFAULT 0 NOT NULL, + retrydelay integer DEFAULT 0 NOT NULL, + retrybackoff boolean DEFAULT false NOT NULL, + startafter timestamp with time zone DEFAULT now() NOT NULL, + startedon timestamp with time zone, + singletonkey text, + singletonon timestamp without time zone, + expirein interval DEFAULT '00:15:00'::interval NOT NULL, + createdon timestamp with time zone DEFAULT now() NOT NULL, + completedon timestamp with time zone +); + + +ALTER TABLE pgboss.job OWNER TO test; + +-- +-- Name: version; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.version ( + version text NOT NULL +); + + +ALTER TABLE pgboss.version OWNER TO test; + +-- +-- Name: aliases; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.aliases ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + name text, + email text, + aff text +); + + +ALTER TABLE public.aliases OWNER TO test; + +-- +-- Name: channel_members; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.channel_members ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + user_id uuid NOT NULL, + channel_id uuid NOT NULL +); + + +ALTER TABLE public.channel_members OWNER TO test; + +-- +-- Name: channels; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.channels ( + id uuid NOT NULL, + manuscript_id uuid, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + topic text, + type text +); + + +ALTER TABLE public.channels OWNER TO test; + +-- +-- Name: entities; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.entities ( + id uuid NOT NULL, + data jsonb +); + + +ALTER TABLE public.entities OWNER TO test; + +-- +-- Name: files; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.files ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + label text, + file_type text, + filename text, + url text, + mime_type text, + size integer, + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) +); + + +ALTER TABLE public.files OWNER TO test; + +-- +-- Name: identities; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.identities ( + id uuid NOT NULL, + user_id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + type text NOT NULL, + identifier text, + name text, + aff text, + oauth jsonb, + is_default boolean +); + + +ALTER TABLE public.identities OWNER TO test; + +-- +-- Name: manuscripts; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.manuscripts ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + parent_id uuid, + submitter_id uuid, + status text, + decision text, + authors jsonb, + suggestions jsonb, + meta jsonb, + submission jsonb, + type text NOT NULL +); + + +ALTER TABLE public.manuscripts OWNER TO test; + +-- +-- Name: messages; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.messages ( + id uuid NOT NULL, + user_id uuid NOT NULL, + channel_id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + content text +); + + +ALTER TABLE public.messages OWNER TO test; + +-- +-- Name: migrations; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.migrations ( + id text NOT NULL, + run_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE public.migrations OWNER TO test; + +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + +-- +-- Name: reviews; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.reviews ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + recommendation text, + is_decision boolean DEFAULT false, + user_id uuid, + manuscript_id uuid, + type text NOT NULL +); + + +ALTER TABLE public.reviews OWNER TO test; + +-- +-- Name: team_members; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.team_members ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + status character varying(255), + team_id uuid, + user_id uuid, + alias_id uuid +); + + +ALTER TABLE public.team_members OWNER TO test; + +-- +-- Name: teams; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.teams ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + name text, + role text NOT NULL, + members jsonb, + owners jsonb, + global boolean, + type text NOT NULL, + manuscript_id uuid +); + + +ALTER TABLE public.teams OWNER TO test; + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.users ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + admin boolean, + email text, + username text, + password_hash text, + teams jsonb, + password_reset_token text, + password_reset_timestamp timestamp with time zone, + type text NOT NULL, + profile_picture text, + online boolean +); + + +ALTER TABLE public.users OWNER TO test; + +-- +-- Data for Name: archive; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + + + +-- +-- Data for Name: job; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + + + +-- +-- Data for Name: version; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + +INSERT INTO pgboss.version (version) VALUES ('11'); + + +-- +-- Data for Name: aliases; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: channel_members; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: channels; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('afd95c06-011b-46e3-9985-964283d51c4a', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('75540565-6619-495f-a8c5-d6bf11ece72d', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Editorial discussion', 'editorial'); + + +-- +-- Data for Name: entities; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: files; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: identities; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('d341a633-cdce-4a7f-a9ad-5afc03cd0dd1', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.741+02', '2020-07-21 16:17:25.87+02', 'orcid', '0000-0002-0564-2016', 'Emily Clay', NULL, '{"accessToken": "079a1165-31e5-4b59-9a99-d80ff7a21ebf", "refreshToken": "ccadc737-defc-419e-823b-a9f3673848ba"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('bcda196e-765a-42c8-94da-ca2e43b80f96', '3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.721+02', '2020-07-21 16:33:26.742+02', 'orcid', '0000-0002-5641-5729', 'Sinead Sullivan', NULL, '{"accessToken": "ef1ed3ec-8371-41b2-a136-fd196ae52a72", "refreshToken": "6972dace-d9a6-4cd3-a2ad-ec7eb3e457c7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('4af83984-6359-47c5-a075-5ddfa9c555d9', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.127+02', '2020-07-21 16:35:07.104+02', 'orcid', '0000-0002-7645-9921', 'Sherry Crofoot', NULL, '{"accessToken": "2ad4e130-0775-4e13-87fb-8e8f5a0570ae", "refreshToken": "159933d9-2020-4c02-bdfb-163af41017dc"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('acfa1777-0aec-4fe1-bc16-92bb9d19e884', '85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.384+02', '2020-07-21 16:35:39.358+02', 'orcid', '0000-0002-9429-4446', 'Elaine Barnes', NULL, '{"accessToken": "dcf07bc7-e59c-41b3-9ce0-924ac20aeeea", "refreshToken": "ae49d6a1-8e62-419d-8767-4a3ec22c1950"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('88c85115-d83c-42d7-a1a1-0139827977da', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.975+02', '2020-07-21 16:36:26.059+02', 'orcid', '0000-0001-5956-7341', 'Gale Davis', NULL, '{"accessToken": "3e9f6f6c-7cc0-4afa-9fdf-6ed377c36aad", "refreshToken": "80b1e911-df97-43f1-9f11-17b61913f6d7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('049f91da-c84e-4b80-be2e-6e0cfca7a136', '231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.611+02', '2020-07-22 14:18:37.745+02', 'orcid', '0000-0003-2536-230X', 'Test Account', NULL, '{"accessToken": "eb551178-79e5-4189-8c5f-0a553092a9b5", "refreshToken": "4506fa5f-bd77-4867-afb4-0b07ea5302d6"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('2fb8359c-239c-43fa-91f5-1ff2058272a6', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.604+02', '2020-07-24 15:21:55.7+02', 'orcid', '0000-0003-1838-2441', 'Joanne Pilger', NULL, '{"accessToken": "842de329-ef16-4461-b83b-e8fe57238904", "refreshToken": "524fbdc5-9c67-4b4c-af17-2ce4cf294e88"}', true); + + +-- +-- Data for Name: manuscripts; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.9+02', '2020-08-13 15:12:29.223+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'accepted', 'accepted', NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "ethics": "This is my ethics statement", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keyword", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzky", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); + + +-- +-- Data for Name: messages; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('f73fdbd8-6fb6-4d7a-a74a-ab2c2c07b572', '2020-08-13 15:09:33.838+02', '2020-08-13 15:09:33.838+02', '5a06fcf3-d368-4f65-917c-1acdb73fcc71', NULL, '<p>Great paper, congratulations! Gale Davis</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('5c86da62-bc7f-4d23-8968-62bd5a56a52b', '2020-08-13 15:09:34.88+02', '2020-08-13 15:09:34.88+02', '5a06fcf3-d368-4f65-917c-1acdb73fcc71', NULL, '<p>This is a very important paper. Gale Davis</p>', 'confidential', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('ef96b249-dab6-4f7e-b24e-571b340b9b41', '2020-08-13 15:09:38.761+02', '2020-08-13 15:09:38.761+02', '7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', NULL, '<p>Great paper, congratulations! Sherry Crofoot</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('04a8a70e-7787-4fd6-bdca-bfac3aa86951', '2020-08-13 15:09:40.155+02', '2020-08-13 15:09:40.155+02', '7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', NULL, '<p>This is a very important paper. Sherry Crofoot</p>', 'confidential', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('7ccda096-07c2-4569-ad0f-5b3574db205e', '2020-08-13 15:09:44.046+02', '2020-08-13 15:09:44.046+02', '3a34e0ef-6695-4268-b901-60de20f9cf4e', NULL, '<p>Great paper, congratulations! Elaine Barnes</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('c8b7d1c9-aef2-47d0-a9ad-c9d46706e79e', '2020-08-13 15:09:45.548+02', '2020-08-13 15:09:45.548+02', '3a34e0ef-6695-4268-b901-60de20f9cf4e', NULL, '<p>This is a very important paper. Elaine Barnes</p>', 'confidential', 'ReviewComment'); + + +-- +-- Data for Name: reviews; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('5a06fcf3-d368-4f65-917c-1acdb73fcc71', '2020-08-13 15:09:32.358+02', '2020-08-13 15:09:34.925+02', 'accepted', false, '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', '2020-08-13 15:09:36.501+02', '2020-08-13 15:09:40.159+02', 'accepted', false, '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('3a34e0ef-6695-4268-b901-60de20f9cf4e', '2020-08-13 15:09:41.911+02', '2020-08-13 15:09:45.561+02', 'accepted', false, '85e1300e-003c-4e96-987b-23812f902477', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('7d962c82-322e-4b02-8981-5f26479433ab', '2020-08-13 15:12:28.737+02', '2020-08-13 15:12:28.737+02', 'accepted', true, '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); + + +-- +-- Data for Name: team_members; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('6505126d-2ecd-498b-a27d-18eafbdbc8a6', '2020-08-12 16:16:44.923+02', '2020-08-12 16:16:44.923+02', NULL, 'c31e3116-6176-45b5-b52c-6f7cbfc86007', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('031ae180-e94e-458d-86b7-f2dc1d456e2e', '2020-08-12 16:17:14.795+02', '2020-08-12 16:17:14.795+02', NULL, 'bf800912-56c4-44eb-b425-64e51a9824fe', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('c4ac4fc0-3fae-43b0-89ee-bf7f8fd9885f', '2020-08-12 16:17:43.262+02', '2020-08-13 15:09:41.898+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('69e896c6-0fdb-421d-a638-1ef7670c03c9', '2020-08-12 16:17:43.884+02', '2020-08-13 15:09:41.898+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('12c33ef5-4fc3-4d48-8309-a90c0461113c', '2020-08-12 16:17:44.547+02', '2020-08-13 15:09:45.782+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '85e1300e-003c-4e96-987b-23812f902477', NULL); + + +-- +-- Data for Name: teams; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('c31e3116-6176-45b5-b52c-6f7cbfc86007', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Author', 'author', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('bf800912-56c4-44eb-b425-64e51a9824fe', '2020-08-12 16:17:14.789+02', '2020-08-12 16:17:14.789+02', 'Senior Editor', 'seniorEditor', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('0719d132-bb6c-49d9-9122-7911a48cfd60', '2020-08-12 16:17:43.258+02', '2020-08-13 15:09:41.898+02', 'Reviewers', 'reviewer', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-08-12 16:17:13.598+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-08-12 16:17:14.868+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-08-13 15:09:35.913+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-08-13 15:09:41.198+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.381+02', '2020-08-13 15:09:46.741+02', NULL, NULL, '0000000294294446', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser1.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-08-13 15:12:29.67+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); + + +-- +-- Name: job job_pkey; Type: CONSTRAINT; Schema: pgboss; Owner: test +-- + +ALTER TABLE ONLY pgboss.job + ADD CONSTRAINT job_pkey PRIMARY KEY (id); + + +-- +-- Name: version version_pkey; Type: CONSTRAINT; Schema: pgboss; Owner: test +-- + +ALTER TABLE ONLY pgboss.version + ADD CONSTRAINT version_pkey PRIMARY KEY (version); + + +-- +-- Name: aliases aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.aliases + ADD CONSTRAINT aliases_pkey PRIMARY KEY (id); + + +-- +-- Name: channel_members channel_members_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_pkey PRIMARY KEY (id); + + +-- +-- Name: channels channels_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channels + ADD CONSTRAINT channels_pkey PRIMARY KEY (id); + + +-- +-- Name: entities entities_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_pkey PRIMARY KEY (id); + + +-- +-- Name: files files_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_pkey PRIMARY KEY (id); + + +-- +-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.identities + ADD CONSTRAINT identities_pkey PRIMARY KEY (id); + + +-- +-- Name: manuscripts manuscripts_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.manuscripts + ADD CONSTRAINT manuscripts_pkey PRIMARY KEY (id); + + +-- +-- Name: messages messages_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_pkey PRIMARY KEY (id); + + +-- +-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.migrations + ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); + + +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_pkey PRIMARY KEY (id); + + +-- +-- Name: team_members team_members_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_pkey PRIMARY KEY (id); + + +-- +-- Name: teams teams_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_email_key; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_username_key; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: archive_archivedon_idx; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX archive_archivedon_idx ON pgboss.archive USING btree (archivedon); + + +-- +-- Name: archive_id_idx; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX archive_id_idx ON pgboss.archive USING btree (id); + + +-- +-- Name: job_name; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX job_name ON pgboss.job USING btree (name text_pattern_ops); + + +-- +-- Name: job_singletonkey; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonkey ON pgboss.job USING btree (name, singletonkey) WHERE ((state < 'completed'::pgboss.job_state) AND (singletonon IS NULL)); + + +-- +-- Name: job_singletonkeyon; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonkeyon ON pgboss.job USING btree (name, singletonon, singletonkey) WHERE (state < 'expired'::pgboss.job_state); + + +-- +-- Name: job_singletonon; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonon ON pgboss.job USING btree (name, singletonon) WHERE ((state < 'expired'::pgboss.job_state) AND (singletonkey IS NULL)); + + +-- +-- Name: channel_members_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX channel_members_idx ON public.channel_members USING btree (user_id, channel_id); + + +-- +-- Name: is_default_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, user_id) WHERE (is_default IS TRUE); + + +-- +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); + + +-- +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); + + +-- +-- Name: channel_members channel_members_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id); + + +-- +-- Name: channel_members channel_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: channels channels_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channels + ADD CONSTRAINT channels_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; + + +-- +-- Name: manuscripts manuscripts_submitter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.manuscripts + ADD CONSTRAINT manuscripts_submitter_id_fkey FOREIGN KEY (submitter_id) REFERENCES public.users(id); + + +-- +-- Name: messages messages_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id) ON DELETE CASCADE; + + +-- +-- Name: messages messages_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.identities + ADD CONSTRAINT sidentities_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + + +-- +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/cypress/dumps/initialState.sql b/cypress/dumps/initialState.sql index 943209725dc5fb3990a02ead7bcb4c509fa0b446..0efe5f96fd618984916c97112e7c973c47411111 100644 --- a/cypress/dumps/initialState.sql +++ b/cypress/dumps/initialState.sql @@ -25,28 +25,28 @@ CREATE SCHEMA pgboss; ALTER SCHEMA pgboss OWNER TO test; -- --- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -- CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; -- --- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -- COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; -- --- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: +-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: -- CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public; -- --- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: +-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: -- COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; @@ -145,9 +145,9 @@ CREATE TABLE public.aliases ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, - name character varying(255), - email character varying(255), - aff character varying(255) + name text, + email text, + aff text ); @@ -175,7 +175,6 @@ ALTER TABLE public.channel_members OWNER TO test; CREATE TABLE public.channels ( id uuid NOT NULL, manuscript_id uuid, - team_id uuid, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, topic text, @@ -205,15 +204,16 @@ CREATE TABLE public.files ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, - object text, - object_id uuid, label text, file_type text, filename text, url text, mime_type text, size integer, - type text NOT NULL + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) ); @@ -289,6 +289,24 @@ CREATE TABLE public.migrations ( ALTER TABLE public.migrations OWNER TO test; +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + -- -- Name: reviews; Type: TABLE; Schema: public; Owner: test -- @@ -299,7 +317,6 @@ CREATE TABLE public.reviews ( updated timestamp with time zone, recommendation text, is_decision boolean DEFAULT false, - comments jsonb, user_id uuid, manuscript_id uuid, type text NOT NULL @@ -335,11 +352,11 @@ CREATE TABLE public.teams ( updated timestamp with time zone, name text, role text NOT NULL, + members jsonb, owners jsonb, global boolean, type text NOT NULL, - object_id uuid, - object_type character varying(255) + manuscript_id uuid ); @@ -421,13 +438,6 @@ INSERT INTO pgboss.version (version) VALUES ('11'); -- Data for Name: identities; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('d341a633-cdce-4a7f-a9ad-5afc03cd0dd1', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.741+02', '2020-07-21 16:17:25.87+02', 'orcid', '0000-0002-0564-2016', 'Emily Clay', NULL, '{"accessToken": "079a1165-31e5-4b59-9a99-d80ff7a21ebf", "refreshToken": "ccadc737-defc-419e-823b-a9f3673848ba"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('bcda196e-765a-42c8-94da-ca2e43b80f96', '3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.721+02', '2020-07-21 16:33:26.742+02', 'orcid', '0000-0002-5641-5729', 'Sinead Sullivan', NULL, '{"accessToken": "ef1ed3ec-8371-41b2-a136-fd196ae52a72", "refreshToken": "6972dace-d9a6-4cd3-a2ad-ec7eb3e457c7"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('4af83984-6359-47c5-a075-5ddfa9c555d9', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.127+02', '2020-07-21 16:35:07.104+02', 'orcid', '0000-0002-7645-9921', 'Sherry Crofoot', NULL, '{"accessToken": "2ad4e130-0775-4e13-87fb-8e8f5a0570ae", "refreshToken": "159933d9-2020-4c02-bdfb-163af41017dc"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('acfa1777-0aec-4fe1-bc16-92bb9d19e884', '85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.384+02', '2020-07-21 16:35:39.358+02', 'orcid', '0000-0002-9429-4446', 'Elaine Barnes', NULL, '{"accessToken": "dcf07bc7-e59c-41b3-9ce0-924ac20aeeea", "refreshToken": "ae49d6a1-8e62-419d-8767-4a3ec22c1950"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('88c85115-d83c-42d7-a1a1-0139827977da', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.975+02', '2020-07-21 16:36:26.059+02', 'orcid', '0000-0001-5956-7341', 'Gale Davis', NULL, '{"accessToken": "3e9f6f6c-7cc0-4afa-9fdf-6ed377c36aad", "refreshToken": "80b1e911-df97-43f1-9f11-17b61913f6d7"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('049f91da-c84e-4b80-be2e-6e0cfca7a136', '231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.611+02', '2020-07-22 14:18:37.745+02', 'orcid', '0000-0003-2536-230X', 'Test Account', NULL, '{"accessToken": "eb551178-79e5-4189-8c5f-0a553092a9b5", "refreshToken": "4506fa5f-bd77-4867-afb4-0b07ea5302d6"}', true); -INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('2fb8359c-239c-43fa-91f5-1ff2058272a6', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.604+02', '2020-07-24 15:21:55.7+02', 'orcid', '0000-0003-1838-2441', 'Joanne Pilger', NULL, '{"accessToken": "842de329-ef16-4461-b83b-e8fe57238904", "refreshToken": "524fbdc5-9c67-4b4c-af17-2ce4cf294e88"}', true); -- @@ -446,24 +456,27 @@ INSERT INTO public.identities (id, user_id, created, updated, type, identifier, -- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-07-21 16:01:00.856209+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-files.sql', '2020-07-21 16:01:00.866487+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-review.sql', '2020-07-21 16:01:00.876573+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-07-21 16:01:00.887088+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542801241-initial-team-migration.sql', '2020-07-21 16:01:00.898301+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1547596236-initial-team-member-migration.js', '2020-07-21 16:01:00.954317+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205275-move-members.js', '2020-07-21 16:01:01.009825+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205276-simplify-object.js', '2020-07-21 16:01:01.025532+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548328420-add-alias-migration.js', '2020-07-21 16:01:01.068783+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-07-21 16:01:01.078878+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-07-21 16:01:01.092107+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-07-21 16:01:01.107057+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-07-21 16:01:01.118725+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-07-21 16:01:01.12668+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-07-21 16:01:01.14497+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-07-21 16:01:01.15657+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-07-21 16:01:01.162443+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-07-21 16:01:01.17359+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + -- @@ -488,13 +501,6 @@ INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities -- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.381+02', '2020-07-24 16:43:03.114+02', NULL, NULL, '0000000294294446', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser1.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-07-24 16:43:15.46+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-07-24 16:43:26.378+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-07-24 16:43:43.943+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', true); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-07-24 16:49:06.488+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', true); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-07-24 16:44:59.306+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', true); -- @@ -585,6 +591,14 @@ ALTER TABLE ONLY public.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + -- -- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test -- @@ -690,17 +704,17 @@ CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, -- --- Name: team_members_team_id_user_id_index; Type: INDEX; Schema: public; Owner: test +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX team_members_team_id_user_id_index ON public.team_members USING btree (team_id, user_id); +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); -- --- Name: teams_object_id_object_type_index; Type: INDEX; Schema: public; Owner: test +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX teams_object_id_object_type_index ON public.teams USING btree (object_id, object_type); +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); -- @@ -728,11 +742,19 @@ ALTER TABLE ONLY public.channels -- --- Name: channels channels_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- -ALTER TABLE ONLY public.channels - ADD CONSTRAINT channels_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id); +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; -- @@ -759,6 +781,30 @@ ALTER TABLE ONLY public.messages ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + -- -- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- @@ -768,30 +814,55 @@ ALTER TABLE ONLY public.identities -- --- Name: team_members team_members_alias_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_alias_id_foreign FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); -- --- Name: team_members team_members_team_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_team_id_foreign FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; -- --- Name: team_members team_members_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_user_id_foreign FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; -- -- PostgreSQL database dump complete -- +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.381+02', '2020-07-24 16:43:03.114+02', NULL, NULL, '0000000294294446', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser1.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-07-24 16:43:15.46+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-07-24 16:43:26.378+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-07-24 16:43:43.943+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-07-24 16:49:06.488+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-07-24 16:44:59.306+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', true); + + +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('d341a633-cdce-4a7f-a9ad-5afc03cd0dd1', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.741+02', '2020-07-21 16:17:25.87+02', 'orcid', '0000-0002-0564-2016', 'Emily Clay', NULL, '{"accessToken": "079a1165-31e5-4b59-9a99-d80ff7a21ebf", "refreshToken": "ccadc737-defc-419e-823b-a9f3673848ba"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('bcda196e-765a-42c8-94da-ca2e43b80f96', '3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.721+02', '2020-07-21 16:33:26.742+02', 'orcid', '0000-0002-5641-5729', 'Sinead Sullivan', NULL, '{"accessToken": "ef1ed3ec-8371-41b2-a136-fd196ae52a72", "refreshToken": "6972dace-d9a6-4cd3-a2ad-ec7eb3e457c7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('4af83984-6359-47c5-a075-5ddfa9c555d9', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.127+02', '2020-07-21 16:35:07.104+02', 'orcid', '0000-0002-7645-9921', 'Sherry Crofoot', NULL, '{"accessToken": "2ad4e130-0775-4e13-87fb-8e8f5a0570ae", "refreshToken": "159933d9-2020-4c02-bdfb-163af41017dc"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('acfa1777-0aec-4fe1-bc16-92bb9d19e884', '85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.384+02', '2020-07-21 16:35:39.358+02', 'orcid', '0000-0002-9429-4446', 'Elaine Barnes', NULL, '{"accessToken": "dcf07bc7-e59c-41b3-9ce0-924ac20aeeea", "refreshToken": "ae49d6a1-8e62-419d-8767-4a3ec22c1950"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('88c85115-d83c-42d7-a1a1-0139827977da', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.975+02', '2020-07-21 16:36:26.059+02', 'orcid', '0000-0001-5956-7341', 'Gale Davis', NULL, '{"accessToken": "3e9f6f6c-7cc0-4afa-9fdf-6ed377c36aad", "refreshToken": "80b1e911-df97-43f1-9f11-17b61913f6d7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('049f91da-c84e-4b80-be2e-6e0cfca7a136', '231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.611+02', '2020-07-22 14:18:37.745+02', 'orcid', '0000-0003-2536-230X', 'Test Account', NULL, '{"accessToken": "eb551178-79e5-4189-8c5f-0a553092a9b5", "refreshToken": "4506fa5f-bd77-4867-afb4-0b07ea5302d6"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('2fb8359c-239c-43fa-91f5-1ff2058272a6', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.604+02', '2020-07-24 15:21:55.7+02', 'orcid', '0000-0003-1838-2441', 'Joanne Pilger', NULL, '{"accessToken": "842de329-ef16-4461-b83b-e8fe57238904", "refreshToken": "524fbdc5-9c67-4b4c-af17-2ce4cf294e88"}', true); + diff --git a/cypress/dumps/reviewers_invited.sql b/cypress/dumps/reviewers_invited.sql index 0af47e77a00e7b820c4706585abb16bfeffe0d1f..3733f35db91d178c49e70b354276c2dedc16d5b7 100644 --- a/cypress/dumps/reviewers_invited.sql +++ b/cypress/dumps/reviewers_invited.sql @@ -145,9 +145,9 @@ CREATE TABLE public.aliases ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, - name character varying(255), - email character varying(255), - aff character varying(255) + name text, + email text, + aff text ); @@ -175,7 +175,6 @@ ALTER TABLE public.channel_members OWNER TO test; CREATE TABLE public.channels ( id uuid NOT NULL, manuscript_id uuid, - team_id uuid, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, topic text, @@ -205,15 +204,16 @@ CREATE TABLE public.files ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, - object text, - object_id uuid, label text, file_type text, filename text, url text, mime_type text, size integer, - type text NOT NULL + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) ); @@ -289,6 +289,24 @@ CREATE TABLE public.migrations ( ALTER TABLE public.migrations OWNER TO test; +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + -- -- Name: reviews; Type: TABLE; Schema: public; Owner: test -- @@ -299,7 +317,6 @@ CREATE TABLE public.reviews ( updated timestamp with time zone, recommendation text, is_decision boolean DEFAULT false, - comments jsonb, user_id uuid, manuscript_id uuid, type text NOT NULL @@ -335,11 +352,11 @@ CREATE TABLE public.teams ( updated timestamp with time zone, name text, role text NOT NULL, + members jsonb, owners jsonb, global boolean, type text NOT NULL, - object_id uuid, - object_type character varying(255) + manuscript_id uuid ); @@ -403,8 +420,8 @@ INSERT INTO pgboss.version (version) VALUES ('11'); -- Data for Name: channels; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('466f49f5-f4ca-46ca-82ca-693212ca9ba2', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Editorial discussion', 'editorial'); -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('d24525e7-f36e-4f5e-b0cb-e05ef0ea9062', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.011+02', '2020-07-28 00:41:34.011+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('afd95c06-011b-46e3-9985-964283d51c4a', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('75540565-6619-495f-a8c5-d6bf11ece72d', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Editorial discussion', 'editorial'); -- @@ -436,7 +453,7 @@ INSERT INTO public.identities (id, user_id, created, updated, type, identifier, -- Data for Name: manuscripts; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('fb2534c6-ecbb-4846-a61d-609dc119e9b0', '2020-07-28 00:41:33.983+02', '2020-07-28 00:42:03.231+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keywords", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzk", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); +INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.9+02', '2020-08-12 16:17:12.499+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "ethics": "This is my ethics statement", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keyword", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzky", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); -- @@ -449,24 +466,27 @@ INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, s -- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-07-21 16:01:00.856209+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-files.sql', '2020-07-21 16:01:00.866487+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-review.sql', '2020-07-21 16:01:00.876573+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-07-21 16:01:00.887088+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542801241-initial-team-migration.sql', '2020-07-21 16:01:00.898301+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1547596236-initial-team-member-migration.js', '2020-07-21 16:01:00.954317+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205275-move-members.js', '2020-07-21 16:01:01.009825+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205276-simplify-object.js', '2020-07-21 16:01:01.025532+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548328420-add-alias-migration.js', '2020-07-21 16:01:01.068783+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-07-21 16:01:01.078878+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-07-21 16:01:01.092107+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-07-21 16:01:01.107057+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-07-21 16:01:01.118725+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-07-21 16:01:01.12668+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-07-21 16:01:01.14497+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-07-21 16:01:01.15657+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-07-21 16:01:01.162443+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-07-21 16:01:01.17359+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + -- @@ -479,20 +499,20 @@ INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities -- Data for Name: team_members; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('af28eb3b-495e-485d-879d-4d609e146dc6', '2020-07-28 00:41:34.024+02', '2020-07-28 00:41:34.024+02', NULL, '0ecdfc46-2400-4818-8623-ee29ad2102cf', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('39066380-96b2-408e-8329-4ff3833f06be', '2020-07-28 00:42:07.541+02', '2020-07-28 00:42:07.541+02', NULL, '6eb1044b-1d8a-4d07-a84d-a167f152a5bf', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('9927026f-4ffa-4805-bc00-cb9b097b7df4', '2020-07-28 00:45:13.354+02', '2020-07-28 00:45:13.354+02', 'invited', 'b107739f-9c14-4f89-9303-229dbfbd2140', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', NULL); -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('e69ca277-c295-44aa-a657-af0c7437840e', '2020-07-28 00:45:14.037+02', '2020-07-28 00:45:14.037+02', 'invited', 'b107739f-9c14-4f89-9303-229dbfbd2140', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', NULL); -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('2e64054b-6a0a-4768-9b37-8638b618141e', '2020-07-28 00:45:14.852+02', '2020-07-28 00:45:14.852+02', 'invited', 'b107739f-9c14-4f89-9303-229dbfbd2140', '85e1300e-003c-4e96-987b-23812f902477', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('6505126d-2ecd-498b-a27d-18eafbdbc8a6', '2020-08-12 16:16:44.923+02', '2020-08-12 16:16:44.923+02', NULL, 'c31e3116-6176-45b5-b52c-6f7cbfc86007', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('031ae180-e94e-458d-86b7-f2dc1d456e2e', '2020-08-12 16:17:14.795+02', '2020-08-12 16:17:14.795+02', NULL, 'bf800912-56c4-44eb-b425-64e51a9824fe', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('c4ac4fc0-3fae-43b0-89ee-bf7f8fd9885f', '2020-08-12 16:17:43.262+02', '2020-08-12 16:17:43.262+02', 'invited', '0719d132-bb6c-49d9-9122-7911a48cfd60', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('69e896c6-0fdb-421d-a638-1ef7670c03c9', '2020-08-12 16:17:43.884+02', '2020-08-12 16:17:43.884+02', 'invited', '0719d132-bb6c-49d9-9122-7911a48cfd60', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('12c33ef5-4fc3-4d48-8309-a90c0461113c', '2020-08-12 16:17:44.547+02', '2020-08-12 16:17:44.547+02', 'invited', '0719d132-bb6c-49d9-9122-7911a48cfd60', '85e1300e-003c-4e96-987b-23812f902477', NULL); -- -- Data for Name: teams; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('0ecdfc46-2400-4818-8623-ee29ad2102cf', '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Author', 'author', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('6eb1044b-1d8a-4d07-a84d-a167f152a5bf', '2020-07-28 00:42:07.533+02', '2020-07-28 00:42:07.533+02', 'Senior Editor', 'seniorEditor', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('b107739f-9c14-4f89-9303-229dbfbd2140', '2020-07-28 00:45:13.348+02', '2020-07-28 00:45:13.348+02', 'Reviewers', 'reviewer', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('c31e3116-6176-45b5-b52c-6f7cbfc86007', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Author', 'author', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('bf800912-56c4-44eb-b425-64e51a9824fe', '2020-08-12 16:17:14.789+02', '2020-08-12 16:17:14.789+02', 'Senior Editor', 'seniorEditor', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('0719d132-bb6c-49d9-9122-7911a48cfd60', '2020-08-12 16:17:43.258+02', '2020-08-12 16:17:43.258+02', 'Reviewers', 'reviewer', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); -- @@ -503,9 +523,9 @@ INSERT INTO public.users (id, created, updated, admin, email, username, password INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-07-24 16:43:43.943+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', true); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-07-24 16:44:59.306+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', true); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-07-28 00:42:05.08+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-07-28 00:42:07.665+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-07-28 00:45:11.921+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-08-12 16:17:13.598+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-08-12 16:17:14.868+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-08-12 16:17:41.916+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); -- @@ -596,6 +616,14 @@ ALTER TABLE ONLY public.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + -- -- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test -- @@ -701,17 +729,17 @@ CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, -- --- Name: team_members_team_id_user_id_index; Type: INDEX; Schema: public; Owner: test +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX team_members_team_id_user_id_index ON public.team_members USING btree (team_id, user_id); +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); -- --- Name: teams_object_id_object_type_index; Type: INDEX; Schema: public; Owner: test +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX teams_object_id_object_type_index ON public.teams USING btree (object_id, object_type); +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); -- @@ -739,11 +767,19 @@ ALTER TABLE ONLY public.channels -- --- Name: channels channels_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- -ALTER TABLE ONLY public.channels - ADD CONSTRAINT channels_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id); +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; -- @@ -770,6 +806,30 @@ ALTER TABLE ONLY public.messages ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + -- -- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- @@ -779,27 +839,35 @@ ALTER TABLE ONLY public.identities -- --- Name: team_members team_members_alias_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_alias_id_foreign FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); -- --- Name: team_members team_members_team_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_team_id_foreign FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; -- --- Name: team_members team_members_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_user_id_foreign FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; -- diff --git a/cypress/dumps/senior_editor_assigned.sql b/cypress/dumps/senior_editor_assigned.sql index 1d2b7ce072f2500e08b12e58db79182c09bfbebf..31e0f3e7492017a2e62177a8d3ce55f58638e59f 100644 --- a/cypress/dumps/senior_editor_assigned.sql +++ b/cypress/dumps/senior_editor_assigned.sql @@ -145,9 +145,9 @@ CREATE TABLE public.aliases ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, - name character varying(255), - email character varying(255), - aff character varying(255) + name text, + email text, + aff text ); @@ -175,7 +175,6 @@ ALTER TABLE public.channel_members OWNER TO test; CREATE TABLE public.channels ( id uuid NOT NULL, manuscript_id uuid, - team_id uuid, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, topic text, @@ -205,15 +204,16 @@ CREATE TABLE public.files ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, - object text, - object_id uuid, label text, file_type text, filename text, url text, mime_type text, size integer, - type text NOT NULL + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) ); @@ -289,6 +289,24 @@ CREATE TABLE public.migrations ( ALTER TABLE public.migrations OWNER TO test; +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + -- -- Name: reviews; Type: TABLE; Schema: public; Owner: test -- @@ -299,7 +317,6 @@ CREATE TABLE public.reviews ( updated timestamp with time zone, recommendation text, is_decision boolean DEFAULT false, - comments jsonb, user_id uuid, manuscript_id uuid, type text NOT NULL @@ -335,11 +352,11 @@ CREATE TABLE public.teams ( updated timestamp with time zone, name text, role text NOT NULL, + members jsonb, owners jsonb, global boolean, type text NOT NULL, - object_id uuid, - object_type character varying(255) + manuscript_id uuid ); @@ -403,8 +420,8 @@ INSERT INTO pgboss.version (version) VALUES ('11'); -- Data for Name: channels; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('466f49f5-f4ca-46ca-82ca-693212ca9ba2', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Editorial discussion', 'editorial'); -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('d24525e7-f36e-4f5e-b0cb-e05ef0ea9062', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.011+02', '2020-07-28 00:41:34.011+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('8be9c91e-10f8-42c1-9d98-429ffb7164a0', 'a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('89848abe-a992-45e4-ace7-36e9c64c4162', 'a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Editorial discussion', 'editorial'); -- @@ -417,6 +434,7 @@ INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic -- Data for Name: files; Type: TABLE DATA; Schema: public; Owner: test -- +INSERT INTO public.files (id, created, updated, label, file_type, filename, url, mime_type, size, type, manuscript_id, review_comment_id) VALUES ('66070eaf-6ee1-475f-98ba-774843f1238e', '2020-08-12 16:35:19.664+02', '2020-08-12 16:35:19.664+02', NULL, 'supplementary', 'test-pdf.pdf', '/static/uploads/bfc74d5e3c0b8bf97cd5a522bfdb3c87.pdf', 'application/pdf', 142400, 'file', 'a696348d-b226-4703-aad1-ff64ddf30d17', NULL); -- @@ -436,7 +454,7 @@ INSERT INTO public.identities (id, user_id, created, updated, type, identifier, -- Data for Name: manuscripts; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('fb2534c6-ecbb-4846-a61d-609dc119e9b0', '2020-07-28 00:41:33.983+02', '2020-07-28 00:42:03.231+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keywords", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzk", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); +INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.371+02', '2020-08-12 16:35:28.918+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "ethics": "This is my ethics statement", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keywords", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzky", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); -- @@ -449,24 +467,27 @@ INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, s -- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-07-21 16:01:00.856209+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-files.sql', '2020-07-21 16:01:00.866487+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-review.sql', '2020-07-21 16:01:00.876573+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-07-21 16:01:00.887088+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542801241-initial-team-migration.sql', '2020-07-21 16:01:00.898301+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1547596236-initial-team-member-migration.js', '2020-07-21 16:01:00.954317+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205275-move-members.js', '2020-07-21 16:01:01.009825+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205276-simplify-object.js', '2020-07-21 16:01:01.025532+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548328420-add-alias-migration.js', '2020-07-21 16:01:01.068783+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-07-21 16:01:01.078878+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-07-21 16:01:01.092107+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-07-21 16:01:01.107057+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-07-21 16:01:01.118725+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-07-21 16:01:01.12668+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-07-21 16:01:01.14497+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-07-21 16:01:01.15657+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-07-21 16:01:01.162443+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-07-21 16:01:01.17359+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + -- @@ -479,16 +500,16 @@ INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities -- Data for Name: team_members; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('af28eb3b-495e-485d-879d-4d609e146dc6', '2020-07-28 00:41:34.024+02', '2020-07-28 00:41:34.024+02', NULL, '0ecdfc46-2400-4818-8623-ee29ad2102cf', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('39066380-96b2-408e-8329-4ff3833f06be', '2020-07-28 00:42:07.541+02', '2020-07-28 00:42:07.541+02', NULL, '6eb1044b-1d8a-4d07-a84d-a167f152a5bf', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('d80380a6-c741-4e3c-9933-126cf368c43b', '2020-08-12 16:35:01.381+02', '2020-08-12 16:35:01.381+02', NULL, 'd5dc5913-db33-4576-a129-3c90321464f6', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('a58d3e82-54b7-4946-8ff8-116d84cbc065', '2020-08-12 16:36:01.535+02', '2020-08-12 16:36:01.535+02', NULL, 'd7cd46ee-8d79-47c1-9c06-da5dfd464075', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); -- -- Data for Name: teams; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('0ecdfc46-2400-4818-8623-ee29ad2102cf', '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Author', 'author', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('6eb1044b-1d8a-4d07-a84d-a167f152a5bf', '2020-07-28 00:42:07.533+02', '2020-07-28 00:42:07.533+02', 'Senior Editor', 'seniorEditor', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('d5dc5913-db33-4576-a129-3c90321464f6', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Author', 'author', NULL, NULL, NULL, 'team', 'a696348d-b226-4703-aad1-ff64ddf30d17'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('d7cd46ee-8d79-47c1-9c06-da5dfd464075', '2020-08-12 16:36:01.513+02', '2020-08-12 16:36:01.513+02', 'Senior Editor', 'seniorEditor', NULL, NULL, NULL, 'team', 'a696348d-b226-4703-aad1-ff64ddf30d17'); -- @@ -499,9 +520,9 @@ INSERT INTO public.users (id, created, updated, admin, email, username, password INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-07-24 16:43:43.943+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', true); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-07-24 16:44:59.306+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', true); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-07-28 00:42:05.08+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-07-28 00:42:07.665+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-07-28 00:42:08.153+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-08-12 16:35:01.383+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-08-12 16:36:01.679+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-08-12 16:36:02.11+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); -- @@ -592,6 +613,14 @@ ALTER TABLE ONLY public.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + -- -- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test -- @@ -697,17 +726,17 @@ CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, -- --- Name: team_members_team_id_user_id_index; Type: INDEX; Schema: public; Owner: test +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX team_members_team_id_user_id_index ON public.team_members USING btree (team_id, user_id); +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); -- --- Name: teams_object_id_object_type_index; Type: INDEX; Schema: public; Owner: test +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX teams_object_id_object_type_index ON public.teams USING btree (object_id, object_type); +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); -- @@ -735,11 +764,19 @@ ALTER TABLE ONLY public.channels -- --- Name: channels channels_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- -ALTER TABLE ONLY public.channels - ADD CONSTRAINT channels_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id); +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; -- @@ -766,6 +803,30 @@ ALTER TABLE ONLY public.messages ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + -- -- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- @@ -775,27 +836,35 @@ ALTER TABLE ONLY public.identities -- --- Name: team_members team_members_alias_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_alias_id_foreign FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); -- --- Name: team_members team_members_team_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_team_id_foreign FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; -- --- Name: team_members team_members_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_user_id_foreign FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; -- diff --git a/cypress/dumps/submission_complete.sql b/cypress/dumps/submission_complete.sql index b318c1f25ef542335d277f2932a1c39028e6d940..f9966719d506445849d95faa2ceef2eec6ce1069 100644 --- a/cypress/dumps/submission_complete.sql +++ b/cypress/dumps/submission_complete.sql @@ -145,9 +145,9 @@ CREATE TABLE public.aliases ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, - name character varying(255), - email character varying(255), - aff character varying(255) + name text, + email text, + aff text ); @@ -175,7 +175,6 @@ ALTER TABLE public.channel_members OWNER TO test; CREATE TABLE public.channels ( id uuid NOT NULL, manuscript_id uuid, - team_id uuid, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, topic text, @@ -205,15 +204,16 @@ CREATE TABLE public.files ( id uuid NOT NULL, created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, updated timestamp with time zone, - object text, - object_id uuid, label text, file_type text, filename text, url text, mime_type text, size integer, - type text NOT NULL + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) ); @@ -289,6 +289,24 @@ CREATE TABLE public.migrations ( ALTER TABLE public.migrations OWNER TO test; +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + -- -- Name: reviews; Type: TABLE; Schema: public; Owner: test -- @@ -299,7 +317,6 @@ CREATE TABLE public.reviews ( updated timestamp with time zone, recommendation text, is_decision boolean DEFAULT false, - comments jsonb, user_id uuid, manuscript_id uuid, type text NOT NULL @@ -335,11 +352,11 @@ CREATE TABLE public.teams ( updated timestamp with time zone, name text, role text NOT NULL, + members jsonb, owners jsonb, global boolean, type text NOT NULL, - object_id uuid, - object_type character varying(255) + manuscript_id uuid ); @@ -403,8 +420,8 @@ INSERT INTO pgboss.version (version) VALUES ('11'); -- Data for Name: channels; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('466f49f5-f4ca-46ca-82ca-693212ca9ba2', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Editorial discussion', 'editorial'); -INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic, type) VALUES ('d24525e7-f36e-4f5e-b0cb-e05ef0ea9062', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', NULL, '2020-07-28 00:41:34.011+02', '2020-07-28 00:41:34.011+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('8be9c91e-10f8-42c1-9d98-429ffb7164a0', 'a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('89848abe-a992-45e4-ace7-36e9c64c4162', 'a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Editorial discussion', 'editorial'); -- @@ -417,6 +434,7 @@ INSERT INTO public.channels (id, manuscript_id, team_id, created, updated, topic -- Data for Name: files; Type: TABLE DATA; Schema: public; Owner: test -- +INSERT INTO public.files (id, created, updated, label, file_type, filename, url, mime_type, size, type, manuscript_id, review_comment_id) VALUES ('66070eaf-6ee1-475f-98ba-774843f1238e', '2020-08-12 16:35:19.664+02', '2020-08-12 16:35:19.664+02', NULL, 'supplementary', 'test-pdf.pdf', '/static/uploads/bfc74d5e3c0b8bf97cd5a522bfdb3c87.pdf', 'application/pdf', 142400, 'file', 'a696348d-b226-4703-aad1-ff64ddf30d17', NULL); -- @@ -436,7 +454,7 @@ INSERT INTO public.identities (id, user_id, created, updated, type, identifier, -- Data for Name: manuscripts; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('fb2534c6-ecbb-4846-a61d-609dc119e9b0', '2020-07-28 00:41:33.983+02', '2020-07-28 00:42:03.231+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keywords", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzk", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); +INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('a696348d-b226-4703-aad1-ff64ddf30d17', '2020-08-12 16:35:01.371+02', '2020-08-12 16:35:28.918+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "ethics": "This is my ethics statement", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keywords", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzky", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); -- @@ -449,24 +467,27 @@ INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, s -- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-07-21 16:01:00.856209+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-files.sql', '2020-07-21 16:01:00.866487+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1537450834-review.sql', '2020-07-21 16:01:00.876573+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-07-21 16:01:00.887088+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1542801241-initial-team-migration.sql', '2020-07-21 16:01:00.898301+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1547596236-initial-team-member-migration.js', '2020-07-21 16:01:00.954317+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205275-move-members.js', '2020-07-21 16:01:01.009825+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548205276-simplify-object.js', '2020-07-21 16:01:01.025532+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1548328420-add-alias-migration.js', '2020-07-21 16:01:01.068783+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-07-21 16:01:01.078878+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-07-21 16:01:01.092107+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-07-21 16:01:01.107057+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-07-21 16:01:01.118725+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-07-21 16:01:01.12668+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-07-21 16:01:01.14497+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-07-21 16:01:01.15657+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-07-21 16:01:01.162443+02'); -INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-07-21 16:01:01.17359+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + -- @@ -479,14 +500,14 @@ INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities -- Data for Name: team_members; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('af28eb3b-495e-485d-879d-4d609e146dc6', '2020-07-28 00:41:34.024+02', '2020-07-28 00:41:34.024+02', NULL, '0ecdfc46-2400-4818-8623-ee29ad2102cf', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('d80380a6-c741-4e3c-9933-126cf368c43b', '2020-08-12 16:35:01.381+02', '2020-08-12 16:35:01.381+02', NULL, 'd5dc5913-db33-4576-a129-3c90321464f6', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); -- -- Data for Name: teams; Type: TABLE DATA; Schema: public; Owner: test -- -INSERT INTO public.teams (id, created, updated, name, role, owners, global, type, object_id, object_type) VALUES ('0ecdfc46-2400-4818-8623-ee29ad2102cf', '2020-07-28 00:41:34.01+02', '2020-07-28 00:41:34.01+02', 'Author', 'author', NULL, NULL, 'team', 'fb2534c6-ecbb-4846-a61d-609dc119e9b0', 'Manuscript'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('d5dc5913-db33-4576-a129-3c90321464f6', '2020-08-12 16:35:01.376+02', '2020-08-12 16:35:01.376+02', 'Author', 'author', NULL, NULL, NULL, 'team', 'a696348d-b226-4703-aad1-ff64ddf30d17'); -- @@ -499,7 +520,7 @@ INSERT INTO public.users (id, created, updated, admin, email, username, password INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-07-24 16:49:06.488+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', true); INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-07-24 16:44:59.306+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', true); -INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-07-28 00:41:34.032+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', true); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-08-12 16:35:01.383+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', true); -- @@ -590,6 +611,14 @@ ALTER TABLE ONLY public.migrations ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + -- -- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test -- @@ -695,17 +724,17 @@ CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, -- --- Name: team_members_team_id_user_id_index; Type: INDEX; Schema: public; Owner: test +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX team_members_team_id_user_id_index ON public.team_members USING btree (team_id, user_id); +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); -- --- Name: teams_object_id_object_type_index; Type: INDEX; Schema: public; Owner: test +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test -- -CREATE INDEX teams_object_id_object_type_index ON public.teams USING btree (object_id, object_type); +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); -- @@ -733,11 +762,19 @@ ALTER TABLE ONLY public.channels -- --- Name: channels channels_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- -ALTER TABLE ONLY public.channels - ADD CONSTRAINT channels_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id); +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; -- @@ -764,6 +801,30 @@ ALTER TABLE ONLY public.messages ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + -- -- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- @@ -773,27 +834,35 @@ ALTER TABLE ONLY public.identities -- --- Name: team_members team_members_alias_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_alias_id_foreign FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); -- --- Name: team_members team_members_team_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_team_id_foreign FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; -- --- Name: team_members team_members_user_id_foreign; Type: FK CONSTRAINT; Schema: public; Owner: test +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test -- ALTER TABLE ONLY public.team_members - ADD CONSTRAINT team_members_user_id_foreign FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE CASCADE ON DELETE CASCADE; + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; -- diff --git a/cypress/dumps/three_reviews_completed.sql b/cypress/dumps/three_reviews_completed.sql new file mode 100644 index 0000000000000000000000000000000000000000..8e7c8bba5d5ed812fb202665671a3580c2784c6c --- /dev/null +++ b/cypress/dumps/three_reviews_completed.sql @@ -0,0 +1,885 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 10.5 +-- Dumped by pg_dump version 10.5 + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: pgboss; Type: SCHEMA; Schema: -; Owner: test +-- + +CREATE SCHEMA pgboss; + + +ALTER SCHEMA pgboss OWNER TO test; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +-- +-- Name: pgcrypto; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public; + + +-- +-- Name: EXTENSION pgcrypto; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION pgcrypto IS 'cryptographic functions'; + + +-- +-- Name: job_state; Type: TYPE; Schema: pgboss; Owner: test +-- + +CREATE TYPE pgboss.job_state AS ENUM ( + 'created', + 'retry', + 'active', + 'completed', + 'expired', + 'cancelled', + 'failed' +); + + +ALTER TYPE pgboss.job_state OWNER TO test; + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: archive; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.archive ( + id uuid NOT NULL, + name text NOT NULL, + priority integer NOT NULL, + data jsonb, + state pgboss.job_state NOT NULL, + retrylimit integer NOT NULL, + retrycount integer NOT NULL, + retrydelay integer NOT NULL, + retrybackoff boolean NOT NULL, + startafter timestamp with time zone NOT NULL, + startedon timestamp with time zone, + singletonkey text, + singletonon timestamp without time zone, + expirein interval NOT NULL, + createdon timestamp with time zone NOT NULL, + completedon timestamp with time zone, + archivedon timestamp with time zone DEFAULT now() NOT NULL +); + + +ALTER TABLE pgboss.archive OWNER TO test; + +-- +-- Name: job; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.job ( + id uuid DEFAULT public.gen_random_uuid() NOT NULL, + name text NOT NULL, + priority integer DEFAULT 0 NOT NULL, + data jsonb, + state pgboss.job_state DEFAULT 'created'::pgboss.job_state NOT NULL, + retrylimit integer DEFAULT 0 NOT NULL, + retrycount integer DEFAULT 0 NOT NULL, + retrydelay integer DEFAULT 0 NOT NULL, + retrybackoff boolean DEFAULT false NOT NULL, + startafter timestamp with time zone DEFAULT now() NOT NULL, + startedon timestamp with time zone, + singletonkey text, + singletonon timestamp without time zone, + expirein interval DEFAULT '00:15:00'::interval NOT NULL, + createdon timestamp with time zone DEFAULT now() NOT NULL, + completedon timestamp with time zone +); + + +ALTER TABLE pgboss.job OWNER TO test; + +-- +-- Name: version; Type: TABLE; Schema: pgboss; Owner: test +-- + +CREATE TABLE pgboss.version ( + version text NOT NULL +); + + +ALTER TABLE pgboss.version OWNER TO test; + +-- +-- Name: aliases; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.aliases ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + name text, + email text, + aff text +); + + +ALTER TABLE public.aliases OWNER TO test; + +-- +-- Name: channel_members; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.channel_members ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + user_id uuid NOT NULL, + channel_id uuid NOT NULL +); + + +ALTER TABLE public.channel_members OWNER TO test; + +-- +-- Name: channels; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.channels ( + id uuid NOT NULL, + manuscript_id uuid, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + topic text, + type text +); + + +ALTER TABLE public.channels OWNER TO test; + +-- +-- Name: entities; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.entities ( + id uuid NOT NULL, + data jsonb +); + + +ALTER TABLE public.entities OWNER TO test; + +-- +-- Name: files; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.files ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + label text, + file_type text, + filename text, + url text, + mime_type text, + size integer, + type text NOT NULL, + manuscript_id uuid, + review_comment_id uuid, + CONSTRAINT exactly_one_file_owner CHECK (((((manuscript_id IS NOT NULL))::integer + ((review_comment_id IS NOT NULL))::integer) = 1)) +); + + +ALTER TABLE public.files OWNER TO test; + +-- +-- Name: identities; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.identities ( + id uuid NOT NULL, + user_id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + type text NOT NULL, + identifier text, + name text, + aff text, + oauth jsonb, + is_default boolean +); + + +ALTER TABLE public.identities OWNER TO test; + +-- +-- Name: manuscripts; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.manuscripts ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + parent_id uuid, + submitter_id uuid, + status text, + decision text, + authors jsonb, + suggestions jsonb, + meta jsonb, + submission jsonb, + type text NOT NULL +); + + +ALTER TABLE public.manuscripts OWNER TO test; + +-- +-- Name: messages; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.messages ( + id uuid NOT NULL, + user_id uuid NOT NULL, + channel_id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + content text +); + + +ALTER TABLE public.messages OWNER TO test; + +-- +-- Name: migrations; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.migrations ( + id text NOT NULL, + run_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE public.migrations OWNER TO test; + +-- +-- Name: review_comments; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.review_comments ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + review_id uuid, + user_id uuid, + content text, + comment_type text, + type text +); + + +ALTER TABLE public.review_comments OWNER TO test; + +-- +-- Name: reviews; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.reviews ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + recommendation text, + is_decision boolean DEFAULT false, + user_id uuid, + manuscript_id uuid, + type text NOT NULL +); + + +ALTER TABLE public.reviews OWNER TO test; + +-- +-- Name: team_members; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.team_members ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + status character varying(255), + team_id uuid, + user_id uuid, + alias_id uuid +); + + +ALTER TABLE public.team_members OWNER TO test; + +-- +-- Name: teams; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.teams ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + name text, + role text NOT NULL, + members jsonb, + owners jsonb, + global boolean, + type text NOT NULL, + manuscript_id uuid +); + + +ALTER TABLE public.teams OWNER TO test; + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: test +-- + +CREATE TABLE public.users ( + id uuid NOT NULL, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated timestamp with time zone, + admin boolean, + email text, + username text, + password_hash text, + teams jsonb, + password_reset_token text, + password_reset_timestamp timestamp with time zone, + type text NOT NULL, + profile_picture text, + online boolean +); + + +ALTER TABLE public.users OWNER TO test; + +-- +-- Data for Name: archive; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + + + +-- +-- Data for Name: job; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + + + +-- +-- Data for Name: version; Type: TABLE DATA; Schema: pgboss; Owner: test +-- + +INSERT INTO pgboss.version (version) VALUES ('11'); + + +-- +-- Data for Name: aliases; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: channel_members; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: channels; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('afd95c06-011b-46e3-9985-964283d51c4a', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Manuscript discussion', 'all'); +INSERT INTO public.channels (id, manuscript_id, created, updated, topic, type) VALUES ('75540565-6619-495f-a8c5-d6bf11ece72d', '93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Editorial discussion', 'editorial'); + + +-- +-- Data for Name: entities; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: files; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: identities; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('d341a633-cdce-4a7f-a9ad-5afc03cd0dd1', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.741+02', '2020-07-21 16:17:25.87+02', 'orcid', '0000-0002-0564-2016', 'Emily Clay', NULL, '{"accessToken": "079a1165-31e5-4b59-9a99-d80ff7a21ebf", "refreshToken": "ccadc737-defc-419e-823b-a9f3673848ba"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('bcda196e-765a-42c8-94da-ca2e43b80f96', '3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.721+02', '2020-07-21 16:33:26.742+02', 'orcid', '0000-0002-5641-5729', 'Sinead Sullivan', NULL, '{"accessToken": "ef1ed3ec-8371-41b2-a136-fd196ae52a72", "refreshToken": "6972dace-d9a6-4cd3-a2ad-ec7eb3e457c7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('4af83984-6359-47c5-a075-5ddfa9c555d9', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.127+02', '2020-07-21 16:35:07.104+02', 'orcid', '0000-0002-7645-9921', 'Sherry Crofoot', NULL, '{"accessToken": "2ad4e130-0775-4e13-87fb-8e8f5a0570ae", "refreshToken": "159933d9-2020-4c02-bdfb-163af41017dc"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('acfa1777-0aec-4fe1-bc16-92bb9d19e884', '85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.384+02', '2020-07-21 16:35:39.358+02', 'orcid', '0000-0002-9429-4446', 'Elaine Barnes', NULL, '{"accessToken": "dcf07bc7-e59c-41b3-9ce0-924ac20aeeea", "refreshToken": "ae49d6a1-8e62-419d-8767-4a3ec22c1950"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('88c85115-d83c-42d7-a1a1-0139827977da', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.975+02', '2020-07-21 16:36:26.059+02', 'orcid', '0000-0001-5956-7341', 'Gale Davis', NULL, '{"accessToken": "3e9f6f6c-7cc0-4afa-9fdf-6ed377c36aad", "refreshToken": "80b1e911-df97-43f1-9f11-17b61913f6d7"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('049f91da-c84e-4b80-be2e-6e0cfca7a136', '231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.611+02', '2020-07-22 14:18:37.745+02', 'orcid', '0000-0003-2536-230X', 'Test Account', NULL, '{"accessToken": "eb551178-79e5-4189-8c5f-0a553092a9b5", "refreshToken": "4506fa5f-bd77-4867-afb4-0b07ea5302d6"}', true); +INSERT INTO public.identities (id, user_id, created, updated, type, identifier, name, aff, oauth, is_default) VALUES ('2fb8359c-239c-43fa-91f5-1ff2058272a6', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.604+02', '2020-07-24 15:21:55.7+02', 'orcid', '0000-0003-1838-2441', 'Joanne Pilger', NULL, '{"accessToken": "842de329-ef16-4461-b83b-e8fe57238904", "refreshToken": "524fbdc5-9c67-4b4c-af17-2ce4cf294e88"}', true); + + +-- +-- Data for Name: manuscripts; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.manuscripts (id, created, updated, parent_id, submitter_id, status, decision, authors, suggestions, meta, submission, type) VALUES ('93735475-08f6-436b-9db3-fe2364b9dbb2', '2020-08-12 16:16:44.9+02', '2020-08-12 16:17:12.499+02', NULL, '027afa6a-edbc-486e-bb31-71e12f8ea1c5', 'submitted', NULL, NULL, NULL, '{"notes": [{"content": "", "notesType": "fundingAcknowledgement"}, {"content": "", "notesType": "specialInstructions"}], "title": "My URL submission"}', '{"irb": "yes", "name": "Emily Clay", "cover": "This is my cover letter", "links": "https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml", "ethics": "This is my ethics statement", "contact": "emily@example.com", "methods": ["Functional MRI", "Optical Imaging"], "datacode": "This is my data and code availability statement", "humanMRI": "3T", "keywords": "some, keyword", "packages": ["SPM", "FSL"], "subjects": "patients", "suggested": "Erica James, Matthew Matretzky", "objectType": "software", "affiliation": "Example University, Egland", "otherMethods": "Erica James, Matthew Matretzky", "humanMRIother": "7T", "otherPackages": "Jupyter, Stencila", "animal_research_approval": "yes"}', 'Manuscript'); + + +-- +-- Data for Name: messages; Type: TABLE DATA; Schema: public; Owner: test +-- + + + +-- +-- Data for Name: migrations; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.migrations (id, run_at) VALUES ('1524494862-entities.sql', '2020-08-12 14:59:10.439327+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1542276313-initial-user-migration.sql', '2020-08-12 14:59:10.452184+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1560771823-add-unique-constraints-to-users.sql', '2020-08-12 14:59:10.463129+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1580908536-add-identities.sql', '2020-08-12 14:59:10.477935+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581371297-migrate-users-to-identities.js', '2020-08-12 14:59:10.499722+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1581450834-manuscript.sql', '2020-08-12 14:59:10.509542+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1582930582-drop-fragments-and-collections.js', '2020-08-12 14:59:10.519573+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585323910-add-channels.sql', '2020-08-12 14:59:10.533012+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585344885-add-messages.sql', '2020-08-12 14:59:10.544214+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1585513226-add-profile-pic.sql', '2020-08-12 14:59:10.549847+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1592915682-change-identities-constraint.sql', '2020-08-12 14:59:10.558714+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830547-review.sql', '2020-08-12 14:59:10.571826+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-add-review-comments.sql', '2020-08-12 14:59:10.583466+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596830548-initial-team-migration.sql', '2020-08-12 14:59:10.611618+02'); +INSERT INTO public.migrations (id, run_at) VALUES ('1596838897-files.sql', '2020-08-12 14:59:10.627188+02'); + + +-- +-- Data for Name: review_comments; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('f73fdbd8-6fb6-4d7a-a74a-ab2c2c07b572', '2020-08-13 15:09:33.838+02', '2020-08-13 15:09:33.838+02', '5a06fcf3-d368-4f65-917c-1acdb73fcc71', NULL, '<p>Great paper, congratulations! Gale Davis</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('5c86da62-bc7f-4d23-8968-62bd5a56a52b', '2020-08-13 15:09:34.88+02', '2020-08-13 15:09:34.88+02', '5a06fcf3-d368-4f65-917c-1acdb73fcc71', NULL, '<p>This is a very important paper. Gale Davis</p>', 'confidential', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('ef96b249-dab6-4f7e-b24e-571b340b9b41', '2020-08-13 15:09:38.761+02', '2020-08-13 15:09:38.761+02', '7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', NULL, '<p>Great paper, congratulations! Sherry Crofoot</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('04a8a70e-7787-4fd6-bdca-bfac3aa86951', '2020-08-13 15:09:40.155+02', '2020-08-13 15:09:40.155+02', '7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', NULL, '<p>This is a very important paper. Sherry Crofoot</p>', 'confidential', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('7ccda096-07c2-4569-ad0f-5b3574db205e', '2020-08-13 15:09:44.046+02', '2020-08-13 15:09:44.046+02', '3a34e0ef-6695-4268-b901-60de20f9cf4e', NULL, '<p>Great paper, congratulations! Elaine Barnes</p>', 'review', 'ReviewComment'); +INSERT INTO public.review_comments (id, created, updated, review_id, user_id, content, comment_type, type) VALUES ('c8b7d1c9-aef2-47d0-a9ad-c9d46706e79e', '2020-08-13 15:09:45.548+02', '2020-08-13 15:09:45.548+02', '3a34e0ef-6695-4268-b901-60de20f9cf4e', NULL, '<p>This is a very important paper. Elaine Barnes</p>', 'confidential', 'ReviewComment'); + + +-- +-- Data for Name: reviews; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('5a06fcf3-d368-4f65-917c-1acdb73fcc71', '2020-08-13 15:09:32.358+02', '2020-08-13 15:09:34.925+02', 'accepted', false, '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('7c6cd2f6-c23e-4902-96ac-df4801ac3d0a', '2020-08-13 15:09:36.501+02', '2020-08-13 15:09:40.159+02', 'accepted', false, '0da0bbec-9261-4706-b990-0c10aa3cc6b4', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); +INSERT INTO public.reviews (id, created, updated, recommendation, is_decision, user_id, manuscript_id, type) VALUES ('3a34e0ef-6695-4268-b901-60de20f9cf4e', '2020-08-13 15:09:41.911+02', '2020-08-13 15:09:45.561+02', 'accepted', false, '85e1300e-003c-4e96-987b-23812f902477', '93735475-08f6-436b-9db3-fe2364b9dbb2', 'Review'); + + +-- +-- Data for Name: team_members; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('6505126d-2ecd-498b-a27d-18eafbdbc8a6', '2020-08-12 16:16:44.923+02', '2020-08-12 16:16:44.923+02', NULL, 'c31e3116-6176-45b5-b52c-6f7cbfc86007', '027afa6a-edbc-486e-bb31-71e12f8ea1c5', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('031ae180-e94e-458d-86b7-f2dc1d456e2e', '2020-08-12 16:17:14.795+02', '2020-08-12 16:17:14.795+02', NULL, 'bf800912-56c4-44eb-b425-64e51a9824fe', '1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('c4ac4fc0-3fae-43b0-89ee-bf7f8fd9885f', '2020-08-12 16:17:43.262+02', '2020-08-13 15:09:41.898+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '40e3d054-9ac8-4c0f-84ed-e3c6307662cd', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('69e896c6-0fdb-421d-a638-1ef7670c03c9', '2020-08-12 16:17:43.884+02', '2020-08-13 15:09:41.898+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '0da0bbec-9261-4706-b990-0c10aa3cc6b4', NULL); +INSERT INTO public.team_members (id, created, updated, status, team_id, user_id, alias_id) VALUES ('12c33ef5-4fc3-4d48-8309-a90c0461113c', '2020-08-12 16:17:44.547+02', '2020-08-13 15:09:45.782+02', 'completed', '0719d132-bb6c-49d9-9122-7911a48cfd60', '85e1300e-003c-4e96-987b-23812f902477', NULL); + + +-- +-- Data for Name: teams; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('c31e3116-6176-45b5-b52c-6f7cbfc86007', '2020-08-12 16:16:44.916+02', '2020-08-12 16:16:44.916+02', 'Author', 'author', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('bf800912-56c4-44eb-b425-64e51a9824fe', '2020-08-12 16:17:14.789+02', '2020-08-12 16:17:14.789+02', 'Senior Editor', 'seniorEditor', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); +INSERT INTO public.teams (id, created, updated, name, role, members, owners, global, type, manuscript_id) VALUES ('0719d132-bb6c-49d9-9122-7911a48cfd60', '2020-08-12 16:17:43.258+02', '2020-08-13 15:09:41.898+02', 'Reviewers', 'reviewer', NULL, NULL, NULL, 'team', '93735475-08f6-436b-9db3-fe2364b9dbb2'); + + +-- +-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: test +-- + +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('231717dd-ba09-43d4-ac98-9d5542b27a0c', '2020-07-22 14:18:36.597+02', '2020-07-24 16:43:54.939+02', NULL, NULL, '000000032536230X', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser5.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('027afa6a-edbc-486e-bb31-71e12f8ea1c5', '2020-07-21 16:17:24.734+02', '2020-08-12 16:17:13.598+02', NULL, NULL, '0000000205642016', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser2.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('3802b0e7-aadc-45de-9cf9-918fede99b97', '2020-07-21 16:30:45.719+02', '2020-08-12 16:17:14.868+02', true, NULL, '0000000256415729', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser6.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('40e3d054-9ac8-4c0f-84ed-e3c6307662cd', '2020-07-21 16:36:24.973+02', '2020-08-13 15:09:35.913+02', NULL, NULL, '0000000159567341', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser4.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('0da0bbec-9261-4706-b990-0c10aa3cc6b4', '2020-07-21 16:35:06.125+02', '2020-08-13 15:09:41.198+02', NULL, NULL, '0000000276459921', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser7.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('85e1300e-003c-4e96-987b-23812f902477', '2020-07-21 16:35:38.381+02', '2020-08-13 15:09:46.741+02', NULL, NULL, '0000000294294446', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser1.jpg', false); +INSERT INTO public.users (id, created, updated, admin, email, username, password_hash, teams, password_reset_token, password_reset_timestamp, type, profile_picture, online) VALUES ('1d599f2c-d293-4d5e-b6c1-ba34e81e3fc8', '2020-07-24 15:21:54.59+02', '2020-08-13 15:09:47.167+02', NULL, NULL, '0000000318382441', NULL, NULL, NULL, NULL, 'user', '/static/profiles/testuser3.jpg', true); + + +-- +-- Name: job job_pkey; Type: CONSTRAINT; Schema: pgboss; Owner: test +-- + +ALTER TABLE ONLY pgboss.job + ADD CONSTRAINT job_pkey PRIMARY KEY (id); + + +-- +-- Name: version version_pkey; Type: CONSTRAINT; Schema: pgboss; Owner: test +-- + +ALTER TABLE ONLY pgboss.version + ADD CONSTRAINT version_pkey PRIMARY KEY (version); + + +-- +-- Name: aliases aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.aliases + ADD CONSTRAINT aliases_pkey PRIMARY KEY (id); + + +-- +-- Name: channel_members channel_members_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_pkey PRIMARY KEY (id); + + +-- +-- Name: channels channels_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channels + ADD CONSTRAINT channels_pkey PRIMARY KEY (id); + + +-- +-- Name: entities entities_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_pkey PRIMARY KEY (id); + + +-- +-- Name: files files_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_pkey PRIMARY KEY (id); + + +-- +-- Name: identities identities_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.identities + ADD CONSTRAINT identities_pkey PRIMARY KEY (id); + + +-- +-- Name: manuscripts manuscripts_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.manuscripts + ADD CONSTRAINT manuscripts_pkey PRIMARY KEY (id); + + +-- +-- Name: messages messages_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_pkey PRIMARY KEY (id); + + +-- +-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.migrations + ADD CONSTRAINT migrations_pkey PRIMARY KEY (id); + + +-- +-- Name: review_comments review_comments_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_pkey PRIMARY KEY (id); + + +-- +-- Name: reviews reviews_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_pkey PRIMARY KEY (id); + + +-- +-- Name: team_members team_members_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_pkey PRIMARY KEY (id); + + +-- +-- Name: teams teams_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_email_key; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_email_key UNIQUE (email); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_username_key; Type: CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_username_key UNIQUE (username); + + +-- +-- Name: archive_archivedon_idx; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX archive_archivedon_idx ON pgboss.archive USING btree (archivedon); + + +-- +-- Name: archive_id_idx; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX archive_id_idx ON pgboss.archive USING btree (id); + + +-- +-- Name: job_name; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE INDEX job_name ON pgboss.job USING btree (name text_pattern_ops); + + +-- +-- Name: job_singletonkey; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonkey ON pgboss.job USING btree (name, singletonkey) WHERE ((state < 'completed'::pgboss.job_state) AND (singletonon IS NULL)); + + +-- +-- Name: job_singletonkeyon; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonkeyon ON pgboss.job USING btree (name, singletonon, singletonkey) WHERE (state < 'expired'::pgboss.job_state); + + +-- +-- Name: job_singletonon; Type: INDEX; Schema: pgboss; Owner: test +-- + +CREATE UNIQUE INDEX job_singletonon ON pgboss.job USING btree (name, singletonon) WHERE ((state < 'expired'::pgboss.job_state) AND (singletonkey IS NULL)); + + +-- +-- Name: channel_members_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX channel_members_idx ON public.channel_members USING btree (user_id, channel_id); + + +-- +-- Name: is_default_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE UNIQUE INDEX is_default_idx ON public.identities USING btree (is_default, user_id) WHERE (is_default IS TRUE); + + +-- +-- Name: team_members_team_id_user_id_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX team_members_team_id_user_id_idx ON public.team_members USING btree (team_id, user_id); + + +-- +-- Name: teams_manuscript_id_idx; Type: INDEX; Schema: public; Owner: test +-- + +CREATE INDEX teams_manuscript_id_idx ON public.teams USING btree (manuscript_id); + + +-- +-- Name: channel_members channel_members_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id); + + +-- +-- Name: channel_members channel_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channel_members + ADD CONSTRAINT channel_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: channels channels_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.channels + ADD CONSTRAINT channels_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: files files_review_comment_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.files + ADD CONSTRAINT files_review_comment_id_fkey FOREIGN KEY (review_comment_id) REFERENCES public.review_comments(id) ON DELETE CASCADE; + + +-- +-- Name: manuscripts manuscripts_submitter_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.manuscripts + ADD CONSTRAINT manuscripts_submitter_id_fkey FOREIGN KEY (submitter_id) REFERENCES public.users(id); + + +-- +-- Name: messages messages_channel_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_channel_id_fkey FOREIGN KEY (channel_id) REFERENCES public.channels(id) ON DELETE CASCADE; + + +-- +-- Name: messages messages_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.messages + ADD CONSTRAINT messages_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_review_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_review_id_fkey FOREIGN KEY (review_id) REFERENCES public.reviews(id) ON DELETE CASCADE; + + +-- +-- Name: review_comments review_comments_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.review_comments + ADD CONSTRAINT review_comments_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL; + + +-- +-- Name: reviews reviews_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.reviews + ADD CONSTRAINT reviews_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- Name: identities sidentities_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.identities + ADD CONSTRAINT sidentities_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: team_members team_members_alias_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_alias_id_fkey FOREIGN KEY (alias_id) REFERENCES public.aliases(id); + + +-- +-- Name: team_members team_members_team_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_team_id_fkey FOREIGN KEY (team_id) REFERENCES public.teams(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- Name: team_members team_members_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.team_members + ADD CONSTRAINT team_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE; + + +-- +-- Name: teams teams_manuscript_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: test +-- + +ALTER TABLE ONLY public.teams + ADD CONSTRAINT teams_manuscript_id_fkey FOREIGN KEY (manuscript_id) REFERENCES public.manuscripts(id) ON DELETE CASCADE; + + +-- +-- PostgreSQL database dump complete +-- + diff --git a/cypress/integration/assign_reviewers_spec.js b/cypress/integration/assign_reviewers_spec.js index 8b041451ce0f0697ea9e173f14dbf01859c7326f..84e8c7894ec7bc7b495eadbee17439fcbdedb0c2 100644 --- a/cypress/integration/assign_reviewers_spec.js +++ b/cypress/integration/assign_reviewers_spec.js @@ -1,9 +1,9 @@ -const login = name => { - cy.task('createToken', name).then(token => { - cy.setToken(token) - cy.visit('/journal/dashboard') - }) -} +// const login = name => { +// cy.task('createToken', name).then(token => { +// cy.setToken(token) +// cy.visit('/journal/dashboard') +// }) +// } const inviteReviewer = name => { cy.get('*[aria-label*="Invite reviewers"]').click({ @@ -21,7 +21,7 @@ describe('Editor assigning reviewers', () => { it('can assign 3 reviewers', () => { cy.task('restore', 'senior_editor_assigned') - login('Joanne Pilger') + cy.login('Joanne Pilger') cy.contains('Control Panel').click() cy.contains('Manage Reviewers').click() diff --git a/cypress/integration/decision_spec.js b/cypress/integration/decision_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..018bfae8ba5e71956c91fe6b04bcc058982858c1 --- /dev/null +++ b/cypress/integration/decision_spec.js @@ -0,0 +1,29 @@ +describe('Completing a review', () => { + it('accept and do a review', () => { + cy.task('restore', 'three_reviews_completed') + + cy.login('Joanne Pilger') // Senior editor + + cy.contains('Control Panel').click() + + cy.get('[data-testid="decisionComment"]').click() + cy.focused().blur() + + // Validations run on blur + cy.contains('Decision letter is required') + cy.get('[data-testid="decisionComment"] div[contenteditable="true"]') + .click({ force: true }) + .type(`Great paper, dear authors, congratulations!`) + + cy.contains('Accept').click({ force: true }) + cy.contains('Submit').click() + cy.contains('Your decision has been saved.') + cy.visit('/journal/dashboard') + cy.contains('Accepted') + + // Regression test, previously this count increased when a decision was made + cy.get('[data-testid="completed"]').should('have.text', '3completed') + + cy.task('dump', 'decision_completed') + }) +}) diff --git a/cypress/integration/review_spec.js b/cypress/integration/review_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..a4a90e1bdc5e462f7f4a6554d63f506f0d178f80 --- /dev/null +++ b/cypress/integration/review_spec.js @@ -0,0 +1,38 @@ +const doReview = name => { + cy.login(name) + + cy.get('[data-testid="accept-review"]').click() + cy.contains('Do Review').click() + + cy.contains('My URL submission') + cy.contains('This is my data and code availability statement') + + cy.get('[data-testid="reviewComment"]') + .click() + .type(`Great paper, congratulations! ${name}`) + cy.get('[data-testid="confidentialComment"]') + .click() + .type(`This is a very important paper. ${name}`) + + cy.contains('Accept').click() + cy.contains('Submit').click() + + cy.visit('/journal/dashboard') + cy.contains('Completed') +} + +describe('Completing a review', () => { + it('accept and do a review', () => { + cy.task('restore', 'reviewers_invited') + + doReview('Gale Davis') // Reviewers + doReview('Sherry Crofoot') + doReview('Elaine Barnes') + + cy.login('Joanne Pilger') // Senior editor + + cy.get('[data-testid="completed"]').should('have.text', '3completed') + + cy.task('dump', 'three_reviews_completed') + }) +}) diff --git a/cypress/integration/submission_spec.js b/cypress/integration/submission_spec.js index dbd1bd2df6ceb52b2fef2c775d2ddce555a773eb..6e98b5780ae19d36a1e7dc25051e8994f995c7ac 100644 --- a/cypress/integration/submission_spec.js +++ b/cypress/integration/submission_spec.js @@ -62,6 +62,20 @@ describe('URL submission test', () => { 'https://doi.org/10.6084/m9.figshare.913521.v1, https://github.com/jure/mathtype_to_mathml', ) + // Supplementary file upload + cy.fixture('test-pdf.pdf', 'base64').then(fileContent => { + cy.get('[data-testid="dropzone"]').attachFile( + 'test-pdf.pdf', + // { + // fileContent, + // fileName: 'test-pdf.pdf', + // encoding: 'base64', + // mimeType: 'application/pdf', + // }, + { subjectType: 'drag-n-drop' }, + ) + }) + cy.get('[data-testid="submission.keywords"]') .click() .type('some, keywords') @@ -144,7 +158,7 @@ describe('URL submission test', () => { cy.contains('Control Panel').click() cy.contains('This is my data and code availability statement') - + cy.contains('test-pdf.pdf') cy.task('dump', 'senior_editor_assigned') }) }) diff --git a/cypress/screenshots/assign_reviewers_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png b/cypress/screenshots/assign_reviewers_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..9b353afdeae50e1fb53a41e80f817c0bb682414a Binary files /dev/null and b/cypress/screenshots/assign_reviewers_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png differ diff --git a/cypress/screenshots/review_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png b/cypress/screenshots/review_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..9b353afdeae50e1fb53a41e80f817c0bb682414a Binary files /dev/null and b/cypress/screenshots/review_spec.js/Editor assigning reviewers -- can assign 3 reviewers (failed).png differ diff --git a/cypress/screenshots/submission_spec.js/URL submission test -- can submit a URL and some metadata (failed).png b/cypress/screenshots/submission_spec.js/URL submission test -- can submit a URL and some metadata (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..c8aa71791004b322002139c08c144aeede81dae5 Binary files /dev/null and b/cypress/screenshots/submission_spec.js/URL submission test -- can submit a URL and some metadata (failed).png differ diff --git a/cypress/screenshots/submission_spec.js/URL submission test -- senior editor can view the submission (failed).png b/cypress/screenshots/submission_spec.js/URL submission test -- senior editor can view the submission (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..30f7279081d5979ed210e72d724338a351c71aea Binary files /dev/null and b/cypress/screenshots/submission_spec.js/URL submission test -- senior editor can view the submission (failed).png differ diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 9a0fa26c03700524169b7e4b94de90754412054c..348a2bcb967291476f69008018f2d6a80e0240fa 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ import 'cypress-file-upload' // *********************************************** @@ -27,6 +28,12 @@ import 'cypress-file-upload' // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) Cypress.Commands.add('setToken', token => { - console.log('Setting token', token) localStorage.setItem('token', token) }) + +Cypress.Commands.add('login', name => { + cy.task('createToken', name).then(token => { + cy.setToken(token) + cy.visit('/journal/dashboard') + }) +}) diff --git a/cypress/videos/assign_reviewers_spec.js.mp4 b/cypress/videos/assign_reviewers_spec.js.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..865430db176851c5dd640d7fe4c8afea33a5f4fe Binary files /dev/null and b/cypress/videos/assign_reviewers_spec.js.mp4 differ diff --git a/cypress/videos/login_spec.js.mp4 b/cypress/videos/login_spec.js.mp4 index 677c7899add35cf4c405c59b7b5be934886774d4..9cef58dbb03a38ca8918a5b39eb7cd1f2572f926 100644 Binary files a/cypress/videos/login_spec.js.mp4 and b/cypress/videos/login_spec.js.mp4 differ diff --git a/cypress/videos/submission_spec.js.mp4 b/cypress/videos/submission_spec.js.mp4 index c15776f8fd7e373407ac86e60ffcfe1fa103290d..3a89b44d3ff16445320d635b489efa0f5a2fd34f 100644 Binary files a/cypress/videos/submission_spec.js.mp4 and b/cypress/videos/submission_spec.js.mp4 differ diff --git a/package.json b/package.json index 1a16ea08843148ec905b6e15cb377152d8311c20..eb0d20005b982bfaef31646a82f534df1f31405b 100644 --- a/package.json +++ b/package.json @@ -143,8 +143,10 @@ "start:services": "docker-compose up postgres", "start:server-and-client": "start-test server 'http://localhost:3000/healthcheck' client", "test:server-and-client": "start-test server:test 'http://localhost:3000/healthcheck' client", - "test:all": "start-test test:server-and-client 4000 test", - "test": "cypress run", + "test:all:firefox": "start-test test:server-and-client 4000 test:firefox", + "test:all:chrome": "start-test test:server-and-client 4000 test:chrome", + "test:firefox": "cypress run --browser firefox --headless", + "test:chrome": "cypress run --browser chrome", "__cleanNodeModules": "find . -name 'node_modules' -type d -prune -print -exec rm -rf '{}' \\;", "build": "NODE_ENV=production pubsweet build", "seedFromDump": "node scripts/seedFromDump.js" diff --git a/server/component-xpub-review-backend/src/reviewBackend.js b/server/component-xpub-review-backend/src/reviewBackend.js index bdee8d7b59b3f6fdd5a205cde4a0fcd44f2c967e..1132bc19e477e44581e24425e75415f30cdfee8b 100644 --- a/server/component-xpub-review-backend/src/reviewBackend.js +++ b/server/component-xpub-review-backend/src/reviewBackend.js @@ -82,8 +82,7 @@ module.exports = app => { { role: 'reviewer', name: 'Reviewer', - objectId: version.id, - objectType: 'fragment', + manuscriptId: version.id, members: [{ user: { id: reviewer[0].id } }], }, { relate: true }, diff --git a/server/model-channel/src/migrations/1585323910-add-channels.sql b/server/model-channel/src/migrations/1585323910-add-channels.sql index 00b50f44df9754f8af82b46adfe61a6c6cb9fc86..bde9bf147777365ba83232c162c7d28567161a7d 100644 --- a/server/model-channel/src/migrations/1585323910-add-channels.sql +++ b/server/model-channel/src/migrations/1585323910-add-channels.sql @@ -1,7 +1,6 @@ CREATE TABLE channels ( id UUID PRIMARY KEY, manuscript_id uuid REFERENCES manuscripts(id) ON DELETE CASCADE, - team_id uuid REFERENCES teams(id), created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, updated TIMESTAMP WITH TIME ZONE, topic TEXT, diff --git a/server/model-file/src/file.js b/server/model-file/src/file.js index 64284826f7414791e1487bea8c05a5d25462abc3..de10f74af9ab6973e24f20e8ea98d661f3581e2f 100644 --- a/server/model-file/src/file.js +++ b/server/model-file/src/file.js @@ -1,5 +1,4 @@ const BaseModel = require('@pubsweet/base-model') -const logger = require('@pubsweet/logger') class File extends BaseModel { static get tableName() { @@ -11,6 +10,29 @@ class File extends BaseModel { this.type = 'file' } + static get relationMappings() { + const { Manuscript, ReviewComment } = require('@pubsweet/models') + + return { + manuscript: { + relation: BaseModel.BelongsToOneRelation, + modelClass: Manuscript, + join: { + from: 'manuscripts.id', + to: 'files.manuscript_id', + }, + }, + reviewComment: { + relation: BaseModel.BelongsToOneRelation, + modelClass: ReviewComment, + join: { + from: 'review_comments.id', + to: 'files.review_comments_id', + }, + }, + } + } + static get schema() { return { properties: { @@ -20,25 +42,11 @@ class File extends BaseModel { fileType: { type: ['string', 'null'] }, filename: { type: ['string', 'null'] }, size: { type: ['integer', 'null'] }, - object: { type: ['string', 'null'] }, - objectId: { type: 'string', format: 'uuid' }, + reviewCommentId: { type: ['string', 'null'], format: 'uuid' }, + manuscriptId: { type: ['string', 'null'], format: 'uuid' }, }, } } - - static async findByObject({ object, object_id }) { - logger.debug('Finding Files by Object') - - const results = await this.query() - .where('object', object) - .andWhere('object_id', object_id) - - return results - } - - // async $beforeDelete() { - // await Team.deleteAssociated(this.data.type, this.id) - // } } File.type = 'file' diff --git a/server/model-file/src/index.js b/server/model-file/src/index.js index 5f1d108b1e4e4ec0e9e547db5bdbb08af74de6a6..3146f811a5304a8da93c489f57f81acad29efbd6 100644 --- a/server/model-file/src/index.js +++ b/server/model-file/src/index.js @@ -1,10 +1,8 @@ const resolvers = require('./resolvers') const typeDefs = require('./typeDefs') -const model = require('./file') module.exports = { - model, - modelName: 'File', + models: [{ modelName: 'File', model: require('./file') }], resolvers, typeDefs, } diff --git a/server/model-file/src/migrations/1537450834-files.sql b/server/model-file/src/migrations/1537450834-files.sql deleted file mode 100644 index c18083f7b9455aefcadbabe42d3821d1052f5d24..0000000000000000000000000000000000000000 --- a/server/model-file/src/migrations/1537450834-files.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TABLE files ( - id UUID PRIMARY KEY, - created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, - updated TIMESTAMP WITH TIME ZONE, - object TEXT, - object_id UUID, - label TEXT, - file_type TEXT, - filename TEXT, - url TEXT, - mime_type TEXT, - size INTEGER, - type TEXT NOT NULL -); \ No newline at end of file diff --git a/server/model-file/src/migrations/1596838897-files.sql b/server/model-file/src/migrations/1596838897-files.sql new file mode 100644 index 0000000000000000000000000000000000000000..f823bc1ce840b4300e346776bf163aff24fdf889 --- /dev/null +++ b/server/model-file/src/migrations/1596838897-files.sql @@ -0,0 +1,24 @@ +CREATE TABLE files ( + id UUID PRIMARY KEY, + created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, + updated TIMESTAMP WITH TIME ZONE, + -- object_type TEXT, + -- object_id UUID, + label TEXT, + file_type TEXT, + filename TEXT, + url TEXT, + mime_type TEXT, + size INTEGER, + type TEXT NOT NULL, + -- Things that can have files + manuscript_id UUID REFERENCES manuscripts(id) ON DELETE CASCADE, + review_comment_id UUID REFERENCES review_comments(id) ON DELETE CASCADE, + + constraint exactly_one_file_owner check( + ( + (manuscript_id is not null)::integer + + (review_comment_id is not null)::integer + ) = 1 + ) +); \ No newline at end of file diff --git a/server/model-file/src/resolvers.js b/server/model-file/src/resolvers.js index da8ea91c7c9c0b3e9a1423ac232df849defd7a10..5001766ded287034c90740b1662935484791cf5f 100644 --- a/server/model-file/src/resolvers.js +++ b/server/model-file/src/resolvers.js @@ -10,8 +10,8 @@ const randomBytes = promisify(crypto.randomBytes) const uploadsPath = config.get('pubsweet-server').uploads const upload = async file => { - const { stream, filename, encoding } = await file - + const { createReadStream, filename, encoding } = await file + const stream = createReadStream() const raw = await randomBytes(16) const generatedFilename = raw.toString('hex') + path.extname(filename) const outPath = path.join(uploadsPath, generatedFilename) @@ -32,6 +32,7 @@ const resolvers = { const path = await upload(file) meta.url = `/static/${path}` const data = await new File(meta).save() + return data }, }, diff --git a/server/model-file/src/typeDefs.js b/server/model-file/src/typeDefs.js index 34050c96a91107418bba4e9e5951163a8bc5dc72..d9d84614fc758b9025cb5b5423fbe8a5b0c85967 100644 --- a/server/model-file/src/typeDefs.js +++ b/server/model-file/src/typeDefs.js @@ -8,8 +8,8 @@ const typeDefs = ` fileType: String filename: String mimeType: String - object: String - objectId: ID! + manuscriptId: ID + reviewCommentId: ID label: String size: Int } @@ -18,8 +18,8 @@ const typeDefs = ` id: ID! created: DateTime! updated: DateTime - object: String - objectId: ID! + manuscriptId: ID + reviewCommentId: ID label: String fileType: String filename: String diff --git a/server/model-manuscript/src/graphql.js b/server/model-manuscript/src/graphql.js index cc598e633a7b61e98189582678707f64524add96..c3819736ac1427bc73f031ed0e1e5b967dadfdb5 100644 --- a/server/model-manuscript/src/graphql.js +++ b/server/model-manuscript/src/graphql.js @@ -5,8 +5,6 @@ const { ref } = require('objection') const resolvers = { Mutation: { async createManuscript(_, vars, ctx) { - const { Team } = require('@pubsweet/models') - const { meta, files } = vars.input // We want the submission information to be stored as JSONB @@ -31,55 +29,38 @@ const resolvers = { status: 'new', submission, submitterId: ctx.user.id, + // Create two channels: 1. free for all involved, 2. editorial + channels: [ + { + topic: 'Manuscript discussion', + type: 'all', + }, + { + topic: 'Editorial discussion', + type: 'editorial', + }, + ], + files: files.map(file => + Object.assign({}, file, { + fileType: 'manuscript', + }), + ), + reviews: [], + teams: [ + { + role: 'author', + name: 'Author', + members: [{ user: { id: ctx.user.id } }], + }, + ], } - // eslint-disable-next-line - const manuscript = await new ctx.models.Manuscript( + const manuscript = await ctx.models.Manuscript.query().upsertGraphAndFetch( emptyManuscript, - ).saveGraph() - - // Create two channels: 1. free for all involved, 2. editorial - const allChannel = new ctx.models.Channel({ - manuscriptId: manuscript.id, - topic: 'Manuscript discussion', - type: 'all', - }).save() - - const editorialChannel = new ctx.models.Channel({ - manuscriptId: manuscript.id, - topic: 'Editorial discussion', - type: 'editorial', - }).save() - - manuscript.manuscriptVersions = [] - manuscript.files = [] - files.map(async file => { - const newFile = Object.assign({}, file, { - fileType: 'manuscript', - object: 'Manuscript', - objectId: manuscript.id, - }) - manuscript.files.push( - // eslint-disable-next-line - await new ctx.models.File(newFile).save(), - ) - }) - - manuscript.reviews = [] - - const createdTeam = await Team.query().upsertGraphAndFetch( - { - role: 'author', - name: 'Author', - objectId: manuscript.id, - objectType: 'Manuscript', - members: [{ user: { id: ctx.user.id } }], - }, { relate: true }, ) - manuscript.teams = [createdTeam] - manuscript.channels = [allChannel, editorialChannel] + manuscript.manuscriptVersions = [] return manuscript }, async deleteManuscript(_, { id }, ctx) { @@ -134,7 +115,7 @@ const resolvers = { recommendation: '', isDecision: false, userId: currentUserId, - manuscriptId: team.objectId, + manuscriptId: team.manuscriptId, } await new Review(review).save() } @@ -184,8 +165,7 @@ const resolvers = { // Create a new team of reviewers if it doesn't exist const newTeam = await new ctx.models.Team({ - objectId: manuscriptId, - objectType: 'Manuscript', + manuscriptId, members: [{ status: 'invited', userId }], role: 'reviewer', name: 'Reviewers', @@ -219,7 +199,7 @@ const resolvers = { const manuscript = await Manuscript.query() .findById(id) - .eager('[teams, channels, reviews]') + .eager('[teams, channels, reviews.[user, comments], files]') if (!manuscript.meta) { manuscript.meta = {} @@ -235,10 +215,6 @@ const resolvers = { }, ] manuscript.decision = '' - manuscript.files = await ctx.models.File.findByObject({ - object: 'Manuscript', - object_id: manuscript.id, - }) manuscript.manuscriptVersions = await manuscript.getManuscriptVersions() // manuscript.channel = await ctx.connectors.Channel.model.find( diff --git a/server/model-manuscript/src/manuscript.js b/server/model-manuscript/src/manuscript.js index 129205d139016f9cfd44cca933f491fa077d5956..16a9b26d8d3db838373293af8e353d6d4b1bd9c7 100644 --- a/server/model-manuscript/src/manuscript.js +++ b/server/model-manuscript/src/manuscript.js @@ -2,7 +2,6 @@ const BaseModel = require('@pubsweet/base-model') const omit = require('lodash/omit') const cloneDeep = require('lodash/cloneDeep') const sortBy = require('lodash/sortBy') -const values = require('lodash/values') class Manuscript extends BaseModel { static get tableName() { @@ -14,48 +13,48 @@ class Manuscript extends BaseModel { this.type = 'Manuscript' } - static async myManuscripts(myManuscripts) { - const mainManuscript = {} - myManuscripts.forEach(manuscript => { - if (!mainManuscript[manuscript.parentId || manuscript.id]) { - mainManuscript[manuscript.parentId || manuscript.id] = manuscript - } else { - const checkManuscript = - mainManuscript[manuscript.parentId || manuscript.id] - // Compare Dates - const dateCheckManuscript = new Date(checkManuscript.created).getTime() - const dateManuscript = new Date(manuscript.created).getTime() - if (dateManuscript >= dateCheckManuscript) { - mainManuscript[manuscript.parentId || manuscript.id] = manuscript - } - } - }) - - const latestManuscripts = values(mainManuscript) - await Promise.all( - latestManuscripts.map(async manuscript => { - manuscript.teams = await new Manuscript(manuscript).getTeams() - manuscript.reviews = await new Manuscript(manuscript).getReviews() - manuscript.manuscriptVersions = - (await manuscript.getManuscriptVersions()) || [] - return manuscript - }), - ) - - return latestManuscripts - } - - async getTeams() { - const { Team } = require('@pubsweet/models') - const myTeams = await Team.query() - .where({ - objectId: this.id, - objectType: 'Manuscript', - }) - .eager('members') - - return myTeams - } + // static async myManuscripts(myManuscripts) { + // const mainManuscript = {} + // myManuscripts.forEach(manuscript => { + // if (!mainManuscript[manuscript.parentId || manuscript.id]) { + // mainManuscript[manuscript.parentId || manuscript.id] = manuscript + // } else { + // const checkManuscript = + // mainManuscript[manuscript.parentId || manuscript.id] + // // Compare Dates + // const dateCheckManuscript = new Date(checkManuscript.created).getTime() + // const dateManuscript = new Date(manuscript.created).getTime() + // if (dateManuscript >= dateCheckManuscript) { + // mainManuscript[manuscript.parentId || manuscript.id] = manuscript + // } + // } + // }) + + // const latestManuscripts = values(mainManuscript) + // await Promise.all( + // latestManuscripts.map(async manuscript => { + // manuscript.teams = await new Manuscript(manuscript).getTeams() + // manuscript.reviews = await new Manuscript(manuscript).getReviews() + // manuscript.manuscriptVersions = + // (await manuscript.getManuscriptVersions()) || [] + // return manuscript + // }), + // ) + + // return latestManuscripts + // } + + // async getTeams() { + // const { Team } = require('@pubsweet/models') + // const myTeams = await Team.query() + // .where({ + // objectId: this.id, + // objectType: 'Manuscript', + // }) + // .eager('members') + + // return myTeams + // } async getReviews() { // TODO: Use relationships @@ -73,15 +72,15 @@ class Manuscript extends BaseModel { } async getManuscriptVersions() { - const { File } = require('@pubsweet/models') + // const { File } = require('@pubsweet/models') const id = this.parentId || this.id const manuscripts = await Manuscript.query() .where('parent_id', id) - .eager('[teams, teams.members, reviews]') + .eager('[teams, teams.members, reviews, files]') const firstManuscript = await Manuscript.query() .findById(id) - .eager('[teams, teams.members, reviews]') + .eager('[teams, teams.members, reviews, files]') manuscripts.push(firstManuscript) const manuscriptVersionsArray = manuscripts.filter( @@ -95,16 +94,6 @@ class Manuscript extends BaseModel { manuscript => new Date(manuscript.created), ) - await Promise.all( - manuscriptVersions.map(async manuscript => { - manuscript.files = await File.findByObject({ - object: 'Manuscript', - object_id: manuscript.id, - }) - return manuscript - }), - ) - return manuscriptVersions } @@ -122,9 +111,8 @@ class Manuscript extends BaseModel { team.role === 'handlingEditor', ) - const manuscriptFiles = await File.findByObject({ - object: 'Manuscript', - object_id: this.id, + const manuscriptFiles = await File.query().where({ + manuscriptId: this.id, }) const manuscriptDecision = manuscriptReviews.find( @@ -147,7 +135,7 @@ class Manuscript extends BaseModel { // Copy Teams to the new Version await Promise.all( teams.map(async team => { - team.objectId = newManuscript.id + team.manuscriptId = newManuscript.id team.members = team.members.map(member => omit(member, 'id')) await new Team(omit(team, ['id'])).saveGraph() }), @@ -158,7 +146,7 @@ class Manuscript extends BaseModel { await Promise.all( manuscriptFiles.map(async file => { const newFile = omit(file, ['id']) - newFile.objectId = newManuscript.id + newFile.manuscriptId = newManuscript.id await new File(newFile).save() return newFile }), @@ -168,7 +156,7 @@ class Manuscript extends BaseModel { } static get relationMappings() { - const { Channel, User, Team, Review } = require('@pubsweet/models') + const { Channel, User, Team, Review, File } = require('@pubsweet/models') return { submitter: { @@ -190,13 +178,17 @@ class Manuscript extends BaseModel { teams: { relation: BaseModel.HasManyRelation, modelClass: Team, - beforeInsert(model) { - model.objectType = 'Manuscript' + join: { + from: 'manuscripts.id', + to: 'teams.manuscriptId', }, - filter: { objectType: 'Manuscript' }, + }, + files: { + relation: BaseModel.HasManyRelation, + modelClass: File, join: { from: 'manuscripts.id', - to: 'teams.objectId', + to: 'files.manuscriptId', }, }, reviews: { @@ -300,35 +292,6 @@ class Manuscript extends BaseModel { }, } } - - // TODO: Do this on the DB level with cascading deletes - async $beforeDelete() { - // const Review = require('../../review/src/review') - const { Review, Team, File } = require('@pubsweet/models') - - const files = await File.findByObject({ - object_id: this.id, - object: 'Manuscript', - }) - if (files.length > 0) { - files.forEach(async fl => { - await new File(fl).delete() - }) - } - - const review = await Review.findByField('manuscript_id', this.id) - if (review.length > 0) { - review.forEach(async rv => { - await new Review(rv).delete() - }) - } - - this.teams = await this.getTeams() - - this.teams.forEach(async team => { - await new Team(team).delete() - }) - } } Manuscript.type = 'Manuscript' diff --git a/server/model-review/src/index.js b/server/model-review/src/index.js index 3d9d6f4c8bec12c8e7c9fb45ac05a217c7c5f517..92e1efbc087a696c0c6d9eb3cd9fe23701e00ff7 100644 --- a/server/model-review/src/index.js +++ b/server/model-review/src/index.js @@ -1,10 +1,11 @@ const resolvers = require('./resolvers') const typeDefs = require('./typeDefs') -const model = require('./review') module.exports = { - model, - modelName: 'Review', resolvers, typeDefs, + models: [ + { modelName: 'Review', model: require('./review') }, + { modelName: 'ReviewComment', model: require('./review_comment') }, + ], } diff --git a/server/model-review/src/migrations/1537450834-review.sql b/server/model-review/src/migrations/1596830547-review.sql similarity index 79% rename from server/model-review/src/migrations/1537450834-review.sql rename to server/model-review/src/migrations/1596830547-review.sql index d679395061b63365a604beb417e7560e1194c52a..56abf5f5a6cf2b904cb12bc6cd92c04be0813f1a 100644 --- a/server/model-review/src/migrations/1537450834-review.sql +++ b/server/model-review/src/migrations/1596830547-review.sql @@ -4,8 +4,7 @@ CREATE TABLE reviews ( updated TIMESTAMP WITH TIME ZONE, recommendation TEXT, is_decision BOOLEAN DEFAULT FALSE, - comments JSONB, user_id UUID, - manuscript_id UUID, + manuscript_id UUID REFERENCES manuscripts(id) ON DELETE CASCADE, type TEXT NOT NULL ); \ No newline at end of file diff --git a/server/model-review/src/migrations/1596830548-add-review-comments.sql b/server/model-review/src/migrations/1596830548-add-review-comments.sql new file mode 100644 index 0000000000000000000000000000000000000000..7a7843c91eec2b04d7162506049afa87c7874034 --- /dev/null +++ b/server/model-review/src/migrations/1596830548-add-review-comments.sql @@ -0,0 +1,12 @@ +CREATE TABLE review_comments ( + id UUID PRIMARY KEY, + created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, + updated TIMESTAMP WITH TIME ZONE, + -- If a review is deleted for some reason, we want its comments to go away too + review_id UUID REFERENCES reviews(id) ON DELETE CASCADE, + -- If a user is deleted, it's likely we want to keep the comments they have made + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + content TEXT, + comment_type TEXT, + type TEXT +); \ No newline at end of file diff --git a/server/model-review/src/resolvers.js b/server/model-review/src/resolvers.js index 9a8fc508e4d9f8d9e78e90e6e26bc7e8a9d8882a..566b16eb3abcee690d095bdb239c07bb5bcceaa0 100644 --- a/server/model-review/src/resolvers.js +++ b/server/model-review/src/resolvers.js @@ -1,25 +1,33 @@ -const merge = require('lodash/merge') -const Review = require('./review') +// const merge = require('lodash/merge') +// const Review = require('./review') const resolvers = { Mutation: { async updateReview(_, { id, input }, ctx) { - if (id) { - const review = await ctx.models.Review.query().findById(id) - const update = merge({}, review, input) - // Load Review - const rvw = await ctx.models.Review.query().updateAndFetchById( - id, - update, - ) - rvw.comments = await rvw.getComments() + // We process comment fields into array + input.user = ctx.user + const processedReview = Object.assign({}, input) + processedReview.comments = [ + input.reviewComment, + input.confidentialComment, + input.decisionComment, + ].filter(Boolean) + + delete processedReview.reviewComment + delete processedReview.confidentialComment + delete processedReview.decisionComment - return rvw - } - input.userId = ctx.user.id - const review = await new Review(input) - await review.save() - review.comments = await review.getComments() + const review = await ctx.models.Review.query().upsertGraphAndFetch( + { + id, + ...processedReview, + }, + { + relate: true, + noUnrelate: true, + noDelete: true, + }, + ) return review }, @@ -43,6 +51,13 @@ const resolvers = { return member.save() }, }, + ReviewComment: { + async files(parent, _, ctx) { + return parent.files + ? parent.files + : ctx.models.File.query().where({ reviewCommentId: parent.id }) + }, + }, } module.exports = resolvers diff --git a/server/model-review/src/review.js b/server/model-review/src/review.js index bc07009f5ad9c90e1c7a4491216188be8714a93f..5de35471ada48191e7caba5b4151844b532b8136 100644 --- a/server/model-review/src/review.js +++ b/server/model-review/src/review.js @@ -10,30 +10,33 @@ class Review extends BaseModel { this.type = 'Review' } - async user() { - const { User } = require('@pubsweet/models') - return User.find(this.userId) - } + // async user() { + // const { User } = require('@pubsweet/models') + // return User.find(this.userId) + // } - async getComments() { - const File = require('../../model-file/src/file') + // async getComments() { + // const File = require('../../model-file/src/file') - await Promise.all( - (this.comments || []).map(async comment => { - const files = await File.findByObject({ - object: 'Review', - object_id: this.id, - }) - const commentFile = files.find(file => file.fileType === comment.type) - if (commentFile) { - comment.files = [commentFile] - } - return comment - }), - ) + // await Promise.all( + // (this.comments || []).map(async comment => { + // const files = await File.query().where({ + // objectType: 'Review', + // objectId: this.id, + // }) + // const commentFile = files.find(file => file.fileType === comment.type) + // if (commentFile) { + // comment.files = [commentFile] + // } + // return comment + // }), + // ) - this.user = this.user() - return this.comments + // this.user = this.user() + // return this.comments + // } + static get relatedFindQueryMutates() { + return false } static get schema() { @@ -44,15 +47,12 @@ class Review extends BaseModel { userId: { type: 'string', format: 'uuid' }, user: { type: ['object', 'null'] }, isDecision: { type: ['boolean', 'false'] }, - comments: { - type: ['array', 'null'], - }, }, } } static get relationMappings() { - const { Manuscript, User } = require('@pubsweet/models') + const { Manuscript, User, ReviewComment } = require('@pubsweet/models') return { manuscript: { @@ -71,21 +71,46 @@ class Review extends BaseModel { to: 'users.id', }, }, + comments: { + relation: BaseModel.HasManyRelation, + modelClass: ReviewComment, + join: { + from: 'review_comments.reviewId', + to: 'reviews.id', + }, + }, } } - async $beforeDelete() { - const File = require('../../model-file/src/file') - const files = await File.findByObject({ - object_id: this.id, - object: 'Review', - }) - if (files.length > 0) { - files.forEach(async fl => { - await new File(fl).delete() - }) + async $afterGet() { + if (this.isDecision) { + this.decisionComment = await this.$relatedQuery('comments') + .where('commentType', 'decision') + .first() + } else { + this.reviewComment = await this.$relatedQuery('comments') + .where('commentType', 'review') + .first() + + this.confidentialComment = await this.$relatedQuery('comments') + .where('commentType', 'confidential') + .first() } + return true } + + // async $beforeDelete() { + // const File = require('../../model-file/src/file') + // const files = await File.query().where({ + // objectId: this.id, + // objectType: 'Review', + // }) + // if (files.length > 0) { + // files.forEach(async fl => { + // await new File(fl).delete() + // }) + // } + // } } Review.type = 'Review' diff --git a/server/model-review/src/review_comment.js b/server/model-review/src/review_comment.js new file mode 100644 index 0000000000000000000000000000000000000000..6ba36c8a7eb44cc5c22298a3ababeff8b0dc594f --- /dev/null +++ b/server/model-review/src/review_comment.js @@ -0,0 +1,57 @@ +const BaseModel = require('@pubsweet/base-model') + +class ReviewComment extends BaseModel { + static get tableName() { + return 'review_comments' + } + + constructor(properties) { + super(properties) + this.type = 'ReviewComment' + } + + static get schema() { + return { + properties: { + content: { type: ['string', 'null'] }, + userId: { type: 'string', format: 'uuid' }, + reviewId: { type: 'string', format: 'uuid' }, + commentType: { type: ['string', 'null'] }, + }, + } + } + + static get relationMappings() { + const { File, Review, User } = require('@pubsweet/models') + + return { + review: { + relation: BaseModel.BelongsToOneRelation, + modelClass: Review, + join: { + from: 'review_comments.reviewId', + to: 'reviews.id', + }, + }, + user: { + relation: BaseModel.BelongsToOneRelation, + modelClass: User, + join: { + from: 'reviews_comments.userId', + to: 'users.id', + }, + }, + files: { + relation: BaseModel.HasManyRelation, + modelClass: File, + join: { + from: 'review_comments.id', + to: 'files.review_comment_id', + }, + }, + } + } +} + +ReviewComment.type = 'Review' +module.exports = ReviewComment diff --git a/server/model-review/src/typeDefs.js b/server/model-review/src/typeDefs.js index fb39b5e3903bb16633a2860330a201fa9a683165..43b7dc62d4336c86761581bfad24dc4739061f1f 100644 --- a/server/model-review/src/typeDefs.js +++ b/server/model-review/src/typeDefs.js @@ -8,29 +8,37 @@ const typeDefs = ` id: ID! created: DateTime! updated: DateTime - comments: [Comment] recommendation: String isDecision: Boolean open: Boolean user: User + reviewComment: ReviewComment + confidentialComment: ReviewComment + decisionComment: ReviewComment } input ReviewInput { - comments: [CommentInput] + reviewComment: ReviewCommentInput + confidentialComment: ReviewCommentInput + decisionComment: ReviewCommentInput recommendation: String isDecision: Boolean manuscriptId: ID! } - input CommentInput { - type: String + type ReviewComment implements Object { + id: ID! + created: DateTime! + updated: DateTime + commentType: String content: String + files: [File] } - type Comment { - type: String + input ReviewCommentInput { + id: ID + commentType: String content: String - files: [File] } ` diff --git a/server/model-team/src/graphql.js b/server/model-team/src/graphql.js index 2e6cac60789d90544225f6e6672349d32f6e49cf..9ea0cf9fcf0989d897e43e92749dbc563db1d9f2 100644 --- a/server/model-team/src/graphql.js +++ b/server/model-team/src/graphql.js @@ -62,9 +62,8 @@ const resolvers = { const t = await ctx.models.Team.query().findById(team.id) return t.$relatedQuery('members') }, - object(team, vars, ctx) { - const { objectId, objectType } = team - return objectId && objectType ? { objectId, objectType } : null + manuscript(parent, vars, ctx) { + return ctx.models.Manuscript.query().findById(parent.manuscriptId) }, }, TeamMember: { @@ -100,7 +99,7 @@ const typeDefs = ` type: String! role: String! name: String - object: TeamObject + manuscript: Manuscript members: [TeamMember!] owners: [User] global: Boolean @@ -136,16 +135,10 @@ const typeDefs = ` aff: String } - type TeamObject { - objectId: ID! - objectType: String! - } - input TeamInput { role: String name: String - objectId: ID - objectType: String + manuscriptId: ID members: [TeamMemberInput] global: Boolean } @@ -153,8 +146,7 @@ const typeDefs = ` input TeamWhereInput { role: String name: String - objectId: ID - objectType: String + manuscriptId: ID members: [TeamMemberInput] global: Boolean users: [ID!] diff --git a/server/model-team/src/migrations/1542801241-initial-team-migration.sql b/server/model-team/src/migrations/1542801241-initial-team-migration.sql deleted file mode 100644 index 0efd6b9fce08a1b77f9ed2bffbdd9fb8a70a5992..0000000000000000000000000000000000000000 --- a/server/model-team/src/migrations/1542801241-initial-team-migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE teams ( - id UUID PRIMARY KEY, - created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, - updated TIMESTAMP WITH TIME ZONE, - object JSONB, - name TEXT, - role TEXT NOT NULL, - members JSONB, - owners JSONB, - global BOOLEAN, - type TEXT NOT NULL -); \ No newline at end of file diff --git a/server/model-team/src/migrations/1547596236-initial-team-member-migration.js b/server/model-team/src/migrations/1547596236-initial-team-member-migration.js deleted file mode 100644 index 143299d1798836425f1ed6c3c171ecb29833ccf2..0000000000000000000000000000000000000000 --- a/server/model-team/src/migrations/1547596236-initial-team-member-migration.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.up = knex => - knex.schema.createTable('team_members', table => { - table.uuid('id').primary() - table.timestamp('created').defaultTo(knex.fn.now()) - table.timestamp('updated').defaultTo(knex.fn.now()) - table.string('status') - table - .uuid('team_id') - .references('id') - .inTable('teams') - .onDelete('CASCADE') - .onUpdate('CASCADE') - table - .uuid('user_id') - .references('id') - .inTable('users') - .onDelete('CASCADE') - .onUpdate('CASCADE') - - table.index(['team_id', 'user_id']) - }) diff --git a/server/model-team/src/migrations/1548205275-move-members.js b/server/model-team/src/migrations/1548205275-move-members.js deleted file mode 100644 index fa8763a58d9012ff67abfd8b83eb9e26f7deabf3..0000000000000000000000000000000000000000 --- a/server/model-team/src/migrations/1548205275-move-members.js +++ /dev/null @@ -1,20 +0,0 @@ -exports.up = async knex => { - const { Team, TeamMember } = require('@pubsweet/models') - const teams = await Team.query() - - const saves = [] - - teams.forEach(team => { - if (team.members) { - team.members.forEach(member => { - saves.push(new TeamMember({ userId: member, teamId: team.id }).save()) - }) - } - }) - - await Promise.all(saves) - - return knex.schema.table('teams', table => { - table.dropColumn('members') - }) -} diff --git a/server/model-team/src/migrations/1548205276-simplify-object.js b/server/model-team/src/migrations/1548205276-simplify-object.js deleted file mode 100644 index f04443c6a26bf553ff9aa5bc01ed950ae89a2386..0000000000000000000000000000000000000000 --- a/server/model-team/src/migrations/1548205276-simplify-object.js +++ /dev/null @@ -1,27 +0,0 @@ -exports.up = async knex => { - const { Team } = require('@pubsweet/models') - const teams = await Team.query() - - const saves = [] - - await knex.schema.table('teams', table => { - table.uuid('object_id') - table.string('object_type') - table.index(['object_id', 'object_type']) - }) - - teams.forEach(team => { - if (team.object && team.object.objectId && team.object.objectType) { - team.objectId = team.object.objectId - team.objectType = team.object.objectType - delete team.object - saves.push(team.save()) - } - }) - - await Promise.all(saves) - - return knex.schema.table('teams', table => { - table.dropColumn('object') - }) -} diff --git a/server/model-team/src/migrations/1548328420-add-alias-migration.js b/server/model-team/src/migrations/1548328420-add-alias-migration.js deleted file mode 100644 index fdb4033401c1398bf9716f1f361972eb2b8663c0..0000000000000000000000000000000000000000 --- a/server/model-team/src/migrations/1548328420-add-alias-migration.js +++ /dev/null @@ -1,17 +0,0 @@ -exports.up = async knex => { - await knex.schema.createTable('aliases', table => { - table.uuid('id').primary() - table.timestamp('created').defaultTo(knex.fn.now()) - table.timestamp('updated').defaultTo(knex.fn.now()) - table.string('name') - table.string('email') - table.string('aff') - }) - - await knex.schema.table('team_members', table => { - table - .uuid('alias_id') - .references('id') - .inTable('aliases') - }) -} diff --git a/server/model-team/src/migrations/1596830548-initial-team-migration.sql b/server/model-team/src/migrations/1596830548-initial-team-migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..c9985aef53957d6be5cbe08da79981325289c2cf --- /dev/null +++ b/server/model-team/src/migrations/1596830548-initial-team-migration.sql @@ -0,0 +1,36 @@ +CREATE TABLE teams ( + id UUID PRIMARY KEY, + created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp, + updated TIMESTAMP WITH TIME ZONE, + + name TEXT, + role TEXT NOT NULL, + members JSONB, + owners JSONB, + global BOOLEAN, + type TEXT NOT NULL, + manuscript_id UUID REFERENCES manuscripts(id) ON DELETE CASCADE +); + +CREATE INDEX ON teams (manuscript_id); + +CREATE TABLE aliases ( + id uuid NOT NULL PRIMARY KEY, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + name TEXT, + email TEXT, + aff TEXT +); + +CREATE TABLE team_members ( + id uuid NOT NULL PRIMARY KEY, + created timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + updated timestamp with time zone DEFAULT CURRENT_TIMESTAMP, + status character varying(255), + team_id uuid REFERENCES teams(id) ON UPDATE CASCADE ON DELETE CASCADE, + user_id uuid REFERENCES users(id) ON DELETE CASCADE, + alias_id uuid REFERENCES aliases(id) +); + +CREATE INDEX ON team_members (team_id, user_id); \ No newline at end of file diff --git a/server/model-team/src/team.js b/server/model-team/src/team.js index 1653eb844c1e40260f6ad07db73106700baa3342..dde11acd8c0d663eb4ef42b2ad5d7a5395e61870 100644 --- a/server/model-team/src/team.js +++ b/server/model-team/src/team.js @@ -12,7 +12,7 @@ class Team extends BaseModel { } static get relationMappings() { - const { Alias, TeamMember, User } = require('@pubsweet/models') + const { Alias, TeamMember, User, Manuscript } = require('@pubsweet/models') return { members: { @@ -49,14 +49,21 @@ class Team extends BaseModel { to: 'aliases.id', }, }, + manuscript: { + relation: BaseModel.BelongsToOneRelation, + modelClass: Manuscript, + join: { + from: 'manuscripts.id', + to: 'teams.manuscript_id', + }, + }, } } static get schema() { return { properties: { - objectId: { type: ['string', 'null'], format: 'uuid' }, - objectType: { type: ['string', 'null'] }, + manuscriptId: { type: ['string', 'null'], format: 'uuid' }, name: { type: 'string' }, role: { type: ['string'] }, owners: { diff --git a/server/model-user/src/user.js b/server/model-user/src/user.js index fd8b6986db9db2826cfd01a66419c5f3f4686e72..02ac1503282761000857809eb9ed7ebc16128c50 100644 --- a/server/model-user/src/user.js +++ b/server/model-user/src/user.js @@ -79,22 +79,17 @@ class User extends BaseModel { } } - // // eslint-disable-next-line class-methods-use-this - // setOwners() { - // // FIXME: this is overriden to be a no-op, because setOwners() is called by - // // the API on create for all entity types and setting `owners` on a User is - // // not allowed. This should instead be solved by having separate code paths - // // in the API for different entity types. - // } - // This gives a view of the teams and team member structure to reflect // the current roles the user is performing. E.g. if they are a member // of a reviewer team and have the status of 'accepted', they will // have a 'accepted:reviewer' role present in the returned object - async currentRoles(object) { + async currentRoles(manuscript) { let teams - if (object && object.id) { - teams = await this.$relatedQuery('teams').where('objectId', object.id) + if (manuscript && manuscript.id) { + teams = await this.$relatedQuery('teams').where( + 'manuscriptId', + manuscript.id, + ) } else { teams = await this.$relatedQuery('teams') } @@ -104,10 +99,10 @@ class User extends BaseModel { const role = `${t.status ? `${t.status}:` : ''}${t.role}` // If there's an existing role for this object, add to the list - if (t.objectId && Array.isArray(roles[t.objectId])) { - roles[t.objectId].push(role) - } else if (t.objectId) { - roles[t.objectId] = [role] + if (t.manuscriptId && Array.isArray(roles[t.manuscriptId])) { + roles[t.manuscriptId].push(role) + } else if (t.manuscriptId) { + roles[t.manuscriptId] = [role] } }) return Object.keys(roles).map(id => ({ id, roles: roles[id] }))