-
Jure authored1afdc7f4
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Forked from
kotahi / Kotahi
4985 commits behind the upstream repository.
manuscript.js 8.50 KiB
const BaseModel = require('@pubsweet/base-model')
const omit = require('lodash/omit')
const cloneDeep = require('lodash/cloneDeep')
const sortBy = require('lodash/sortBy')
const values = require('lodash/values')
class Manuscript extends BaseModel {
static get tableName() {
return 'manuscripts'
}
constructor(properties) {
super(properties)
this.type = 'Manuscript'
}
static async myManuscripts(myManuscripts) {
const mainManuscript = {}
myManuscripts.forEach(manuscript => {
if (!mainManuscript[manuscript.parentId || manuscript.id]) {
mainManuscript[manuscript.parentId || manuscript.id] = manuscript
} else {
const checkManuscript =
mainManuscript[manuscript.parentId || manuscript.id]
// Compare Dates
const dateCheckManuscript = new Date(checkManuscript.created).getTime()
const dateManuscript = new Date(manuscript.created).getTime()
if (dateManuscript >= dateCheckManuscript) {
mainManuscript[manuscript.parentId || manuscript.id] = manuscript
}
}
})
const latestManuscripts = values(mainManuscript)
await Promise.all(
latestManuscripts.map(async manuscript => {
manuscript.teams = await new Manuscript(manuscript).getTeams()
manuscript.reviews = await new Manuscript(manuscript).getReviews()
manuscript.manuscriptVersions =
(await manuscript.getManuscriptVersions()) || []
return manuscript
}),
)
return latestManuscripts
}
async getTeams() {
const { Team } = require('@pubsweet/models')
const myTeams = await Team.query()
.where({
objectId: this.id,
objectType: 'Manuscript',
})
.eager('members')
// const { rows } = await db.raw(
// `SELECT id, data FROM entities WHERE ${where.join(' AND ')}`,
// Object.values(selector),
// )
// const myTeams = rows.map(
// result => new Team({ id: result.id, ...result.data }),
// )
return myTeams
}
async getReviews() {
const Review = require('../../review/src/review')
const manuscriptReviews = await Review.findByField('manuscript_id', this.id)
await Promise.all(
manuscriptReviews.map(async review => {
review.comments = await review.getComments()
}),
)
return manuscriptReviews
}
async getManuscriptVersions() {
const { File } = require('@pubsweet/models')
const id = this.parentId || this.id
const manuscripts = await Manuscript.findByField('parent_id', id)
const firstManuscript = await Manuscript.findOneByField('id', id)
manuscripts.push(firstManuscript)
const manuscriptVersionsArray = manuscripts.filter(
manuscript =>
new Date(manuscript.created).getTime() <
new Date(this.created).getTime() && this.id !== manuscript.id,
)
const manuscriptVersions = sortBy(
manuscriptVersionsArray,
manuscript => new Date(manuscript.created),
)
await Promise.all(
manuscriptVersions.map(async manuscript => {
manuscript.reviews = await manuscript.getReviews()
manuscript.teams = await manuscript.getTeams()
manuscript.files = await File.findByObject({
object: 'Manuscript',
object_id: manuscript.id,
})
return manuscript
}),
)
return manuscriptVersions
}
async createNewVersion() {
const { Team, File } = require('@pubsweet/models')
const manuscriptReviews = await this.getReviews()
const manuscriptTeams = await this.getTeams()
const teams = manuscriptTeams.filter(
team =>
team.role === 'author' ||
team.role === 'seniorEditor' ||
team.role === 'handlingEditor',
)
const manuscriptFiles = await File.findByObject({
object: 'Manuscript',
object_id: this.id,
})
const manuscriptDecision = manuscriptReviews.find(
review => review.isDecision,
)
const dataManuscript = await new Manuscript(
omit(cloneDeep(this), ['id', 'created', 'updated', 'decision']),
)
dataManuscript.status =
manuscriptDecision.recommendation === 'revise'
? 'revising'
: manuscriptDecision.recommendation
dataManuscript.parentId = this.parentId || this.id
const newManuscript = await dataManuscript.save()
if (teams.length > 0) {
// Copy Teams to the new Version
await Promise.all(
teams.map(async team => {
team.objectId = newManuscript.id
team.members = team.members.map(member => omit(member, 'id'))
await new Team(omit(team, ['id'])).saveGraph()
}),
)
}
// Copy Files to the new Version
await Promise.all(
manuscriptFiles.map(async file => {
const newFile = omit(file, ['id'])
newFile.objectId = newManuscript.id
await new File(newFile).save()
return newFile
}),
)
return this
}
static get relationMappings() {
const { Channel } = require('@pubsweet/models')
return {
channels: {
relation: BaseModel.HasManyRelation,
modelClass: Channel,
join: {
from: 'manuscripts.id',
to: 'channels.manuscriptId',
},
},
}
}
static get schema() {
return {
properties: {
parentId: { type: ['string', 'null'], format: 'uuid' },
manuscriptVersions: { type: ['object', 'null'] },
files: {
items: { type: 'object' },
type: ['array', 'null'],
},
teams: {
items: { type: 'object' },
type: ['array', 'null'],
},
reviews: {
items: { type: 'object' },
type: ['array', 'null'],
},
status: { type: ['string', 'null'] },
decision: { type: ['string', 'null'] },
suggestions: {
type: ['object', 'null'],
properties: {
reviewers: {
suggested: { type: ['string', 'null'] },
opposed: { type: ['string', 'null'] },
},
editors: {
suggested: { type: ['string', 'null'] },
opposed: { type: ['string', 'null'] },
},
},
},
authors: {
items: { type: 'object' },
type: ['array', 'null'],
},
meta: {
type: 'object',
properties: {
title: { type: 'string' },
abstract: { type: ['string', 'null'] },
source: { type: 'string' },
articleType: { type: 'string' },
declarations: {
type: 'object',
properties: {
openData: { type: ['string', 'null'] },
openPeerReview: { type: ['string', 'null'] },
preregistered: { type: ['string', 'null'] },
previouslySubmitted: { type: ['string', 'null'] },
researchNexus: { type: ['string', 'null'] },
streamlinedReview: { type: ['string', 'null'] },
},
},
articleSections: {
items: { type: 'string' },
type: ['array', 'null'],
},
articleIds: {
items: { type: 'object' },
type: ['array', 'null'],
},
history: {
items: { type: 'object' },
type: ['array', 'null'],
},
publicationDates: {
items: { type: 'object' },
type: ['array', 'null'],
},
notes: {
items: { type: 'object' },
type: ['array', 'null'],
},
keywords: { type: ['string', 'null'] },
},
},
submission: {},
submitterId: { type: ['string', 'null'], format: 'uuid' },
},
}
}
// TODO: Do this on the DB level with cascading deletes
async $beforeDelete() {
// const Review = require('../../review/src/review')
const { Review, Team, File } = require('@pubsweet/models')
const files = await File.findByObject({
object_id: this.id,
object: 'Manuscript',
})
if (files.length > 0) {
files.forEach(async fl => {
await new File(fl).delete()
})
}
const review = await Review.findByField('manuscript_id', this.id)
if (review.length > 0) {
review.forEach(async rv => {
await new Review(rv).delete()
})
}
this.teams = await this.getTeams()
this.teams.forEach(async team => {
await new Team(team).delete()
})
}
}
Manuscript.type = 'Manuscript'
module.exports = Manuscript