Skip to content
Snippets Groups Projects
Commit 515cf4a9 authored by Sebastian Mihalache's avatar Sebastian Mihalache :hammer_pick:
Browse files

refactor(recommendations): finalized EiC decisions

parent c737b758
No related branches found
No related tags found
3 merge requests!196S25 - EiC submit revision,!189S25,!177Hin 230 eic request revision
const config = require('config') const config = require('config')
const { findLast, isEmpty, maxBy, get, flatMap, last } = require('lodash') const { v4 } = require('uuid')
const logger = require('@pubsweet/logger')
const { features = {}, recommendations: configRecommendations } = config const {
findLast,
isEmpty,
maxBy,
get,
flatMap,
last,
has,
set,
} = require('lodash')
// const { features = {}, recommendations: configRecommendations } = config
const Fragment = require('./Fragment') const Fragment = require('./Fragment')
...@@ -176,6 +188,79 @@ class Collection { ...@@ -176,6 +188,79 @@ class Collection {
isLatestVersion(fragmentId) { isLatestVersion(fragmentId) {
return last(this.collection.fragments) === fragmentId return last(this.collection.fragments) === fragmentId
} }
hasEQA() {
const technicalChecks = get(this.collection, 'technicalChecks', {})
return has(technicalChecks, 'eqa')
}
async setTechnicalChecks() {
set(this.collection, 'technicalChecks.token', v4())
set(this.collection, 'technicalChecks.eqa', false)
await this.collection.save()
}
async sendToMTS({ FragmentModel, UserModel, fragmentHelper }) {
await Promise.all(
this.collection.fragments.map(async fragmentId => {
const fragment = await FragmentModel.find(fragmentId)
let fragmentUsers = []
try {
fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
collection: this.collection,
UserModel,
})
await sendMTSPackage({
collection: this.collection,
fragment,
isEQA: true,
fragmentUsers,
})
} catch (e) {
logger.error(e)
}
}),
).catch(e => {
throw new Error('Something went wrong.')
})
}
async removeTechnicalChecks() {
this.collection.technicalChecks = {}
await this.collection.save()
}
}
const sendMTSPackage = async ({
fragment,
collection,
isEQA = false,
fragmentUsers = [],
}) => {
const s3Config = get(config, 'pubsweet-component-aws-s3', {})
const mtsConfig = get(config, 'mts-service', {})
const { sendPackage } = require('pubsweet-component-mts-package')
const { journal, xmlParser, ftp } = mtsConfig
const packageFragment = {
...fragment,
metadata: {
...fragment.metadata,
customId: collection.customId,
},
}
await sendPackage({
isEQA,
s3Config,
fragmentUsers,
ftpConfig: ftp,
config: journal,
options: xmlParser,
fragment: packageFragment,
})
} }
module.exports = Collection module.exports = Collection
const { get, remove, findLast } = require('lodash') const { get, remove, findLast } = require('lodash')
const config = require('config') const config = require('config')
const User = require('./User') const User = require('./User')
...@@ -222,6 +223,13 @@ class Fragment { ...@@ -222,6 +223,13 @@ class Fragment {
return revAndEditorData return revAndEditorData
} }
async addRecommendation(newRecommendation) {
this.fragment.recommendations = this.fragment.recommendations || []
this.fragment.recommendations.push(newRecommendation)
await this.fragment.save()
}
} }
module.exports = Fragment module.exports = Fragment
const uuid = require('uuid') const { pick, isEmpty, chain, findLast } = require('lodash')
const {
pick,
get,
set,
has,
isEmpty,
last,
chain,
findLast,
} = require('lodash')
const config = require('config') const config = require('config')
const { v4 } = require('uuid') const { v4 } = require('uuid')
const logger = require('@pubsweet/logger')
const { const {
services, services,
...@@ -20,10 +9,13 @@ const { ...@@ -20,10 +9,13 @@ const {
authsome: authsomeHelper, authsome: authsomeHelper,
} = require('pubsweet-component-helper-service') } = require('pubsweet-component-helper-service')
const { features = {}, recommendations } = config const { recommendations } = config
const Notification = require('../../notifications/notification') const Notification = require('../../notifications/notification')
const publishAsHE = require('./strategies/hePublish') const publishAsHE = require('./strategies/hePublish')
const publishAsEiC = require('./strategies/eicPublish')
const rejectAsEiC = require('./strategies/eicReject')
const returnToHE = require('./strategies/eicReturnToHE')
module.exports = models => async (req, res) => { module.exports = models => async (req, res) => {
const { recommendation, comments, recommendationType } = req.body const { recommendation, comments, recommendationType } = req.body
...@@ -130,47 +122,61 @@ module.exports = models => async (req, res) => { ...@@ -130,47 +122,61 @@ module.exports = models => async (req, res) => {
} }
} }
let role = ''
switch (recommendationType) {
case 'review':
role = 'reviewer'
break
case 'editorRecommendation':
role = isEditorInChief ? 'eic' : 'he'
break
default:
return res.status(400).json({
error: `Recommendation ${recommendation} is not defined.`,
})
}
const newRecommendation = {
id: v4(),
userId: reqUser.id,
createdOn: Date.now(),
updatedOn: Date.now(),
recommendationType,
recommendation,
comments: comments || [],
}
const notification = new Notification({
fragment,
collection,
newRecommendation,
UserModel: models.User,
baseUrl: services.getBaseUrl(req),
})
const strategies = { const strategies = {
he: { he: {
publish: publishAsHE, publish: publishAsHE,
}, },
eic: {
publish: publishAsEiC,
reject: rejectAsEiC,
'return-to-handling-editor': returnToHE,
},
} }
const role = 'he'
try { try {
strategies[role][recommendation].execute({ strategies[role][recommendation].execute({
collectionHelper, models,
fragments, fragments,
notification,
fragmentHelper, fragmentHelper,
collectionHelper,
}) })
} catch (e) { } catch (e) {
return res.status(400).json({ error: e.message }) return res.status(400).json({ error: e.message })
} }
// if (
// recommendation === recommendations.publish &&
// recommendationType === recommendations.type.editor &&
// collection.handlingEditor &&
// collection.handlingEditor.id === req.user
// ) {
// if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
// return res.status(400).json({
// error: 'Cannot publish without at least one reviewer report.',
// })
// }
// }
fragment.recommendations = fragment.recommendations || []
const newRecommendation = {
id: uuid.v4(),
userId: reqUser.id,
createdOn: Date.now(),
updatedOn: Date.now(),
recommendationType,
}
// newRecommendation.recommendation = recommendation || undefined
newRecommendation.comments = comments || []
if (recommendationType === 'editorRecommendation') { if (recommendationType === 'editorRecommendation') {
await collectionHelper.updateStatusOnRecommendation({ await collectionHelper.updateStatusOnRecommendation({
isEditorInChief, isEditorInChief,
...@@ -181,102 +187,15 @@ module.exports = models => async (req, res) => { ...@@ -181,102 +187,15 @@ module.exports = models => async (req, res) => {
fragment.revision = pick(fragment, ['authors', 'files', 'metadata']) fragment.revision = pick(fragment, ['authors', 'files', 'metadata'])
} }
const technicalChecks = get(collection, 'technicalChecks', {})
const hasEQA = has(technicalChecks, 'eqa')
// the manuscript has not yet passed through the EQA process so we need to upload it to the FTP server
if (isEditorInChief && recommendation === 'publish' && !hasEQA) {
if (features.mts) {
await Promise.all(
collection.fragments.map(async fragmentId => {
const fragment = await models.Fragment.find(fragmentId)
const fragmentHelper = new Fragment({ fragment })
let fragmentUsers = []
try {
fragmentUsers = await fragmentHelper.getReviewersAndEditorsData({
collection,
UserModel: models.User,
})
await sendMTSPackage({
collection,
fragment,
isEQA: true,
fragmentUsers,
})
} catch (e) {
logger.error(e)
}
}),
).catch(e =>
res.status(500).json({
error: 'Something went wrong.',
}),
)
}
collection.status = 'inQA'
set(collection, 'technicalChecks.token', v4())
set(collection, 'technicalChecks.eqa', false)
await collection.save()
}
/* if the EiC returns the manuscript to the HE after the EQA has been performed
then remove all properties from the technicalChecks property so that the manuscript
can go through the EQA process again
*/
if (
isEditorInChief &&
recommendation === 'return-to-handling-editor' &&
hasEQA
) {
collection.technicalChecks = {}
await collection.save()
}
const notification = new Notification({
fragment,
collection,
newRecommendation,
UserModel: models.User,
baseUrl: services.getBaseUrl(req),
})
const hasPeerReview = !isEmpty(collection.handlingEditor) const hasPeerReview = !isEmpty(collection.handlingEditor)
if (isEditorInChief) { if (collection.status === 'revisionRequested') {
if (recommendation === 'publish' && collection.status === 'inQA') { notification.notifySAWhenHERequestsRevision()
notification.notifyEAWhenEiCRequestsEQAApproval() }
}
if (recommendation === 'publish' && collection.status === 'accepted') {
notification.notifyEAWhenEiCMakesFinalDecision()
}
if (hasPeerReview && (recommendation !== 'publish' || hasEQA)) {
if (recommendation === 'return-to-handling-editor') {
notification.notifyHEWhenEiCReturnsToHE()
} else {
notification.notifyHEWhenEiCMakesDecision()
notification.notifyReviewersWhenEiCMakesDecision()
}
}
if (
recommendation !== 'return-to-handling-editor' &&
(recommendation !== 'publish' || hasEQA)
) {
notification.notifyAuthorsWhenEiCMakesDecision()
}
} else {
if (collection.status === 'revisionRequested') {
notification.notifySAWhenHERequestsRevision()
}
if (hasPeerReview) { if (hasPeerReview) {
notification.notifyReviewersWhenHEMakesRecommendation() notification.notifyReviewersWhenHEMakesRecommendation()
notification.notifyEiCWhenHEMakesRecommendation() notification.notifyEiCWhenHEMakesRecommendation()
}
} }
} }
...@@ -285,33 +204,3 @@ module.exports = models => async (req, res) => { ...@@ -285,33 +204,3 @@ module.exports = models => async (req, res) => {
return res.status(200).json(newRecommendation) return res.status(200).json(newRecommendation)
} }
const sendMTSPackage = async ({
fragment,
collection,
isEQA = false,
fragmentUsers = [],
}) => {
const s3Config = get(config, 'pubsweet-component-aws-s3', {})
const mtsConfig = get(config, 'mts-service', {})
const { sendPackage } = require('pubsweet-component-mts-package')
const { journal, xmlParser, ftp } = mtsConfig
const packageFragment = {
...fragment,
metadata: {
...fragment.metadata,
customId: collection.customId,
},
}
await sendPackage({
isEQA,
s3Config,
fragmentUsers,
ftpConfig: ftp,
config: journal,
options: xmlParser,
fragment: packageFragment,
})
}
const config = require('config')
const { features = {} } = config
module.exports = { module.exports = {
execute: ({ fragment, collection, recommendation }) => {}, execute: async ({
models,
notification,
fragmentHelper,
collectionHelper,
newRecommendation,
}) => {
await fragmentHelper.addRecommendation(newRecommendation)
let newStatus = ''
if (collectionHelper.hasEQA()) {
newStatus = 'accepted'
notification.notifyEAWhenEiCMakesFinalDecision()
notification.notifyAuthorsWhenEiCMakesDecision()
notification.notifyHEWhenEiCMakesDecision()
notification.notifyReviewersWhenEiCMakesDecision()
} else {
if (features.mts) {
await collectionHelper.sendToMTS({
fragmentHelper,
UserModel: models.User,
FragmentModel: models.Fragment,
})
}
newStatus = 'inQA'
await collectionHelper.setTechnicalChecks()
notification.notifyEAWhenEiCRequestsEQAApproval()
}
await collectionHelper.updateStatus({ newStatus })
},
} }
module.exports = {
execute: async ({
notification,
fragmentHelper,
collectionHelper,
newRecommendation,
}) => {
await fragmentHelper.addRecommendation(newRecommendation)
await collectionHelper.updateStatus({ newStatus: 'rejected' })
notification.notifyAuthorsWhenEiCMakesDecision()
notification.notifyHEWhenEiCMakesDecision()
notification.notifyReviewersWhenEiCMakesDecision()
},
}
module.exports = {
execute: async ({
notification,
fragmentHelper,
collectionHelper,
newRecommendation,
}) => {
if (collectionHelper.hasEQA()) {
await collectionHelper.removeTechnicalChecks()
}
await collectionHelper.updateStatus({ newStatus: 'reviewCompleted' })
await fragmentHelper.addRecommendation(newRecommendation)
notification.notifyHEWhenEiCReturnsToHE()
},
}
module.exports = { module.exports = {
execute: ({ collectionHelper, fragments, fragmentHelper }) => { execute: async ({
collectionHelper,
fragments,
fragmentHelper,
notification,
newRecommendation,
}) => {
if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) { if (!collectionHelper.canHEMakeRecommendation(fragments, fragmentHelper)) {
throw new Error('Cannot publish without at least one reviewer report.') throw new Error('Cannot publish without at least one reviewer report.')
} }
await fragmentHelper.addRecommendation(newRecommendation)
await collectionHelper.updateStatus({ newStatus: 'pendingApproval' })
notification.notifyReviewersWhenHEMakesRecommendation()
notification.notifyEiCWhenHEMakesRecommendation()
}, },
} }
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