diff --git a/app/components/submission-wizard/SubmitPage.jsx b/app/components/submission-wizard/SubmitPage.jsx index 51951b490fb37bbca0056e05626fc0a460e592e4..a2a80dc0c316f10d88da064780d97281eea9612b 100755 --- a/app/components/submission-wizard/SubmitPage.jsx +++ b/app/components/submission-wizard/SubmitPage.jsx @@ -22,7 +22,7 @@ import { SectionHeader as Header, } from '../ui' import { UserContext } from '../App' -import { GET_MANUSCRIPT } from './operations' +import { GET_MANUSCRIPT, CHECK_DUPES } from './operations' import UploadFiles, { SubmissionTypes } from '../upload-files' import PubMedSearch from '../citation-search' import { FileThumbnails } from '../preview-files' @@ -94,7 +94,7 @@ class Submit extends React.Component { `${name.title ? `${name.title} ` : ''}${name.givenNames} ${name.surname}` render() { const currentUser = this.context - const { manuscript } = this.props + const { manuscript, duplicates } = this.props const { id: mId, meta, @@ -159,14 +159,26 @@ class Submit extends React.Component { </div> ), error: - // TODO: Add test for duplicate articles! - currentUser.admin && status === 'submitted' && unmatchedJournal ? ( - <ErrorMessage> - <Icon color="currentColor" size={2}> - alert_circle - </Icon> - Journal is not in the NLM Catalog. - </ErrorMessage> + (currentUser.admin && status === 'submitted' && unmatchedJournal) || + duplicates ? ( + <React.Fragment> + {unmatchedJournal && ( + <ErrorMessage> + <Icon color="currentColor" size={2}> + alert_circle + </Icon> + Journal is not in the NLM Catalog. + </ErrorMessage> + )} + {duplicates && ( + <ErrorMessage> + <Icon color="currentColor" size={2}> + alert_circle + </Icon> + Submission is likely a duplicate. + </ErrorMessage> + )} + </React.Fragment> ) : null, } const manuscriptFiles = { @@ -405,7 +417,36 @@ class Submit extends React.Component { const SubmitWithMutations = ManuscriptMutations(Submit) const SubmitWithHeader = SubmissionHeader(SubmitWithMutations) -const SubmitPage = ({ match, ...props }) => ( +const DupeCheckSubmitPage = ({ manuscript, ...props }) => { + const { id, meta } = manuscript + const pmid = meta.articleIds + ? meta.articleIds.find(id => id.pubIdType === 'pmid').id + : null + return ( + <Query query={CHECK_DUPES} variables={{ id, pmid, title: meta.title }}> + {({ data, loading }) => { + if (loading) { + return ( + <Loading> + <LoadingIcon /> + </Loading> + ) + } + const duplicates = + data.checkDuplicates.length > 0 && data.checkDuplicates + return ( + <SubmitWithHeader + duplicates={duplicates} + manuscript={manuscript} + {...props} + /> + ) + }} + </Query> + ) +} + +const SubmitPage = ({ match, currentUser, ...props }) => ( <Query fetchPolicy="cache-and-network" query={GET_MANUSCRIPT} @@ -419,7 +460,22 @@ const SubmitPage = ({ match, ...props }) => ( </Loading> ) } - return <SubmitWithHeader manuscript={data.manuscript} {...props} /> + if (currentUser.admin) { + return ( + <DupeCheckSubmitPage + currentUser={currentUser} + manuscript={data.manuscript} + {...props} + /> + ) + } + return ( + <SubmitWithHeader + currentUser={currentUser} + manuscript={data.manuscript} + {...props} + /> + ) }} </Query> ) diff --git a/app/components/submission-wizard/operations.js b/app/components/submission-wizard/operations.js index d985d8ee1cf386199035c16e4d628e667e129579..d2ff78fba269e5a8ef75e5e43f65020b7fdd4765 100644 --- a/app/components/submission-wizard/operations.js +++ b/app/components/submission-wizard/operations.js @@ -93,6 +93,15 @@ export const GET_MANUSCRIPT = gql` ${ManuscriptFragment} ` +export const CHECK_DUPES = gql` + query($id: ID!, $pmid: String, $title: String!) { + checkDuplicates(id: $id, pmid: $pmid, title: $title) { + ...ManuscriptFragment + } + } + ${ManuscriptFragment} +` + export const CREATE_MANUSCRIPT = gql` mutation CreateManuscript { createManuscript { diff --git a/server/xpub-model/entities/manuscript/data-access.js b/server/xpub-model/entities/manuscript/data-access.js index ec7ee36ea905c3fb3f1c3bd2f8efcfbe5c1e84ee..8255672963f8af510d8faf9fcdeffac7f18d100e 100644 --- a/server/xpub-model/entities/manuscript/data-access.js +++ b/server/xpub-model/entities/manuscript/data-access.js @@ -241,13 +241,6 @@ class Manuscript extends EpmcBaseModel { return manuscripts && manuscripts.length > 0 ? manuscripts[0] : null } - /* static async selectByIdAndUser(id, user) { - const manuscripts = await Manuscript.query() - .where('id', id) - .andWhere('updated_by', user) - return manuscripts[0] - } */ - static async selectByStatus(statuses, page = 0, pageSize = PAGE_SIZE, user) { const manuscripts = page === -1 @@ -337,12 +330,10 @@ class Manuscript extends EpmcBaseModel { ? await Manuscript.query() .whereJsonSupersetOf('meta,article_ids', [{ id }]) .whereNull('deleted') - .first() : await Manuscript.query() .whereJsonSupersetOf('meta,article_ids', [{ id }]) .whereIn('id', manuscriptIds) .whereNull('deleted') - .first() return manuscript } diff --git a/server/xpub-model/entities/manuscript/index.js b/server/xpub-model/entities/manuscript/index.js index 65120aba4ed26eca8baabe510a0a56aa56f1f851..d6f76cd1e2138eab405ad7afb4ab3213908efb30 100755 --- a/server/xpub-model/entities/manuscript/index.js +++ b/server/xpub-model/entities/manuscript/index.js @@ -59,7 +59,8 @@ const Manuscript = { if (id.toUpperCase().startsWith('EMS')) { manuscript = await ManuscriptAccess.selectById(id) } else { - manuscript = await ManuscriptAccess.searchArticleIds(id, userId) + const manuscripts = await ManuscriptAccess.searchArticleIds(id, userId) + manuscript = manuscripts.pop() } return { manuscript, @@ -68,6 +69,35 @@ const Manuscript = { : [{ message: `No manuscript found with ID: ${id}` }], } }, + checkDuplicates: async (id, pmid, title, user) => { + let manuscripts = [] + if (pmid) { + const idMatches = await ManuscriptAccess.searchArticleIds(pmid, user) + manuscripts = manuscripts.concat( + idMatches.reduce((other, each) => { + if (each.id !== id) { + other.push(each) + } + return other + }, []), + ) + } + const titleMatches = await ManuscriptAccess.searchByTitleOrLastname( + title, + 0, + 10, + user, + ) + manuscripts = manuscripts.concat( + titleMatches.results.reduce((other, each) => { + if (each.id !== id && !manuscripts.some(m => m.id === each.id)) { + other.push(each) + } + return other + }, []), + ) + return manuscripts + }, countByStatus: async () => { const { states } = config const counts = await states.map(async type => { diff --git a/server/xpub-server/entities/manuscript/resolvers.js b/server/xpub-server/entities/manuscript/resolvers.js index 1e21401e0fb23abb91b98cbaa1e82b897b7052d4..c030308442ceccae60f32a401e5102bef353ec83 100644 --- a/server/xpub-server/entities/manuscript/resolvers.js +++ b/server/xpub-server/entities/manuscript/resolvers.js @@ -19,6 +19,12 @@ const resolvers = { return ManuscriptManager.all(user) }, + async checkDuplicates(_, { id, pmid, title }, { user }) { + if (!user) { + throw new Error('You are not authenticated!') + } + return ManuscriptManager.checkDuplicates(id, pmid, title, user) + }, async countByStatus(_, vars, { user }) { if (!user) { throw new Error('You are not authenticated!') diff --git a/server/xpub-server/entities/manuscript/typeDefs.graphqls b/server/xpub-server/entities/manuscript/typeDefs.graphqls index bcf749c7f3b7c01c47244ba7e5fc8406634614df..7a3a9302b25a3868a66121fc46c02ca5b7a1c750 100644 --- a/server/xpub-server/entities/manuscript/typeDefs.graphqls +++ b/server/xpub-server/entities/manuscript/typeDefs.graphqls @@ -23,6 +23,7 @@ extend type Query { manuscripts: [Manuscript]! adminManuscripts: [Manuscript]! countByStatus: [Count]! + checkDuplicates(id: ID!, pmid: String, title: String!): [Manuscript] searchArticleIds(id: String!): ManuscriptResult! findByStatus(query: String!, page: Int, pageSize: Int): ManuscriptSearchResult! searchManuscripts(query: String!, page: Int, pageSize: Int): ManuscriptSearchResult!