Newer
Older
const merge = require('lodash/merge')
const form = require('../../../app/storage/forms/submit.json')
const resolvers = {
Mutation: {
async createManuscript(_, vars, ctx) {
Jure
committed
// We want the submission information to be stored as JSONB
// but we want the input to come in as a JSON string
const submission = vars.input.submission
? JSON.parse(vars.input.submission)
: {}
const emptyManuscript = {
meta: Object.assign(meta, {
notes: [
{
notesType: 'fundingAcknowledgement',
content: '',
},
{
notesType: 'specialInstructions',
content: '',
},
],
}),
status: 'new',
Jure
committed
submission,
Jure
committed
const manuscript = await new ctx.models.Manuscript(
// Create two channels: 1. free for all involved, 2. editorial
manuscriptId: manuscript.id,
topic: 'Manuscript discussion',
type: 'all',
}).save()
manuscriptId: manuscript.id,
topic: 'Editorial discussion',
type: 'editorial',
}).save()
manuscript.manuscriptVersions = []
manuscript.files = []
files.map(async file => {
const newFile = Object.assign({}, file, {
fileType: 'manuscript',
object: 'Manuscript',
objectId: manuscript.id,
})
const createdTeam = await Team.query().upsertGraphAndFetch(
{
role: 'author',
name: 'Author',
objectId: manuscript.id,
objectType: 'Manuscript',
manuscript.channels = [allChannel, editorialChannel]
return manuscript
},
async deleteManuscript(_, { id }, ctx) {
const deleteManuscript = []
const manuscript = await ctx.models.Manuscript.find(id)
deleteManuscript.push(manuscript.id)
if (manuscript.parentId) {
const parentManuscripts = await ctx.models.Manuscript.findByField(
'parent_id',
manuscript.parentId,
)
parentManuscripts.forEach(manuscript => {
deleteManuscript.push(manuscript.id)
})
}
// Delete Manuscript
if (deleteManuscript.length > 0) {
deleteManuscript.forEach(async manuscript => {
await ctx.models.Manuscript.query().deleteById(manuscript)
})
}
return id
},
async reviewerResponse(_, { currentUserId, action, teamId }, context) {
const { Team, Review } = require('@pubsweet/models')
if (action !== 'accepted' && action !== 'rejected')
throw new Error(
`Invalid action provided to handleInvitation:
Must be either "accepted" or "rejected"`,
)
const team = await Team.query()
.findById(teamId)
.eager('members')
})
if (!team) throw new Error('No team was found')
if (action === 'accepted') {
const review = {
recommendation: '',
isDecision: false,
userId: currentUserId,
}
await new Review(review).save()
}
return team
},
async updateManuscript(_, { id, input }, ctx) {
const data = JSON.parse(input)
const manuscript = await ctx.models.Manuscript.query().findById(id)
return ctx.models.Manuscript.query().updateAndFetchById(id, update)
async makeDecision(_, { id, decision }, ctx) {
const manuscript = await ctx.models.Manuscript.query().findById(id)
manuscript.status = decision
return manuscript.save()
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
async addReviewer(_, { manuscriptId, userId }, ctx) {
const manuscript = await ctx.models.Manuscript.query().findById(
manuscriptId,
)
const existingTeam = await manuscript
.$relatedQuery('teams')
.where('role', 'reviewer')
.first()
// Add the reviewer to the existing team of reviewers
if (existingTeam) {
const reviewerExists =
(await existingTeam
.$relatedQuery('users')
.where('users.id', userId)
.resultSize()) > 0
if (!reviewerExists) {
await new ctx.models.TeamMember({
teamId: existingTeam.id,
status: 'invited',
userId,
}).save()
}
return existingTeam.$query().eager('members.[user]')
}
// Create a new team of reviewers if it doesn't exist
const newTeam = await new ctx.models.Team({
objectId: manuscriptId,
objectType: 'Manuscript',
members: [{ status: 'invited', userId }],
role: 'reviewer',
}).saveGraph()
return newTeam
},
async removeReviewer(_, { manuscriptId, userId }, ctx) {
const manuscript = await ctx.models.Manuscript.query().findById(
manuscriptId,
)
const reviewerTeam = await manuscript
.$relatedQuery('teams')
.where('role', 'reviewer')
.first()
await ctx.models.TeamMember.query()
.where({
userId,
teamId: reviewerTeam.id,
})
.delete()
return reviewerTeam.$query().eager('members.[user]')
},
async manuscript(_, { id }, ctx) {
const Manuscript = require('./manuscript')
const manuscript = await Manuscript.query()
.findById(id)
if (!manuscript.meta) {
manuscript.meta = {}
}
manuscript.meta.notes = (manuscript.meta || {}).notes || [
{
notesType: 'fundingAcknowledgement',
content: '',
},
{
notesType: 'specialInstructions',
content: '',
},
]
manuscript.decision = ''
manuscript.files = await ctx.models.File.findByObject({
object: 'Manuscript',
object_id: manuscript.id,
})
manuscript.manuscriptVersions = await manuscript.getManuscriptVersions()
// manuscript.channel = await ctx.connectors.Channel.model.find(
// manuscript.channelId,
// )
return ctx.models.Manuscript.query().eager('[teams, reviews]')
async paginatedManuscripts(_, { sort, offset, limit, filter }, ctx) {
const query = ctx.models.Manuscript.query().eager('submitter')
if (filter && filter.status) {
query.where({ status: filter.status })
}
const totalCount = await query.resultSize()
if (sort) {
const [sortName, sortDirection] = sort.split('_')
query.orderBy(ref(sortName), sortDirection)
// }
// // e.g. 'created_DESC' into 'created' and 'DESC' arguments
// query.orderBy(...sort.split('_'))
}
if (limit) {
query.limit(limit)
}
if (offset) {
query.offset(offset)
}
const manuscripts = await query
return {
totalCount,
manuscripts,
}
// return ctx.connectors.User.fetchAll(where, ctx, { eager })
},
async getFile() {
return form
},
},
Jure
committed
// We want submission into to come out as a stringified JSON, so that we don't have to
// change our queries if the submission form changes. We still want to store it as JSONB
// so that we can easily search through the information within.
Manuscript: {
submission(parent) {
return JSON.stringify(parent.submission)
},
async reviews(parent, _, ctx) {
return parent.reviews
? parent.reviews
: (
await ctx.models.Manuscript.query().findById(parent.id)
).$relatedQuery('reviews')
},
async teams(parent, _, ctx) {
return parent.teams
? parent.teams
: (
await ctx.models.Manuscript.query().findById(parent.id)
).$relatedQuery('teams')
},
},
ManuscriptVersion: {
submission(parent) {
Jure
committed
return JSON.stringify(parent.submission)
},
},
const typeDefs = `
extend type Query {
globalTeams: [Team]
manuscript(id: ID!): Manuscript!
manuscripts: [Manuscript]!
paginatedManuscripts(sort: String, offset: Int, limit: Int, filter: ManuscriptsFilter): PaginatedManuscripts
input ManuscriptsFilter {
status: String
}
type PaginatedManuscripts {
totalCount: Int
manuscripts: [Manuscript]
}
# enum ManuscriptsSort {
# meta->>'title'_DESC
# created_ASC
# created_DESC
# updated_ASC
# updated_DESC
# }
extend type Mutation {
createManuscript(input: ManuscriptInput): Manuscript!
updateManuscript(id: ID!, input: String): Manuscript!
makeDecision(id: ID!, decision: String): Manuscript!
deleteManuscript(id: ID!): ID!
reviewerResponse(currentUserId: ID, action: String, teamId: ID! ): Team
assignTeamEditor(id: ID!, input: String): [Team]
addReviewer(manuscriptId: ID!, userId: ID!): Team
removeReviewer(manuscriptId: ID!, userId: ID!): Team
}
type Manuscript implements Object {
id: ID!
created: DateTime!
updated: DateTime
manuscriptVersions: [ManuscriptVersion]
files: [File]
teams: [Team]
reviews: [Review!]
status: String
decision: String
suggestions: Suggestions
authors: [Author]
meta: ManuscriptMeta
submission: String
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
}
type ManuscriptVersion implements Object {
id: ID!
created: DateTime!
updated: DateTime
files: [File]
teams: [Team]
reviews: [Review]
status: String
formState: String
decision: String
suggestions: Suggestions
authors: [Author]
meta: ManuscriptMeta
submission: String
}
input ManuscriptInput {
files: [FileInput]
meta: ManuscriptMetaInput
submission: String
}
input ManuscriptMetaInput {
title: String
source: String
}
input FileInput {
filename: String
url: String
mimeType: String
size: Int
}
type Author {
firstName: String
lastName: String
email: String
affiliation: String
}
type Suggestion {
suggested: String
opposed: String
}
type Suggestions {
reviewers: Suggestion
editors: Suggestion
}
type ManuscriptMeta {
title: String!
source: String
articleType: String
declarations: Declarations
articleSections: [String]
articleIds: [ArticleId]
abstract: String
subjects: [String]
history: [MetaDate]
publicationDates: [MetaDate]
notes: [Note]
keywords: String
}
type ArticleId {
pubIdType: String
id: String
}
type MetaDate {
type: String
date: DateTime
}
type Declarations {
openData: String
openPeerReview: String
preregistered: String
previouslySubmitted: String
researchNexus: String
streamlinedReview: String
}
type Note implements Object {
id: ID!
created: DateTime!
updated: DateTime
notesType: String
content: String
}
`
module.exports = {
typeDefs,
resolvers,
}