Skip to content
Snippets Groups Projects
Commit 280f28d8 authored by Alexandru Munteanu's avatar Alexandru Munteanu
Browse files

Merge branch 'develop' of gitlab.coko.foundation:xpub/xpub-faraday into hindawi-theme

parents f1d4378e bcb17433
No related branches found
No related tags found
1 merge request!43Sprint #19
Showing
with 213 additions and 216 deletions
......@@ -7,7 +7,11 @@ export const isHEToManuscript = (state, collectionId) => {
return get(collection, 'handlingEditor.id') === currentUserId
}
const canMakeRecommendationStatuses = ['reviewCompleted', 'heAssigned']
const canMakeRecommendationStatuses = [
'reviewCompleted',
'heAssigned',
'underReview',
]
export const canMakeRecommendation = (state, collection, fragment = {}) => {
if (fragment.id !== last(collection.fragments)) return false
const isHE = isHEToManuscript(state, collection.id)
......
......@@ -45,7 +45,12 @@ class User {
const { UserModel } = this
const users = await UserModel.all()
return users.filter(user => user.editorInChief)
const eics = users.filter(user => user.editorInChief)
if (eics.length === 0) {
throw new Error('No Editor in Chief has been found')
}
return eics
}
async updateUserTeams({ userId, teamId }) {
......
const config = require('config')
const { chain, get } = require('lodash')
const { chain, get, isEmpty } = require('lodash')
const {
User,
......@@ -58,9 +58,13 @@ module.exports = {
comments = eicComments
}
const hasPeerReview = (collection = {}) =>
!isEmpty(collection.handlingEditor)
if (
(isEditorInChief || newRecommendation.recommendationType === 'review') &&
collection.status !== 'rejected'
hasPeerReview(collection)
) {
// the request came from either the Editor in Chief or a reviewer, so the HE needs to be notified
sendHandlingEditorEmail({
......@@ -81,17 +85,19 @@ module.exports = {
newRecommendation.recommendationType !== 'review' &&
newRecommendation.recommendation !== 'return-to-handling-editor'
) {
sendAuthorsEmail({
email,
baseUrl,
titleText,
parsedFragment,
fragmentAuthors,
isEditorInChief,
subjectBaseText,
newRecommendation,
})
if (collection.status !== 'rejected') {
if (isEditorInChief || collection.status === 'revisionRequested') {
sendAuthorsEmail({
email,
baseUrl,
titleText,
parsedFragment,
fragmentAuthors,
isEditorInChief,
subjectBaseText,
newRecommendation,
})
}
if (hasPeerReview(collection)) {
sendReviewersEmail({
email,
baseUrl,
......
......@@ -40,6 +40,7 @@ const SideBarActions = ({
collectionId={project.id}
fragmentId={version.id}
modalKey={`decide-${version.id}`}
status={project.status}
/>
)}
......
## MTS service integration
This component is running as a service to integrate current Hindawi Manuscript Tracking System for Editorial Quality Screening and for Editorial Quality Assurance.
### Use-case
As an Editor in Chief, I want the manuscript to go through Editorial Quality Screening before I assign a Handling Editor to it and start the review process.
### Workflow
Stage 1: When an article is submitted, Faraday needs to convert the submission to XML JATS format, and upload as a .zip file to a FTP server.
Stage 2: When new .zip file has been detected on FTP server, then third party system MTS (Manuscript Tracking System - Hindawi) needs to consume package and populate DB records.
Stage 3: When check is completed, then Faraday system needs to be updated to move status from Technical Checks to Submitted - which allows the Editor in Chief to assign a Handling Editor.
### Configuration
| Params | Required | Description |
| ------------- |:-------------:| -----|
| journalConfig | Yes | Journal configuration in .xml file as: doctype, dtdVersion, journalTitle, articleType, journal email, journalIdPublisher, issn |
| xmlParserOptions | No | parsing config options used by xml-js library |
| s3Config | Yes | Access to AWS S3 Bucket where fragment files are saved |
| FTPConfig | Yes | FTP server connection credentials |
### Usage
MTS service gathers all the fragment files, creates an .xml file in a specific JATS format out of fragment JSON, creates a .zip archive and sends it to a specific FTP server with a configurable package name (also a backup it's uploaded to AWS S3).
.xml structure of Hindawi use-case can be checked `/tests/sample.xml` from generated json `/tests/sample.json`.
#### Example
```javascript
const fragment = {} //fragment json here
const { journalConfig, xmlParser, s3Config, ftpConfig } = config //import your config
const MTS = new MTSService(journalConfig, xmlParser, s3Config, ftpConfig)
MTS.sendPackage({ fragment })
```
[GIFs Demo](https://gitlab.coko.foundation/xpub/xpub-faraday/wikis/mts-integration)
......@@ -24,12 +24,12 @@
"_attributes": {
"journal-id-type": "email"
},
"_text": "trashjo@ariessys.com"
"_text": "faraday@hindawi.com"
}
],
"journal-title-group": {
"journal-title": {
"_text": "Research"
"_text": "Bioinorganic Chemistry and Applications"
}
},
"issn": [
......@@ -37,7 +37,7 @@
"_attributes": {
"pub-type": "ppub"
},
"_text": "0000-000Y"
"_text": "2474-7394"
},
{
"_attributes": {
......@@ -52,60 +52,28 @@
"_attributes": {
"pub-id-type": "publisher-id"
},
"_text": "RESEARCH-D-18-00005"
"_text": "RESEARCH-F-3326913"
},
{
"_attributes": {
"pub-id-type": "manuscript"
},
"_text": "RESEARCH-D-18-00005"
"_text": "RESEARCH-F-3326913"
}
],
"article-categories": {
"subj-group": [
{
"_attributes": {
"subj-group-type": "Article Type"
},
"subject": {
"_text": "Research Article"
}
},
{
"_attributes": {
"subj-group-type": "Category"
},
"subject": {
"_text": "Information science"
}
},
{
"_attributes": {
"subj-group-type": "Classification"
},
"subject": {
"_text": "Applied sciences and engineering"
}
"subj-group": {
"_attributes": {
"subj-group-type": "Article Type"
},
{
"_attributes": {
"subj-group-type": "Classification"
},
"subject": {
"_text": "Scientific community"
}
"subject": {
"_text": "clinical-study"
}
]
}
},
"title-group": {
"article-title": {
"_text": "January 24 sample article with new email trigger in place"
},
"alt-title": {
"_attributes": {
"alt-title-type": "running-head"
},
"_text": "let's hope this works"
"_text": "Demo sprint 16 no fun"
}
},
"contrib-group": {
......@@ -121,17 +89,17 @@
},
"name": {
"surname": {
"_text": "Heckner"
"_text": "Raluca"
},
"given-names": {
"_text": "Hannah"
"_text": "Authorescu"
},
"prefix": {
"_text": "Ms."
"_text": "miss"
}
},
"email": {
"_text": "hheckner@aaas.org"
"_text": "raluca.gramschi+auth@thinslices.com"
},
"xref": {
"_attributes": {
......@@ -144,8 +112,9 @@
"_attributes": {
"id": "aff1"
},
"country": {
"_text": "UNITED STATES"
"country": {},
"addr-line": {
"_text": "Technical University Gheorghe Asachi Iasi"
}
}
},
......@@ -155,10 +124,10 @@
"date-type": "received"
},
"day": {
"_text": "24"
"_text": "3"
},
"month": {
"_text": "01"
"_text": "8"
},
"year": {
"_text": "2018"
......@@ -166,78 +135,58 @@
}
},
"abstract": {
"p": {
"_text": "Abstract\nThis article explains and illustrates the use of LATEX in preparing manuscripts for submission to the American Journal of Physics (AJP). While it is not a comprehensive reference, we hope it will suffice for the needs of most AJP authors."
}
"_text": "<p>some abstract here</p>"
},
"kwd-group": {
"kwd": [
{
"_text": "manuscript"
"funding-group": {}
},
"files": {
"file": [
{
"item_type": {
"_text": "coverLetter"
},
{
"_text": "submissions"
"item_description": {
"_text": "sample cover letter_ms 1.doc"
},
{
"_text": "ftp site"
}
]
},
"funding-group": {},
"counts": {
"fig-count": {
"_attributes": {
"count": "0"
"item_name": {
"_text": "sample cover letter_ms 1.doc"
}
}
},
"custom-meta-group": {
"custom-meta": [
{
"meta-name": {
"_text": "Black and White Image Count"
},
"meta-value": {
"_text": "0"
}
},
{
"item_type": {
"_text": "manuscripts"
},
{
"meta-name": {
"_text": "Color Image Count"
},
"meta-value": {
"_text": "0"
}
"item_description": {
"_text": "manuscript.pdf"
},
"item_name": {
"_text": "manuscript.pdf"
}
]
}
}
},
"body": {
"fig": [
{
"label": {
"_text": "Figure 1"
},
"graphic": {
"_attributes": {
"xlink:href": "GasBulbData.eps",
"xmlns:xlink": "http://www.w3.org/1999/xlink"
{
"item_type": {
"_text": "supplementary"
},
"item_description": {
"_text": "important-emails.md"
},
"item_name": {
"_text": "important-emails.md"
}
}
},
{
"label": {
"_text": "Figure 2"
},
"graphic": {
"_attributes": {
"xlink:href": "ThreeSunsets.jpg",
"xmlns:xlink": "http://www.w3.org/1999/xlink"
{
"item_type": {
"_text": "supplementary"
},
"item_description": {
"_text": "important-emails.md"
},
"item_name": {
"_text": "important-emails (1).md"
}
}
}
]
]
}
}
}
}
\ No newline at end of file
......@@ -4,89 +4,71 @@
<front>
<journal-meta>
<journal-id journal-id-type="publisher">research</journal-id>
<journal-id journal-id-type="email">trashjo@ariessys.com</journal-id>
<journal-id journal-id-type="email">faraday@hindawi.com</journal-id>
<journal-title-group>
<journal-title>Research</journal-title>
<journal-title>Bioinorganic Chemistry and Applications</journal-title>
</journal-title-group>
<issn pub-type="ppub">0000-000Y</issn>
<issn pub-type="ppub">2474-7394</issn>
<issn pub-type="epub"></issn>
</journal-meta>
<article-meta>
<article-id pub-id-type="publisher-id">RESEARCH-D-18-00005</article-id>
<article-id pub-id-type="manuscript">RESEARCH-D-18-00005</article-id>
<article-id pub-id-type="publisher-id">RESEARCH-F-3326913</article-id>
<article-id pub-id-type="manuscript">RESEARCH-F-3326913</article-id>
<article-categories>
<subj-group subj-group-type="Article Type">
<subject>Research Article</subject>
</subj-group>
<subj-group subj-group-type="Category">
<subject>Information science</subject>
</subj-group>
<subj-group subj-group-type="Classification">
<subject>Applied sciences and engineering</subject>
</subj-group>
<subj-group subj-group-type="Classification">
<subject>Scientific community</subject>
<subject>clinical-study</subject>
</subj-group>
</article-categories>
<title-group>
<article-title>January 24 sample article with new email trigger in place</article-title>
<alt-title alt-title-type="running-head">let's hope this works</alt-title>
<article-title>Demo sprint 16 no fun</article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author" corresp="yes">
<role content-type="1" />
<role content-type="1"></role>
<name>
<surname>Heckner</surname>
<given-names>Hannah</given-names>
<prefix>Ms.</prefix>
<surname>Raluca</surname>
<given-names>Authorescu</given-names>
<prefix>miss</prefix>
</name>
<email>hheckner@aaas.org</email>
<xref ref-type="aff" rid="aff1" />
<email>raluca.gramschi+auth@thinslices.com</email>
<xref ref-type="aff" rid="aff1"></xref>
</contrib>
<aff id="aff1">
<country>UNITED STATES</country>
<country></country>
<addr-line>Technical University Gheorghe Asachi Iasi</addr-line>
</aff>
</contrib-group>
<history>
<date date-type="received">
<day>24</day>
<month>01</month>
<day>3</day>
<month>8</month>
<year>2018</year>
</date>
</history>
<abstract>
<p>Abstract
This article explains and illustrates the use of LATEX in preparing manuscripts for submission to the American Journal of Physics (AJP). While it is not a comprehensive reference, we hope it will suffice for the needs of most AJP authors.</p>
</abstract>
<kwd-group>
<kwd>manuscript</kwd>
<kwd>submissions</kwd>
<kwd>ftp site</kwd>
</kwd-group>
<funding-group />
<counts>
<fig-count count="0" />
</counts>
<custom-meta-group>
<custom-meta>
<meta-name>Black and White Image Count</meta-name>
<meta-value>0</meta-value>
</custom-meta>
<custom-meta>
<meta-name>Color Image Count</meta-name>
<meta-value>0</meta-value>
</custom-meta>
</custom-meta-group>
<abstract>&lt;p&gt;some abstract here&lt;/p&gt;</abstract>
<funding-group></funding-group>
</article-meta>
<files>
<file>
<item_type>coverLetter</item_type>
<item_description>sample cover letter_ms 1.doc</item_description>
<item_name>sample cover letter_ms 1.doc</item_name>
</file>
<file>
<item_type>manuscripts</item_type>
<item_description>manuscript.pdf</item_description>
<item_name>manuscript.pdf</item_name>
</file>
<file>
<item_type>supplementary</item_type>
<item_description>important-emails.md</item_description>
<item_name>important-emails.md</item_name>
</file>
<file>
<item_type>supplementary</item_type>
<item_description>important-emails.md</item_description>
<item_name>important-emails (1).md</item_name>
</file>
</files>
</front>
<body>
<fig>
<label>Figure 1</label>
<graphic xlink:href="GasBulbData.eps" xmlns:xlink="http://www.w3.org/1999/xlink" />
</fig>
<fig>
<label>Figure 2</label>
<graphic xlink:href="ThreeSunsets.jpg" xmlns:xlink="http://www.w3.org/1999/xlink" />
</fig>
</body>
</article>
\ No newline at end of file
const getEmailCopy = ({ emailType, titleText }) => {
let paragraph
switch (emailType) {
case 'co-author-added-to-manuscript':
paragraph = `You have been added as co-author to ${titleText}. The manuscript will become visible on your dashboard once it's submitted. Please click on the link below to access your dashboard.`
case 'author-added-to-manuscript':
paragraph = `You have been added as an author to ${titleText}. The manuscript will become visible on your dashboard once it's submitted. Please click on the link below to access your dashboard.`
break
case 'new-author-added-to-manuscript':
paragraph = `You have been added as an author to ${titleText}. In order to gain access to the manuscript, please confirm your account and set your account details by clicking on the link below.`
......
......@@ -9,17 +9,11 @@ const {
services,
Fragment,
} = require('pubsweet-component-helper-service')
const { getEmailCopy } = require('./emailCopy')
module.exports = {
async sendNotifications({
user,
baseUrl,
isSubmitting,
fragment,
UserModel,
collection,
}) {
async sendNotifications({ user, baseUrl, fragment, UserModel, collection }) {
const fragmentHelper = new Fragment({ fragment })
const { title } = await fragmentHelper.getFragmentData({
handlingEditor: collection.handlingEditor,
......@@ -44,21 +38,27 @@ module.exports = {
},
})
if (!isSubmitting) {
sendCoAuthorEmail({ email, baseUrl, user, titleText, subjectBaseText })
if (!user.isConfirmed) {
sendNewAuthorEmail({
email,
user,
baseUrl,
titleText,
subjectBaseText,
})
}
sendNewAuthorEmail({
sendAddedToManuscriptEmail({
email,
user,
baseUrl,
user,
titleText,
subjectBaseText,
})
},
}
const sendCoAuthorEmail = ({
const sendAddedToManuscriptEmail = ({
email,
baseUrl,
user,
......@@ -77,7 +77,7 @@ const sendCoAuthorEmail = ({
const { html, text } = email.getBody({
body: getEmailCopy({
emailType: 'co-author-added-to-manuscript',
emailType: 'author-added-to-manuscript',
titleText,
}),
})
......@@ -85,13 +85,7 @@ const sendCoAuthorEmail = ({
email.sendEmail({ html, text })
}
const sendNewAuthorEmail = ({
email,
baseUrl,
user,
titleText,
subjectBaseText,
}) => {
const sendNewAuthorEmail = ({ email, baseUrl, user, titleText }) => {
email.toUser = {
email: user.email,
name: `${user.firstName} ${user.lastName}`,
......
......@@ -92,6 +92,14 @@ module.exports = models => async (req, res) => {
collection.save()
}
notifications.sendNotifications({
user,
baseUrl,
fragment,
collection,
UserModel: models.User,
})
return res.status(200).json({
...pick(user, authorKeys),
isSubmitting,
......@@ -128,7 +136,6 @@ module.exports = models => async (req, res) => {
collection,
user: newUser,
UserModel: models.User,
isSubmitting,
})
if (!collection.owners.includes(newUser.id)) {
......
......@@ -74,7 +74,6 @@ const DashboardCard = ({
collectionId={project.id}
fragmentId={version.id}
modalKey={`recommend-${version.id}`}
status={project.status}
/>
)}
<ZipFiles
......
......@@ -9,7 +9,10 @@ import { getFormValues, reset as resetForm } from 'redux-form'
import { FormItems } from '../UIComponents'
import { StepOne, StepTwo, utils } from './'
import { createRecommendation } from '../../redux/recommendations'
import {
createRecommendation,
selectReviewRecommendations,
} from '../../redux/recommendations'
const RecommendWizard = ({
step,
......@@ -40,8 +43,9 @@ const RecommendWizard = ({
export default compose(
connect(
state => ({
(state, { fragmentId }) => ({
decision: get(getFormValues('recommendation')(state), 'decision'),
reviews: selectReviewRecommendations(state, fragmentId),
}),
{
resetForm,
......
import React from 'react'
import { reduxForm } from 'redux-form'
import { isEmpty } from 'lodash'
import { RadioGroup, ValidatedField, Button } from '@pubsweet/ui'
import { utils } from './'
......@@ -7,7 +8,7 @@ import { FormItems } from '../UIComponents'
const { Row, Title, RowItem, RootContainer, CustomRadioGroup } = FormItems
const StepOne = ({ hideModal, disabled, onSubmit, status }) => (
const StepOne = ({ hideModal, disabled, onSubmit, reviews }) => (
<RootContainer>
<Title>Recommendation for Next Phase</Title>
<Row>
......@@ -21,7 +22,7 @@ const StepOne = ({ hideModal, disabled, onSubmit, status }) => (
<RadioGroup
name="decision"
options={
status === 'reviewCompleted'
!isEmpty(reviews)
? utils.recommendationOptions
: utils.recommendationOptions.slice(1)
}
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment