-
Audrey Hamelers authoredf2c24e1f
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
index.js 11.81 KiB
const { transaction } = require('objection')
const config = require('config')
const lodash = require('lodash')
const rfr = require('rfr')
const authorization = require('pubsweet-server/src/helpers/authorization')
const logger = require('@pubsweet/logger')
const EmailValidator = require('email-validator')
const ManuscriptAccess = require('./data-access')
const FileAccess = require('../file/data-access')
const NoteAccess = require('../note/data-access')
const ReviewAccess = require('../review/data-access')
const UserAccess = require('../user/data-access')
const Team = require('../team/data-access')
const { dManuscriptUpdate, gManuscript } = require('./helpers/transform')
const { userMessage, reviewerEmail, submitterRejectEmail } = rfr('server/email')
const Manuscript = {
selectActivityById: async id => {
const manuscript = await ManuscriptAccess.selectActivityById(id)
const gMan = gManuscript(manuscript)
return gMan
},
all: async user => {
const Manuscripts = await ManuscriptAccess.selectAll(user)
return Manuscripts.map(manuscript => gManuscript(manuscript))
},
findByStatus: async (query, page, pageSize, user) => {
const manuscripts = await ManuscriptAccess.selectByStatus(
query,
page,
pageSize,
user,
)
const rtn =
page === -1
? manuscripts.map(manuscript => gManuscript(manuscript))
: {
total: manuscripts.total,
manuscripts: manuscripts.results.map(manuscript =>
gManuscript(manuscript),
),
}
return rtn
},
findById: async (id, userId) => {
const manuscript = await ManuscriptAccess.selectById(id, true)
await authorization.can(userId, 'read', {
id,
type: 'Manuscript',
status: manuscript.status,
})
return gManuscript(manuscript)
},
findByArticleId: async (id, userId) => {
let manuscript = null
if (id.toUpperCase().startsWith('EMS')) {
manuscript = await ManuscriptAccess.selectById(id)
} else {
const manuscripts = await ManuscriptAccess.searchArticleIds(id, userId)
manuscript = manuscripts.pop()
}
return {
manuscript,
errors: manuscript
? null
: [{ 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 => {
const count = await ManuscriptAccess.countByStatus(type)
return { type, count }
})
return counts
},
search: async (query, page, pageSize, user) => {
let manuscripts
if (EmailValidator.validate(query)) {
manuscripts = await ManuscriptAccess.searchByEmail(
query,
page,
pageSize,
user,
)
logger.debug('manuscripts: ', manuscripts)
return {
total: manuscripts.total,
manuscripts: manuscripts.results.map(manuscript =>
gManuscript(manuscript),
),
}
}
manuscripts = await ManuscriptAccess.searchByTitleOrLastname(
query,
page,
pageSize,
user,
)
logger.debug('manuscripts: ', manuscripts)
return {
total: manuscripts.total,
manuscripts: manuscripts.results.map(manuscript =>
gManuscript(manuscript),
),
}
},
findByDepositStates: ManuscriptAccess.selectByPdfDepositStates,
findByDepositStatesNull: ManuscriptAccess.selectByPdfDepositStatesNull,
delete: async (id, userId) => {
let trx
try {
trx = await transaction.start(ManuscriptAccess.knex())
const manuscript = await ManuscriptAccess.selectById(id)
if (manuscript) {
await ManuscriptAccess.delete(id, userId, trx)
await FileAccess.deleteByManuscriptId(id, userId, trx)
await ReviewAccess.deleteByManuscriptId(id, userId, trx)
await NoteAccess.deleteByManuscriptId(id, userId, trx)
await trx.commit()
return true
}
return false
} catch (error) {
if (trx) {
await trx.rollback()
}
logger.error('Nothing was deleted')
logger.error(error)
throw error
}
},
create: async (userId, organizationId) => {
await authorization.can(userId, 'create', {
id: null,
type: 'Manuscript',
status: config.manuscript.status.initial,
})
let trx
let savedMan
try {
trx = await transaction.start(ManuscriptAccess.knex())
const manuscript = new ManuscriptAccess({
organizationId,
updatedBy: userId,
status: config.manuscript.status.initial,
})
savedMan = await manuscript.saveWithTrx(trx)
const team = new Team({
manuscriptId: savedMan.id,
userId,
roleName: config.authsome.teams.submitter.name,
updatedBy: userId,
})
await team.saveWithTrx(trx)
await trx.commit()
} catch (error) {
if (trx) {
await trx.rollback()
}
logger.error('Nothing was created: ', error)
throw error
}
return savedMan
},
changeClaim: async (manId, userId, unclaim = false) => {
const originalMan = await ManuscriptAccess.selectById(manId)
let manuscriptUpdate = {}
const errors = []
if (originalMan.claimedBy && unclaim) {
if (originalMan.claimedBy === userId) {
manuscriptUpdate = dManuscriptUpdate({ claimedBy: null }, userId)
} else {
errors.push({ message: 'You have not claimed this manuscript' })
}
} else if (originalMan.claimedBy) {
errors.push({ message: 'Manuscript already claimed' })
} else {
manuscriptUpdate = dManuscriptUpdate({ claimedBy: userId }, userId)
}
lodash.assign(originalMan, manuscriptUpdate)
await originalMan.save()
const updatedMan = await ManuscriptAccess.selectById(manId, true)
return {
manuscript: gManuscript(updatedMan),
errors,
}
},
update: async (input, userId) => {
const originalMan = await ManuscriptAccess.selectById(input.id)
if (!originalMan) {
throw new Error('Manuscript not found')
}
const manuscriptUpdate = dManuscriptUpdate(input, userId)
lodash.assign(originalMan, manuscriptUpdate)
await originalMan.save()
const updatedMan = await ManuscriptAccess.selectById(input.id, true)
return gManuscript(updatedMan)
},
submit: async (input, userId) => {
const originalMan = await ManuscriptAccess.selectById(input.id)
const errors = []
if (!originalMan) {
errors.push({ message: 'Manuscript not found' })
return {
manuscript: null,
errors,
}
}
if (input.status === 'submitted') {
const notes = await NoteAccess.selectByManuscriptId(input.id)
const reviewerNote = notes.find(n => n.notesType === 'selectedReviewer')
const teams = await Team.selectByManuscriptId(input.id)
const subTeam = teams.find(t => t.roleName === 'submitter')
const revTeam = teams.find(t => t.roleName === 'reviewer')
const submitter = await UserAccess.findById(subTeam.userId)
let inReview = false
let reviewer = {}
let token = ''
if (reviewerNote) {
reviewer = JSON.parse(reviewerNote.content)
token = reviewerNote.id
if (reviewer.id) {
let trx
try {
trx = await transaction.start(Team.knex())
const team = new Team({
manuscriptId: input.id,
userId: reviewer.id,
roleName: 'reviewer',
updatedBy: userId,
})
await team.saveWithTrx(trx)
await NoteAccess.delete(reviewerNote.id, userId)
if (revTeam) {
await Team.delete(revTeam.id, userId)
}
await trx.commit()
} catch (error) {
if (trx) {
await trx.rollback()
}
logger.error('Nothing was created: ', error)
errors.push(error)
return {
manuscript: null,
errors,
}
}
if (reviewer.id !== submitter.id) {
inReview = true
}
} else {
inReview = true
}
} else if (
originalMan.status === 'submission-error' &&
revTeam &&
revTeam.userId !== submitter.id &&
userId !== revTeam.userId
) {
const revUser = await UserAccess.findById(revTeam.userId)
const { id, title, givenNames, surname, identities } = revUser
const { email } = identities[0]
inReview = true
reviewer = {
id,
name: {
title,
givenNames,
surname,
},
email,
}
token = 'correction'
} else if (!revTeam) {
errors.push({ message: 'Reviewer must be selected' })
return {
manuscript: null,
errors,
}
}
if (inReview) {
input.status = 'in-review'
await reviewerEmail({
reviewer,
manInfo: {
id: input.id,
title: originalMan['meta,title'],
},
submitter,
token,
})
}
}
input.claimedBy = null
try {
const manuscriptUpdate = dManuscriptUpdate(input, userId)
lodash.assign(originalMan, manuscriptUpdate)
await originalMan.save()
} catch (error) {
logger.error(error)
errors.push(error)
}
const updatedMan = await ManuscriptAccess.selectById(input.id, true)
return {
manuscript: gManuscript(updatedMan),
errors,
}
},
reject: async (input, userId) => {
const originalMan = await ManuscriptAccess.selectById(input.manuscriptId)
const teams = await Team.selectByManuscriptId(input.manuscriptId)
const subTeam = teams.find(t => t.roleName === 'submitter')
const revTeam = teams.find(t => t.roleName === 'reviewer')
const submitter = await UserAccess.findById(subTeam.userId)
const reviewer = await UserAccess.findById(revTeam.userId)
const email = JSON.parse(input.content)
const errors = []
try {
await NoteAccess.insert(input, userId)
const manUpdate = {
claimedBy: null,
formState: email.message ? email.message : email,
status: 'submission-error',
updatedBy: userId,
}
lodash.assign(originalMan, manUpdate)
await originalMan.save()
} catch (error) {
logger.error(error)
errors.push(error)
return {
manuscript: null,
errors,
}
}
if (email.to) {
email.to.forEach(async e => {
const sendTo =
(submitter.id === e && submitter.identities[0].email) ||
(reviewer.id === e && reviewer.identities[0].email)
await userMessage(sendTo, email.subject, email.message)
})
} else {
await submitterRejectEmail({
reviewer,
manInfo: {
id: originalMan.id,
title: originalMan['meta,title'],
},
submitter,
message: email,
})
}
const updatedMan = await ManuscriptAccess.selectById(originalMan.id, true)
return {
manuscript: gManuscript(updatedMan),
errors,
}
},
}
module.exports = Manuscript