Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • micropublication/micropublication
  • amardesi/wormbase
  • unteem/wormbase
  • Boroday/wormbase
  • joel-99/micropublication
  • Saimali/micropublication
  • jgutix/micropublication
7 results
Show changes
Commits on Source (8)
Showing
with 473 additions and 167 deletions
......@@ -18,10 +18,6 @@ const GlobalStyle = createGlobalStyle`
* {
box-sizing: border-box;
}
p {
margin: 0;
}
}
`
......
......@@ -5,6 +5,7 @@ import styled from 'styled-components'
import { State } from 'react-powerplug'
import { Action as UIAction } from '@pubsweet/ui'
import {
ArticlePreviewModal,
AuthorSectionItem,
......@@ -128,10 +129,6 @@ const Dashboard = props => {
label: 'Under Revision',
value: 'under revision',
},
{
label: 'Accepted To Proofs',
value: 'accepted to proofs',
},
{
label: 'Declined',
value: 'declined',
......@@ -144,6 +141,10 @@ const Dashboard = props => {
label: 'Published',
value: 'published',
},
{
label: 'Accepted To Proofs',
value: 'accepted to proofs',
},
{
label: 'Revision Submitted',
value: 'revision submitted',
......@@ -174,7 +175,11 @@ const Dashboard = props => {
storedStatuses.map(s => s.value).includes(article.displayStatus),
)
}
return editorArticles
return editorArticles.filter(
article =>
!['published', 'rejected', 'declined'].includes(article.displayStatus),
)
}
return (
......@@ -220,7 +225,13 @@ const Dashboard = props => {
)
setState({ filteredArticles })
} else {
setState({ filteredArticles: editorArticles })
const filteredArticles = editorArticles.filter(
article =>
!['published', 'rejected', 'declined'].includes(
article.displayStatus,
),
)
setState({ filteredArticles })
}
}
......
......@@ -20,9 +20,7 @@ const GlobalStyle = createGlobalStyle`
height: 100%;
}
p {
margin: 0;
}
`
const PageLayout = styled.div`
......
......@@ -559,8 +559,8 @@ const initialValidations = {
yup
.object()
.shape({
doi: yup.string(),
pubmedId: yup.string(), // 1-8 digit number
doi: yup.string().nullable(),
pubmedId: yup.string().nullable(), // 1-8 digit number
reference: yup.string(),
})
.test(
......
const axios = require('axios')
const config = require('config')
const cheerio = require('cheerio')
const { Manuscript, ManuscriptVersion } = require('@pubsweet/models')
const baseUrl = config.get('datacite.url')
const username = config.get('datacite.username')
const password = config.get('datacite.password')
const auth = {
username,
password,
}
const headers = {
'content-type': 'application/vnd.api+json',
}
const makeFetchRequest = async (req, res) => {
await axios({
url: `${baseUrl}/${req.query.doi}`,
method: 'get',
headers,
auth,
})
.then(response => res.send(response.data))
.catch(error => {
const { status, title: message } = error
return res.status(status).send(message)
})
}
const makeNewRequest = async (req, res) => {
const { doi } = req.query
const data = {
data: {
type: 'dois',
attributes: {
doi,
},
},
}
await axios({
url: baseUrl,
method: 'post',
headers,
data,
auth,
})
.then(response => res.send(response.data))
.catch(error => {
const { status, data: errorMessages } = error.response
return res.status(status).send(errorMessages.errors)
})
}
const makeFetchLastRequest = async (req, res) => {
await axios({
url: `${baseUrl}/?client-id=caltech.micropub&page[size]=1&sort=-created`,
method: 'get',
headers,
auth,
}).then(response => res.send(response.data))
}
const makePublishRequest = async (req, res) => {
const { id: manuscriptId } = req.query
const version = await ManuscriptVersion.query()
.where({ manuscriptId })
.orderBy('created', 'desc')
.first()
const manuscript = await Manuscript.query().findById(manuscriptId)
const { title, patternDescription, updated, authors } = version
const { doi } = manuscript
const creators = authors.map(author => {
const { firstName, lastName } = author
const creator = {
givenName: firstName,
familyName: lastName,
}
return creator
})
const updatedDate = new Date(Number(updated))
// Grab the first paragraph for the abstract
const $ = cheerio.load(patternDescription)
const abstract = $('p')
.first()
.text()
// Strip the HTML
const strippedTitle = title.replace(/(<([^>]+)>)/gi, '')
const baseDoi = doi.split('/')[1].replace(/\./g, '-')
const url = `https://www.micropublication.org/journals/biology/${baseDoi}`
const data = {
data: {
attributes: {
event: 'publish',
titles: { title: strippedTitle },
publicationYear: updatedDate.getFullYear(),
descriptions: { description: abstract, descriptionType: 'Abstract' },
creators,
types: { resourceTypeGeneral: 'DataPaper' },
publisher: 'microPublication Biology',
url,
},
},
}
await axios({
url: `${baseUrl}/${doi}`,
method: 'put',
headers,
data,
auth,
})
.then(response => res.send(response.data))
.catch(error => {
const { status, data: errorMessages } = error.response
return res.status(status).send(errorMessages.errors)
})
}
const DataCiteApi = app => {
/**
* GET ENDPOINTS
*/
app.get('/api/datacite/new', async (req, res) => {
await makeNewRequest(req, res)
})
app.get('/api/datacite/fetch', async (req, res) => {
await makeFetchRequest(req, res)
})
app.get('/api/datacite/fetchLast', async (req, res) => {
await makeFetchLastRequest(req, res)
})
app.get('/api/datacite/publish', async (req, res) => {
await makePublishRequest(req, res)
})
}
module.exports = DataCiteApi
/* eslint-disable global-require */
module.exports = {
server: () => app => require('./DataCiteApi')(app),
}
import config from 'config'
const { baseUrl } = config['pubsweet-client']
const apiUrl = `${baseUrl}/api/datacite`
const getDoi = doi => {
const url = `${apiUrl}/fetch?doi=${doi}`
return fetch(url)
}
const createDoi = async values => {
// Retrieve the last DOI and increment
const lastSubmission = await fetch(`${apiUrl}/fetchLast`)
let errorMessage = ''
const result = await lastSubmission.json()
if (result.data.length > 0) {
const doi = result.data[0].id
const newDoi = incrementDoi(doi)
const createResult = await fetch(`${apiUrl}/new?doi=${newDoi}`)
if (createResult.status === 200) {
return newDoi
}
const error = await createResult.text()
errorMessage = error
} else {
errorMessage = 'No DOI returned'
}
throw Error(errorMessage)
}
const publishDoi = async manuscriptId => {
const url = `${apiUrl}/publish?id=${manuscriptId}`
const result = await fetch(url)
if (result.status === 200) {
return result
}
const error = await result.text()
throw Error(error)
}
const incrementDoi = doi => {
const doiSplit = doi.split('.')
const doiNumber = parseInt(doiSplit[3], 10) + 1
const paddedNumber = `${doiNumber}`.padStart(6, '0')
return `${doiSplit[0]}.${doiSplit[1]}.${doiSplit[2]}.${paddedNumber}`
}
export { getDoi, createDoi, publishDoi }
......@@ -31,6 +31,7 @@ import {
transformChatMessages,
saveToStorage,
} from '../_helpers/common'
import { createDoi, publishDoi } from '../../fetch/DataCiteApi'
/* eslint-disable-next-line react/prop-types */
const Label = ({ created, index }) => (
......@@ -216,9 +217,11 @@ const EditorView = props => {
const getSavedChat = () => getFromStorage(`chat_${chatModalThreadId}`)
const saveChat = content =>
saveToStorage(content, `chat_${chatModalThreadId}`)
const finalizeDoi = () => publishDoi(manuscriptId)
if (!editorLoading && editorData) {
const transformed = transform(editorData, {
finalizeDoi,
reinviteReviewerMutation,
sendChatMutation,
setDataTypeMutation,
......@@ -318,6 +321,7 @@ const EditorView = props => {
authorEmail={authorEmail}
authorName={authorName}
categories={categories}
createDoi={createDoi}
curatorId={curatorId}
curatorName={curatorName}
curatorReview={curatorReview}
......@@ -328,6 +332,7 @@ const EditorView = props => {
decisionSubmitted={!!decision}
doi={doi}
editorName={editorName}
finalizeDoi={finalizeDoi}
getSavedDecision={getSavedDecision}
getSavedSOChat={getSavedSOChat}
invitedReviewersCount={invitedReviewersCount}
......
import { css } from 'styled-components'
import { merge } from 'lodash'
import cokoTheme from '@pubsweet/coko-theme'
/* eslint-disable import/extensions */
import 'fontsource-fira-sans-condensed'
import 'fontsource-vollkorn'
/* eslint-enable import/extensions */
import { theme as cokoTheme } from '@coko/client'
import { th } from '@pubsweet/ui-toolkit'
const activeTab = css`
......@@ -44,8 +49,16 @@ const HeadingWeight = css`
`
const edits = {
// fonts
fontInterface: "'Fira Sans Condensed'",
fontHeading: "'Fira Sans Condensed'",
fontReading: "'Vollkorn'",
fontWriting: "'Fira Sans Condensed'",
// diffs
colorAddition: 'palegreen',
colorRemoval: 'lightcoral',
cssOverrides: {
ui: {
Accordion: {
......
......@@ -42,7 +42,6 @@ const contentStyles = css`
}
p {
margin-bottom: 0;
margin-top: 0;
}
`
......
......@@ -18,4 +18,5 @@ module.exports = [
'./app/wbApi',
'./server/export',
'./app/pubMedApi',
'./app/dataCiteApi',
]
module.exports = {
datacite: {
username: 'DATACITE_USERNAME',
password: 'DATACITE_PASSWORD',
url: 'DATACITE_URL',
},
}
......@@ -24,6 +24,9 @@ const logger = new winston.Logger({
})
module.exports = {
datacite: {
url: 'https://api.test.datacite.org/dois',
},
'pubsweet-client': {
baseUrl: deferConfig(
cfg => `http://localhost:${cfg['pubsweet-server'].port}`,
......
module.exports = {
datacite: {
url: 'https://api.test.datacite.org/dois',
},
dbManager: {
admin: true,
email: 'admin@admin.com',
......
......@@ -329,6 +329,7 @@ const updateManuscriptMetadata = async (_, { data, manuscriptId }, ctx) => {
categories,
species,
} = data
await Manuscript.query()
.patch({
dbReferenceId,
......
......@@ -825,7 +825,7 @@ const initialSubmission = async context => {
</p>
<p>
If you have have any further concerns you are welcome to contact us
If you have any further concerns you are welcome to contact us
directly at
<a href="mailto:contact@micropublication.org">
contact@micropublication.org
......
......@@ -65,6 +65,7 @@ const DecisionSection = props => {
getSavedDecision,
decision,
decisionLetter,
finalizeDoi,
saveDecision,
submitDecision,
submitted,
......@@ -84,6 +85,9 @@ const DecisionSection = props => {
decision: values.decision,
decisionLetter: values.decisionLetter,
})
if (values.decision === 'publish') {
finalizeDoi()
}
}
return (
......@@ -163,6 +167,8 @@ DecisionSection.propTypes = {
decision: PropTypes.oneOf(['accept', 'decline', 'reject', 'revise']),
/** Decision letter text content */
decisionLetter: PropTypes.string,
/** Function to publish the DOI metadata at DataCite */
finalizeDoi: PropTypes.func,
/** Fetch saved (but not submitted) decision */
getSavedDecision: PropTypes.func,
/** Save decision without submitting */
......@@ -176,6 +182,7 @@ DecisionSection.propTypes = {
DecisionSection.defaultProps = {
decision: null,
decisionLetter: null,
finalizeDoi: null,
getSavedDecision: null,
saveDecision: null,
submitDecision: null,
......
......@@ -41,6 +41,7 @@ const EditorPanel = props => {
authorEmail,
authorName,
categories,
createDoi,
curatorId,
curatorName,
curatorReview,
......@@ -51,6 +52,7 @@ const EditorPanel = props => {
decisionSubmitted,
doi,
editorName,
finalizeDoi,
getSavedDecision,
getSavedSOChat,
onClickCuratorChat,
......@@ -173,6 +175,7 @@ const EditorPanel = props => {
<DecisionSection
decision={decision}
decisionLetter={decisionLetter}
finalizeDoi={finalizeDoi}
getSavedDecision={getSavedDecision}
saveDecision={saveDecision}
submitDecision={submitDecision}
......@@ -185,8 +188,10 @@ const EditorPanel = props => {
<Accordion label="Metadata" startExpanded={startMetadataExpanded}>
<MetadataSection
categories={categories}
createDoi={createDoi}
dbReferenceId={dbReferenceId}
doi={doi}
finalizeDoi={finalizeDoi}
pmcId={pmcId}
pmId={pmId}
species={species}
......@@ -218,11 +223,15 @@ EditorPanel.propTypes = {
decisionLetter: PropTypes.string,
/** Whether the decision has been sent (as opposed to simply saved) */
decisionSubmitted: PropTypes.bool,
/** Function to publish the DOI metadata at DataCite */
finalizeDoi: PropTypes.func,
/** Reference ID from organism database */
dbReferenceId: PropTypes.string,
/** DOI given to the manuscript */
doi: PropTypes.string,
/** Function to generate new DOI */
createDoi: PropTypes.func,
/** Categories for the manuscript */
categories: PropTypes.arrayOf(PropTypes.string),
/** PubMed ID for the manuscript */
......@@ -242,6 +251,7 @@ EditorPanel.propTypes = {
curatorName: PropTypes.string,
/** Assigned editor's display name */
editorName: PropTypes.string,
/** Assigned section editor's display name */
sectionEditorName: PropTypes.string,
/** Assigned science officer's display name */
......@@ -365,6 +375,7 @@ EditorPanel.defaultProps = {
authorEmail: null,
authorName: null,
categories: null,
createDoi: null,
curatorId: null,
curatorName: null,
curatorReview: null,
......@@ -375,6 +386,7 @@ EditorPanel.defaultProps = {
decisionSubmitted: false,
doi: null,
editorName: null,
finalizeDoi: null,
getSavedDecision: null,
getSavedSOChat: null,
onClickCuratorChat: null,
......
......@@ -9,6 +9,11 @@ import ValueList from './ValueList'
const Wrapper = styled.div``
const DoiWrapper = styled.div`
display: flex;
flex-direction: row;
`
const MetadataValues = styled(ValueList)`
margin-bottom: ${grid(2)};
`
......@@ -33,6 +38,145 @@ const StyledField = styled(TextField)`
width: calc(${th('gridUnit')} * 35);
`
const categoryOptions = [
{
label: 'Phenotype Data',
value: 'phenotype data',
},
{
label: 'Expression Data',
value: 'expression data',
},
{
label: 'Genotype Data',
value: 'genotype data',
},
{
label: 'Methods',
value: 'methods',
},
{
label: 'Software',
value: 'software',
},
{
label: 'Database Updates',
value: 'database updates',
},
{
label: 'Genetic Screens',
value: 'genetic screens',
},
{
label: 'Integrations',
value: 'integrations',
},
{
label: 'Interaction Data',
value: 'interaction data',
},
{
label: 'Models of Human Disease',
value: 'models of human disease',
},
{
label: 'Phylogenetic Data',
value: 'phylogenetic data',
},
{
label: 'Science and Society',
value: 'science and society',
},
]
const speciesOptions = [
{
label: 'Arabidopsis',
value: 'arabidopsis',
},
{ label: 'C. elegans', value: 'c. elegans' },
{
label: 'Drosophila',
value: 'drosophila',
},
{
label: 'S. cerevisiae',
value: 's. cerevisiae',
},
{
label: 'Universal',
value: 'universal',
},
{
label: 'Xenopus',
value: 'xenopus',
},
{
label: 'Zebrafish',
value: 'zebrafish',
},
]
const submissionTypesOptions = [
{
label: 'New Finding',
value: 'new finding',
},
{
label: 'New Methods',
value: 'new methods',
},
{
label: 'Materials and Reagents',
value: 'materials and reagents',
},
{
label: 'Negative Result',
value: 'negative result',
},
{
label: 'Software',
value: 'software',
},
{
label: 'Commodity Validation',
value: 'commodity validation',
},
{
label: 'Corrigendum',
value: 'corrigendum',
},
{
label: 'Data Updates',
value: 'data updates',
},
{
label: 'Erratum',
value: 'erratum',
},
{
label: 'Findings Previously Not Shown',
value: 'findings previously not shown',
},
{
label: 'Replication Successful',
value: 'replication successful',
},
{
label: 'Replication Unsuccessful',
value: 'replication unsuccessful',
},
{
label: 'Retracted',
value: 'retracted',
},
{
label: 'Retraction',
value: 'retraction',
},
]
const validations = yup.object().shape({
dbReferenceId: yup.string(),
doi: yup.string(),
......@@ -46,6 +190,7 @@ const validations = yup.object().shape({
const MetadataSection = props => {
const {
categories,
createDoi,
dbReferenceId,
doi,
pmcId,
......@@ -54,7 +199,9 @@ const MetadataSection = props => {
submissionTypes,
updateMetadata,
} = props
const [showForm, setShowForm] = useState(false)
const [fetchDoi, setFetchDoi] = useState(false)
/**
* Either value list
......@@ -106,145 +253,6 @@ const MetadataSection = props => {
updateMetadata(values).then(() => setShowForm(false))
}
const categoryOptions = [
{
label: 'Phenotype Data',
value: 'phenotype data',
},
{
label: 'Expression Data',
value: 'expression data',
},
{
label: 'Genotype Data',
value: 'genotype data',
},
{
label: 'Methods',
value: 'methods',
},
{
label: 'Software',
value: 'software',
},
{
label: 'Database Updates',
value: 'database updates',
},
{
label: 'Genetic Screens',
value: 'genetic screens',
},
{
label: 'Integrations',
value: 'integrations',
},
{
label: 'Interaction Data',
value: 'interaction data',
},
{
label: 'Models of Human Disease',
value: 'models of human disease',
},
{
label: 'Pylogenetic Data',
value: 'pylogenetic data',
},
{
label: 'Science and Society',
value: 'science and society',
},
]
const speciesOptions = [
{
label: 'Arabidopsis',
value: 'arabidopsis',
},
{ label: 'C. elegans', value: 'c. elegans' },
{
label: 'Drosophila',
value: 'drosophila',
},
{
label: 'S. cerevisiae',
value: 's. cerevisiae',
},
{
label: 'Universal',
value: 'universal',
},
{
label: 'Xenopus',
value: 'xenopus',
},
{
label: 'Zebrafish',
value: 'zebrafish',
},
]
const submissionTypesOptions = [
{
label: 'New Finding',
value: 'new finding',
},
{
label: 'New Methods',
value: 'new methods',
},
{
label: 'Materials and Reagents',
value: 'materials and reagents',
},
{
label: 'Negative Result',
value: 'negative result',
},
{
label: 'Software',
value: 'software',
},
{
label: 'Commodity Validation',
value: 'commodity validation',
},
{
label: 'Corrigendum',
value: 'corrigendum',
},
{
label: 'Data Updates',
value: 'data updates',
},
{
label: 'Erratum',
value: 'erratum',
},
{
label: 'Findings Previously Not Shown',
value: 'findings previously not shown',
},
{
label: 'Replication Successful',
value: 'replication successful',
},
{
label: 'Replication Unsuccessful',
value: 'replication unsuccessful',
},
{
label: 'Retracted',
value: 'retracted',
},
{
label: 'Retraction',
value: 'retraction',
},
]
const initialValues = {
dbReferenceId: dbReferenceId || '',
doi: doi || '',
......@@ -266,7 +274,9 @@ const MetadataSection = props => {
errors,
handleBlur,
handleChange,
setFieldError,
setFieldValue,
setFieldTouched,
touched,
values,
} = formProps
......@@ -302,6 +312,23 @@ const MetadataSection = props => {
const handleSubmissionTypes = newValues =>
handleSelect('submissionTypes', newValues)
const generateDoi = async () => {
setFetchDoi(true)
await createDoi()
.then(newDoi => {
setFieldValue('doi', newDoi)
values.doi = newDoi
updateMetadata(values)
})
.catch(error => {
setFieldError('doi', `Generate DOI Failed: ${error}`)
setFieldTouched('doi', true, false)
})
.finally(() => {
setFetchDoi(false)
})
}
return (
<Wrapper>
<Label>Species</Label>
......@@ -340,15 +367,21 @@ const MetadataSection = props => {
value={currentSubmissionTypesValues}
/>
<TextField
error={errors.doi}
handleBlur={handleBlur}
handleChange={handleChange}
label="DOI"
name="doi"
touched={touched}
value={values.doi}
/>
<DoiWrapper>
<TextField
error={errors.doi}
handleBlur={handleBlur}
handleChange={handleChange}
label="DOI"
name="doi"
touched={touched}
value={values.doi}
/>
<Button loading={fetchDoi} onClick={() => generateDoi()}>
Generate DOI
</Button>
</DoiWrapper>
<FieldWrapper>
<StyledField
error={errors.pmcId}
......@@ -381,6 +414,7 @@ const MetadataSection = props => {
/>
<Button onClick={() => setShowForm(false)}>Cancel</Button>
<Button primary type="submit">
Save
</Button>
......@@ -393,6 +427,7 @@ const MetadataSection = props => {
MetadataSection.propTypes = {
categories: PropTypes.arrayOf(PropTypes.string),
createDoi: PropTypes.func.isRequired,
dbReferenceId: PropTypes.string,
doi: PropTypes.string,
pmcId: PropTypes.string,
......