diff --git a/app/components/pdf-viewer/Loading.jsx b/app/component-pdf-viewer/client/components/Loading.jsx similarity index 100% rename from app/components/pdf-viewer/Loading.jsx rename to app/component-pdf-viewer/client/components/Loading.jsx diff --git a/app/components/pdf-viewer/PDFViewer.jsx b/app/component-pdf-viewer/client/components/PDFViewer.jsx similarity index 100% rename from app/components/pdf-viewer/PDFViewer.jsx rename to app/component-pdf-viewer/client/components/PDFViewer.jsx diff --git a/app/components/pdf-viewer/Page.jsx b/app/component-pdf-viewer/client/components/Page.jsx similarity index 100% rename from app/components/pdf-viewer/Page.jsx rename to app/component-pdf-viewer/client/components/Page.jsx diff --git a/app/components/pdf-viewer/Viewer.jsx b/app/component-pdf-viewer/client/components/Viewer.jsx similarity index 100% rename from app/components/pdf-viewer/Viewer.jsx rename to app/component-pdf-viewer/client/components/Viewer.jsx diff --git a/app/components/pdf-viewer/index.js b/app/component-pdf-viewer/client/components/index.js similarity index 100% rename from app/components/pdf-viewer/index.js rename to app/component-pdf-viewer/client/components/index.js diff --git a/app/component-pdf-viewer/client/index.js b/app/component-pdf-viewer/client/index.js new file mode 100644 index 0000000000000000000000000000000000000000..3a552650a74d153f0bdb149c201a9f5c6eb6161e --- /dev/null +++ b/app/component-pdf-viewer/client/index.js @@ -0,0 +1 @@ +export { default } from './components' diff --git a/app/component-pdf-viewer/index.js b/app/component-pdf-viewer/index.js new file mode 100644 index 0000000000000000000000000000000000000000..d134c340029a8254d698f16b067d383d735dc580 --- /dev/null +++ b/app/component-pdf-viewer/index.js @@ -0,0 +1 @@ +export { default } from './client' diff --git a/app/component-pdf-viewer/package.json b/app/component-pdf-viewer/package.json new file mode 100755 index 0000000000000000000000000000000000000000..6c658fa911bdb4d3116d0ebbbd343315b7a4118a --- /dev/null +++ b/app/component-pdf-viewer/package.json @@ -0,0 +1,19 @@ +{ + "name": "component-pdf-viewer", + "version": "0.0.1", + "description": "A component for viewing and highlighting PDFs", + "license": "MIT", + "author": "EBI", + "repository": { + "type": "git", + "url": "https://gitlab.coko.foundation/xpub/xpub-epmc", + "path": "/app/component-pdf-viewer" + }, + "dependencies": { + "@pubsweet/ui": "9.0.0", + "@pubsweet/ui-toolkit": "2.0.0", + "styled-components": "^4.1.3", + "pdfjs-dist": "^2.0.489", + "react": "^16.2.0" + } +} diff --git a/app/components/ManuscriptPreview.jsx b/app/components/ManuscriptPreview.jsx index fabd29ef788b13a938810272b86127d3269a937b..0965b15124a4f23f8828d738761ae409f19b7670 100755 --- a/app/components/ManuscriptPreview.jsx +++ b/app/components/ManuscriptPreview.jsx @@ -1,6 +1,6 @@ import React from 'react' import SimpleEditor from 'wax-editor-react' -import PDFViewer from './pdf-viewer' +import PDFViewer from '../component-pdf-viewer' import { A } from './ui' class ManuscriptPreview extends React.Component { diff --git a/app/components/activity/EventDescription.jsx b/app/components/activity/EventDescription.jsx index d65a76e7b7899f69a682782bc1ac21525bd4e379..98181783ad9a1eb2420e9468588353fc1cba1512 100644 --- a/app/components/activity/EventDescription.jsx +++ b/app/components/activity/EventDescription.jsx @@ -86,7 +86,7 @@ const toggleHidden = button => { button.parentNode.nextElementSibling.classList.toggle('hidden') } -const cleanUp = column => column.replace('meta,', '').replace('_', ' ') +const cleanUp = column => column.replace('meta,', '').replace(/_/g, ' ') const isJson = str => { try { JSON.parse(str) diff --git a/app/components/dashboard/DashboardPage.jsx b/app/components/dashboard/DashboardPage.jsx index ee2dcaeef2a075ff82c2fc7b481edd7ce79b93e0..7f711a5784077b3357aa59409eb90a548dafe6c8 100644 --- a/app/components/dashboard/DashboardPage.jsx +++ b/app/components/dashboard/DashboardPage.jsx @@ -2,7 +2,7 @@ import React from 'react' import { Query, compose, graphql } from 'react-apollo' import styled from 'styled-components' import { H4, Link } from '@pubsweet/ui' -import { pageSize } from 'config' +import { pageSize, states } from 'config' import { Loading, LoadingIcon, Notification, Toggle, Pagination } from '../ui' import { ALL_MANUSCRIPTS, @@ -117,15 +117,13 @@ const MyManuscripts = ({ currentUser, errors, history }) => { </Loading> ) } - // get the total number of manuscripts to decide whether the toggles are required const { countByStatus } = data - let totalTount = 0 - countByStatus.forEach(status => { - totalTount += status.count - }) - const togglesRequired = totalTount > pageSize - + const totalCount = countByStatus.reduce( + (sum, status) => sum + parseInt(status.count, 10), + 0, + ) + const togglesRequired = totalCount > pageSize // determine the query and variables used to get manuscripts const query = togglesRequired ? MANUSCRIPTS_BY_STATUS : ALL_MANUSCRIPTS const params = new URLSearchParams(history.location.search) @@ -133,17 +131,17 @@ const MyManuscripts = ({ currentUser, errors, history }) => { const completed = params.get('completed') const variables = {} + const done = states.indexOf('xml-complete') if (togglesRequired) { if (completed) { - variables.query = `xml-complete,ncbi-ready,published` + variables.query = states.slice(done).join(',') variables.page = params.get('page') ? params.get('page') - 1 : 0 variables.pageSize = pageSize } else { - variables.query = `INITIAL,READY,submission-error,in-review,submitted,tagging,xml-qa,xml-triage,xml-review,being-withdrawn` + variables.query = states.slice(0, done).join(',') variables.page = -1 } } - return ( <Query fetchPolicy="cache-and-network" @@ -158,7 +156,6 @@ const MyManuscripts = ({ currentUser, errors, history }) => { </Loading> ) } - const { total, manuscripts } = togglesRequired ? data.findByStatus : data @@ -211,30 +208,41 @@ const MyManuscripts = ({ currentUser, errors, history }) => { } const attention = [] - const review = [] + const warning = [] + const processing = [] const complete = [] - const other = [] + const highlight = [ + 'INITIAL', + 'READY', + 'submission-error', + 'in-review', + 'xml-review', + ] manuscripts.forEach(m => { const reviewer = m.teams.find(t => t.role === 'reviewer') const submitter = m.teams.find(t => t.role === 'submitter') - if ( - reviewer && - reviewer.teamMembers[0].user.id === currentUser.id && - ['in-review', 'xml-review'].includes(m.status) - ) { - review.push(m) - } else if ( - submitter.teamMembers[0].user.id === currentUser.id && - ['INITIAL', 'READY', 'submission-error'].includes(m.status) - ) { - attention.push(m) + if (highlight.includes(m.status)) { + if ( + reviewer && + reviewer.teamMembers[0].user.id === currentUser.id && + highlight.slice(-2).includes(m.status) + ) { + attention.push(m) + } else if ( + submitter.teamMembers[0].user.id === currentUser.id && + highlight.slice(0, 3).includes(m.status) + ) { + attention.push(m) + } else { + warning.push(m) + } } else if ( !togglesRequired && - ['xml-complete', 'ncbi-ready', 'published'].includes(m.status) + states.slice(done).includes(m.status) ) { complete.push(m) } else { - other.push(m) + processing.push(m) } }) return ( @@ -256,25 +264,30 @@ const MyManuscripts = ({ currentUser, errors, history }) => { ))} {attention.length > 0 && ( <React.Fragment> - <H4>Needs attention ({attention.length})</H4> + <H4>Needs your attention ({attention.length})</H4> <DashboardList + currentUser={currentUser} listData={attention} - sectionRole="submitter" /> </React.Fragment> )} - {review.length > 0 && ( + {warning.length > 0 && ( <React.Fragment> - <H4>Waiting for author review ({review.length})</H4> - <DashboardList listData={review} sectionRole="reviewer" /> + <H4> + Waiting for action by another user ({warning.length}) + </H4> + <DashboardList + currentUser={currentUser} + listData={warning} + /> </React.Fragment> )} - {other.length > 0 && ( + {processing.length > 0 && ( <React.Fragment> - <H4>In process at Europe PMC ({other.length})</H4> + <H4>In process at Europe PMC ({processing.length})</H4> <DashboardList currentUser={currentUser} - listData={other} + listData={processing} /> </React.Fragment> )} diff --git a/app/components/dashboard/SearchBoxes.jsx b/app/components/dashboard/SearchBoxes.jsx index d6270137aa706eed0e88c1b353a0b53ffe89ab1f..c9aacc7d4f0d6f9b514e631bcedc0c170c6e832a 100644 --- a/app/components/dashboard/SearchBoxes.jsx +++ b/app/components/dashboard/SearchBoxes.jsx @@ -27,6 +27,9 @@ const SearchArea = styled.div` flex-wrap: wrap; } ` + +let errorTimer + class SearchBoxes extends React.Component { state = { id: SearchBoxes.id ? SearchBoxes.id : '', @@ -34,19 +37,32 @@ class SearchBoxes extends React.Component { errors: [], } componentDidUpdate() { - if (this.state.errors && this.area) { - setTimeout(() => { + const { errors } = this.state + + if (errorTimer) { + clearTimeout(errorTimer) + } + + if (errors && this.area) { + errorTimer = setTimeout(() => { this.setState({ errors: [] }) }, 10000) } } + componentWillUnmount() { + clearTimeout(errorTimer) + } + static id = '' static search = '' setRef = area => { this.area = area } onSearchValChanged = e => { - this.setState({ [e.target.name]: e.target.value }) + this.setState({ + [e.target.name]: e.target.value, + errors: [], + }) SearchBoxes[e.target.name] = e.target.value } onSearchValSubmitted = (where, e) => { diff --git a/app/components/dashboard/index.js b/app/components/dashboard/index.js index e58bc026e03147f594cb483730892c37cb3c46c6..ecaf44c9cc8688184d31b567f4b29311e043b667 100644 --- a/app/components/dashboard/index.js +++ b/app/components/dashboard/index.js @@ -5,7 +5,7 @@ const submitterState = { url: 'create', }, READY: { - status: 'Not yet submitted', + status: 'Incomplete', color: 'error', url: 'submit', }, @@ -15,12 +15,12 @@ const submitterState = { url: 'submit', }, 'in-review': { - status: 'Submitted', - color: 'normal', + status: 'Initial review', + color: 'warning', url: 'submit', }, submitted: { - status: 'Submitted', + status: 'Europe PMC QA', color: 'normal', url: 'submit', }, @@ -35,8 +35,8 @@ const submitterState = { url: 'submit', }, 'xml-review': { - status: 'Processing', - color: 'normal', + status: 'Final proof', + color: 'warning', url: 'submit', }, 'xml-triage': { @@ -45,17 +45,17 @@ const submitterState = { url: 'submit', }, 'xml-complete': { - status: 'Approved for archive', + status: 'Approved for Europe PMC', color: 'success', url: 'submit', }, 'ncbi-ready': { - status: 'Approved for archive', + status: 'Approved for Europe PMC', color: 'success', url: 'submit', }, published: { - status: 'Available in archive', + status: 'Available in Europe PMC', color: 'success', url: 'submit', }, @@ -68,13 +68,13 @@ const submitterState = { const reviewerState = { INITIAL: { - status: 'With submitter', - color: 'normal', + status: 'Incomplete', + color: 'warning', url: 'submit', }, READY: { - status: 'With submitter', - color: 'normal', + status: 'Incomplete', + color: 'warning', url: 'submit', }, 'submission-error': { @@ -83,12 +83,12 @@ const reviewerState = { url: 'submit', }, 'in-review': { - status: 'Needs review', + status: 'Initial review', color: 'error', url: 'submit', }, submitted: { - status: 'Submitted', + status: 'Europe PMC QA', color: 'normal', url: 'submit', }, @@ -103,27 +103,27 @@ const reviewerState = { url: 'submit', }, 'xml-review': { - status: 'Needs final review', + status: 'Final proof', color: 'error', url: 'review', }, 'xml-triage': { status: 'Processing', - color: 'warning', + color: 'normal', url: 'submit', }, 'xml-complete': { - status: 'Approved for archive', + status: 'Approved for Europe PMC', color: 'success', url: 'submit', }, 'ncbi-ready': { - status: 'Approved for archive', + status: 'Approved for Europe PMC', color: 'success', url: 'submit', }, published: { - status: 'Available in archive', + status: 'Available in Europe PMC', color: 'success', url: 'submit', }, @@ -136,12 +136,12 @@ const reviewerState = { const adminState = { INITIAL: { - status: 'Not yet submitted', + status: 'Incomplete', color: 'normal', url: 'create', }, READY: { - status: 'Not yet submitted', + status: 'Incomplete', color: 'normal', url: 'submit', }, @@ -151,7 +151,7 @@ const adminState = { url: 'submit', }, 'in-review': { - status: 'Needs review', + status: 'Initial review', color: 'normal', url: 'submit', }, @@ -171,7 +171,7 @@ const adminState = { url: 'review', }, 'xml-review': { - status: 'Final review', + status: 'Final proof', color: 'normal', url: 'review', }, @@ -186,12 +186,12 @@ const adminState = { url: 'activity', }, 'ncbi-ready': { - status: 'Approved for archive', + status: 'Approved for Europe PMC', color: 'success', url: 'activity', }, published: { - status: 'Available in archive', + status: 'Available in Europe PMC', color: 'success', url: 'activity', }, diff --git a/app/components/preview-files/FileLightbox.jsx b/app/components/preview-files/FileLightbox.jsx index a8534984f8e97476642699b0497adfc60faa5487..5ae58e2a4d804de1123ee24ee1095baf3120a686 100755 --- a/app/components/preview-files/FileLightbox.jsx +++ b/app/components/preview-files/FileLightbox.jsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom' import styled from 'styled-components' import { Action } from '@pubsweet/ui' import { th } from '@pubsweet/ui-toolkit' -import PDFViewer from '../pdf-viewer' +import PDFViewer from '../../component-pdf-viewer' import { A, Page, Center, Cover, Close, CloseButton } from '../ui' import { ImageTypes } from './' diff --git a/app/components/review-wizard/Review.jsx b/app/components/review-wizard/Review.jsx index b1519fa08bd67f67f444b24058fd8f3b5de6dfa3..2ae23316639811392ac85ef436f940879281403b 100755 --- a/app/components/review-wizard/Review.jsx +++ b/app/components/review-wizard/Review.jsx @@ -19,7 +19,7 @@ import UploadFiles, { AllTypes, } from '../upload-files' import ManuscriptPreview from '../ManuscriptPreview' -import PDFViewer from '../pdf-viewer' +import PDFViewer from '../../component-pdf-viewer' import { GET_MANUSCRIPT } from '../operations' import HTMLPreview from './HTMLPreview' import ReviewForm from './ReviewForm' diff --git a/app/components/upload-files/uploadtypes.js b/app/components/upload-files/uploadtypes.js index dfe4ba4dd0188985381b1f86b35fc2ea2bba6196..b572382fcf106a802012808f22723bdc072275dc 100755 --- a/app/components/upload-files/uploadtypes.js +++ b/app/components/upload-files/uploadtypes.js @@ -24,6 +24,8 @@ export const FileTypes = [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/xml', 'application/gzip', + 'application/x-gzip', + 'application/x-gzip-compressed', 'text/xml', 'audio/midi', diff --git a/runShellScript.sh b/runShellScript.sh index c7f0c787d9eb2017d7196ac04f75b83ba10f7f6d..b24bb270ec4d43b6bae61a30ab16e5c21da1c9bc 100755 --- a/runShellScript.sh +++ b/runShellScript.sh @@ -4,11 +4,13 @@ cmd=$1 echo "runShellScript.sh $cmd" -# Start the first process -ps aux | grep "$cmd" | grep -q -v grep -PROCESS_1_STATUS=$? -echo "PROCESS_1_STATUS: $PROCESS_1_STATUS" -if [ $PROCESS_1_STATUS -ne 0 ]; then +# Start the process +PROCESS_RESULT=`ps aux | grep "$cmd" | grep -v "runShellScript.sh" | grep -v grep` + +echo "$PROCESS_RESULT" + +if [ -z "$PROCESS_RESULT" ] +then echo "Executing: $cmd" $cmd status=$? @@ -21,30 +23,3 @@ else echo "Process $cmd already running" exit 1 fi - -# Start the second process -#./my_second_process -D -#status=$? -#if [ $status -ne 0 ]; then -# echo "Failed to start my_second_process: $status" -# exit $status -#fi - -# Naive check runs checks once a minute to see if either of the processes exited. -# This illustrates part of the heavy lifting you need to do if you want to run -# more than one service in a container. The container exits with an error -# if it detects that either of the processes has exited. -# Otherwise it loops forever, waking up every 60 seconds -while sleep 60; do - ps aux |grep "$cmd" |grep -q -v grep - PROCESS_1_STATUS=$? -# ps aux |grep my_second_process |grep -q -v grep -# PROCESS_2_STATUS=$? - # If the greps above find anything, they exit with 0 status - # If they are not both 0, then something is wrong - if [ $PROCESS_1_STATUS -ne 0 ]; then -# if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then - echo "One of the processes has already exited." - exit 1 - fi -done \ No newline at end of file diff --git a/server/email/index.js b/server/email/index.js index b3efbcce803a9a465b3186b56c7df8b2d4707178..81b90763651b0a0122b676660e63b4d0df7118d5 100755 --- a/server/email/index.js +++ b/server/email/index.js @@ -1,5 +1,6 @@ const config = require('config') const Email = require('@pubsweet/component-send-email') +const lodash = require('lodash') const logger = require('@pubsweet/logger') const { htmlEmailBase, @@ -19,6 +20,8 @@ const { const tagger = config.ftp_tagger.email const { sender, url, testAddress, system, dev } = config['epmc-email'] +const parsed = string => lodash.unescape(string) + const sendMail = (to, subject, message, from = null, cc = null, bcc = null) => { const mailData = { from: from || sender, @@ -54,13 +57,13 @@ const taggerErrorEmail = (subject, message) => { } const taggerEmail = (email, manId, title, link) => { - const html = newPackageForTaggingTemplate(manId, title, link) + const html = newPackageForTaggingTemplate(manId, parsed(title), link) const subject = 'New Package Available for Tagging' sendMail(email, subject, html, null, null, system) } const processedTaggerEmail = (email, manId, title, packageName) => { - const html = processedTaggingFilesTemplate(manId, title, packageName) + const html = processedTaggingFilesTemplate(manId, parsed(title), packageName) const subject = 'Tagging files have been uploaded' sendMail(email, subject, html, null, null, system) } @@ -88,15 +91,16 @@ const reviewerEmail = ({ reviewer, manInfo, submitter, token }) => { const submitterName = `${title ? `${title} ` : ''}${givenNames} ${surname}` const { title: t, givenNames: g, surname: s } = reviewer.name const salutation = `${t ? `${t} ` : ''}${g} ${s}` - let link = `${url}submission/${manInfo.id}/submit` + const link = `${url}submission/${manInfo.id}/submit` + const args = [salutation, parsed(manInfo.title), submitterName, link] let html = '' if (token === 'correction') { - html = checkReviewerTemplate(salutation, manInfo.title, submitterName, link) + html = checkReviewerTemplate(...args) } else if (reviewer.id) { - html = setReviewerTemplate(salutation, manInfo.title, submitterName, link) + html = setReviewerTemplate(...args) } else { - link = `${url}dashboard?accept=${token}` - html = newReviewerTemplate(salutation, manInfo.title, submitterName, link) + args[4] = `${url}dashboard?accept=${token}` + html = newReviewerTemplate(...args) } const subject = `Approve submission of ${manInfo.id}` sendMail(reviewer.email, subject, html, null, null, system) @@ -111,7 +115,7 @@ const submitterRejectEmail = ({ reviewer, manInfo, submitter, message }) => { const link = `${url}submission/${manInfo.id}/submit` const html = rejectSubmissionTemplate( salutation, - manInfo.title, + parsed(manInfo.title), reviewerName, message, link, @@ -132,7 +136,7 @@ const removeDuplicateEmail = (user, badInfo, goodInfo) => { const html = removeDupeTemplate( salutation, badInfo.id, - badInfo['meta,title'], + parsed(badInfo['meta,title']), goodInfo.id, pmcid, ) @@ -153,7 +157,7 @@ const finalReviewEmail = (reviewer, manInfo) => { }` const html = finalReviewTemplate( salutation, - manInfo.title, + parsed(manInfo.title), link, releaseDelay, ) diff --git a/server/eutils/api.js b/server/eutils/api.js index e6938086d6c197a905570935bd0f6f2b734c12d1..62ae77d10bbb88cfe6116e3ce1a5a615df521ab6 100755 --- a/server/eutils/api.js +++ b/server/eutils/api.js @@ -8,10 +8,12 @@ try { // console.log("eutils-api-key is not defined") } -// const authBearer = passport.authenticate('bearer', { session: false }) - module.exports = app => { - app.get('/eutils/esearch', (req, res) => { + const authBearer = app.locals.passport.authenticate('bearer', { + session: false, + }) + + app.get('/eutils/esearch', authBearer, (req, res) => { res.set({ 'Content-Type': 'application/json' }) const { term, db, retstart, sort } = req.query @@ -32,7 +34,7 @@ module.exports = app => { } }) }) - app.get('/eutils/efetch', (req, res) => { + app.get('/eutils/efetch', authBearer, (req, res) => { res.set({ 'Content-Type': 'application/xml' }) const { id, db } = req.query @@ -48,7 +50,7 @@ module.exports = app => { res.send(response.text.toString()) }) }) - app.get('/eutils/esummary', (req, res) => { + app.get('/eutils/esummary', authBearer, (req, res) => { res.set({ 'Content-Type': 'application/json' }) const { id, db } = req.query diff --git a/server/xpub-model/entities/team/data-access.js b/server/xpub-model/entities/team/data-access.js index 1dc82d9a0c52d508b9ea7e27424d918bd3bfdeb7..939006c22ce3af09827a815e11e423ad9dc26d57 100755 --- a/server/xpub-model/entities/team/data-access.js +++ b/server/xpub-model/entities/team/data-access.js @@ -16,7 +16,8 @@ class Team extends EpmcBaseModel { // static idColumn = ['article_id', 'member_id']; static get idColumn() { - return ['manuscript_id', 'user_id', 'role_name'] + // return ['manuscript_id', 'user_id', 'role_name'] + return 'id' } /* diff --git a/server/xpub-model/entities/user/index.js b/server/xpub-model/entities/user/index.js index 76ee20ea999042b25eb9b069a281b4068c9becfa..3582b0b4c0bd9c47900912b92ed749702584fa8f 100644 --- a/server/xpub-model/entities/user/index.js +++ b/server/xpub-model/entities/user/index.js @@ -113,7 +113,12 @@ const UserManager = { updatedBy, }) } - await dbUser.save() + await dbUser.save({ + relate: true, + unrelate: false, + insertMissing: true, + noDelete: false, + }) return dbUser }, mergeUser: async (from, to, updatedBy) => {