2017-07-03 10:54:10 +09:00
/ *
Default mutations
* /
2018-03-03 11:39:56 +09:00
import { registerCallback , newMutator , editMutator , removeMutator , Utils , Connectors } from 'meteor/vulcan:lib' ;
2017-07-03 10:54:10 +09:00
import Users from 'meteor/vulcan:users' ;
2017-10-21 15:58:02 +09:00
export const getDefaultMutations = ( collectionName , options = { } ) => {
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
// register callbacks for documentation purposes
registerCollectionCallbacks ( collectionName ) ;
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
return {
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
// mutation for inserting a new document
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
new : {
name : ` ${ collectionName } New ` ,
2018-01-02 13:04:33 +09:00
description : ` Mutation for inserting new ${ collectionName } documents ` ,
2017-10-21 15:58:02 +09:00
// check function called on a user to see if they can perform the operation
check ( user , document ) {
if ( options . newCheck ) {
return options . newCheck ( user , document ) ;
}
2018-03-03 23:11:33 +01:00
// check if they can perform "foo.new" operation (e.g. "movies.new")
2017-10-21 15:58:02 +09:00
return Users . canDo ( user , ` ${ collectionName . toLowerCase ( ) } .new ` ) ;
} ,
async mutation ( root , { document } , context ) {
const collection = context [ collectionName ] ;
// check if current user can pass check function; else throw error
Utils . performCheck ( this . check , context . currentUser , document ) ;
2018-02-17 11:17:25 +09:00
// pass document to boilerplate newMutator function
return await newMutator ( {
2017-10-21 15:58:02 +09:00
collection ,
document : document ,
currentUser : context . currentUser ,
validate : true ,
context ,
} ) ;
} ,
2017-07-03 10:54:10 +09:00
} ,
2017-10-21 15:58:02 +09:00
// mutation for editing a specific document
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
edit : {
name : ` ${ collectionName } Edit ` ,
2018-01-02 13:04:33 +09:00
description : ` Mutation for editing a ${ collectionName } document ` ,
2017-10-21 15:58:02 +09:00
// check function called on a user and document to see if they can perform the operation
check ( user , document ) {
if ( options . editCheck ) {
return options . editCheck ( user , document ) ;
}
if ( ! user || ! document ) return false ;
// check if user owns the document being edited.
// if they do, check if they can perform "foo.edit.own" action
// if they don't, check if they can perform "foo.edit.all" action
return Users . owns ( user , document ) ? Users . canDo ( user , ` ${ collectionName . toLowerCase ( ) } .edit.own ` ) : Users . canDo ( user , ` ${ collectionName . toLowerCase ( ) } .edit.all ` ) ;
} ,
async mutation ( root , { documentId , set , unset } , context ) {
const collection = context [ collectionName ] ;
// get entire unmodified document from database
2018-03-03 11:39:56 +09:00
const document = await Connectors . get ( collection , documentId ) ;
2017-10-21 15:58:02 +09:00
// check if user can perform operation; if not throw error
Utils . performCheck ( this . check , context . currentUser , document ) ;
2018-02-17 11:17:25 +09:00
// call editMutator boilerplate function
return await editMutator ( {
2017-10-21 15:58:02 +09:00
collection ,
documentId : documentId ,
set : set ,
unset : unset ,
currentUser : context . currentUser ,
validate : true ,
context ,
} ) ;
} ,
2017-07-03 10:54:10 +09:00
} ,
2018-01-28 22:24:33 -06:00
// mutation for upserting a specific document
upsert : {
name : ` ${ collectionName } Upsert ` ,
description : ` Mutation for upserting a ${ collectionName } document ` ,
async mutation ( root , { search , set , unset } , context ) {
const collection = context [ collectionName ] ;
// check if document exists already
2018-03-03 11:39:56 +09:00
const existingDocument = await Connectors . get ( collection , search , { fields : { _id : 1 } } ) ;
2018-01-28 22:24:33 -06:00
if ( existingDocument ) {
const editArgs = {
documentId : existingDocument . _id ,
set ,
unset ,
} ;
return await collection . options . mutations . edit . mutation ( root , editArgs , context ) ;
} else {
return await collection . options . mutations . new . mutation ( root , { document : set } , context ) ;
}
} ,
} ,
2017-10-21 15:58:02 +09:00
// mutation for removing a specific document (same checks as edit mutation)
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
remove : {
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
name : ` ${ collectionName } Remove ` ,
2017-08-07 16:02:29 +09:00
2018-01-02 13:04:33 +09:00
description : ` Mutation for deleting a ${ collectionName } document ` ,
2017-10-21 15:58:02 +09:00
check ( user , document ) {
if ( options . removeCheck ) {
return options . removeCheck ( user , document ) ;
}
if ( ! user || ! document ) return false ;
return Users . owns ( user , document ) ? Users . canDo ( user , ` ${ collectionName . toLowerCase ( ) } .remove.own ` ) : Users . canDo ( user , ` ${ collectionName . toLowerCase ( ) } .remove.all ` ) ;
} ,
async mutation ( root , { documentId } , context ) {
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
const collection = context [ collectionName ] ;
2017-07-03 10:54:10 +09:00
2018-03-03 11:39:56 +09:00
const document = await Connectors . get ( collection , documentId ) ;
2017-10-21 15:58:02 +09:00
Utils . performCheck ( this . check , context . currentUser , document , context ) ;
2017-07-03 10:54:10 +09:00
2018-02-17 11:17:25 +09:00
return await removeMutator ( {
2017-10-21 15:58:02 +09:00
collection ,
documentId : documentId ,
currentUser : context . currentUser ,
validate : true ,
context ,
} ) ;
} ,
2017-07-03 10:54:10 +09:00
2017-10-21 15:58:02 +09:00
} ,
}
} ;
const registerCollectionCallbacks = collectionName => {
collectionName = collectionName . toLowerCase ( ) ;
registerCallback ( {
name : ` ${ collectionName } .new.validate ` ,
arguments : [ { document : 'The document being inserted' } , { currentUser : 'The current user' } , { validationErrors : 'An object that can be used to accumulate validation errors' } ] ,
runs : 'sync' ,
returns : 'document' ,
description : ` Validate a document before insertion (can be skipped when inserting directly on server). `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .new.before ` ,
arguments : [ { document : 'The document being inserted' } , { currentUser : 'The current user' } ] ,
runs : 'sync' ,
returns : 'document' ,
description : ` Perform operations on a new document before it's inserted in the database. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .new.after ` ,
arguments : [ { document : 'The document being inserted' } , { currentUser : 'The current user' } ] ,
runs : 'sync' ,
returns : 'document' ,
description : ` Perform operations on a new document after it's inserted in the database but *before* the mutation returns it. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .new.async ` ,
arguments : [ { document : 'The document being inserted' } , { currentUser : 'The current user' } , { collection : 'The collection the document belongs to' } ] ,
runs : 'async' ,
returns : null ,
description : ` Perform operations on a new document after it's inserted in the database asynchronously. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .edit.validate ` ,
2017-11-08 10:06:01 +09:00
arguments : [ { modifier : 'The MongoDB modifier' } , { document : 'The document being edited' } , { currentUser : 'The current user' } , { validationErrors : 'An object that can be used to accumulate validation errors' } ] ,
2017-10-21 15:58:02 +09:00
runs : 'sync' ,
returns : 'modifier' ,
description : ` Validate a document before update (can be skipped when updating directly on server). `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .edit.before ` ,
2017-11-08 10:06:01 +09:00
arguments : [ { modifier : 'The MongoDB modifier' } , { document : 'The document being edited' } , { currentUser : 'The current user' } ] ,
2017-10-21 15:58:02 +09:00
runs : 'sync' ,
returns : 'modifier' ,
description : ` Perform operations on a document before it's updated in the database. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .edit.after ` ,
2017-11-08 10:06:01 +09:00
arguments : [ { modifier : 'The MongoDB modifier' } , { document : 'The document being edited' } , { currentUser : 'The current user' } ] ,
2017-10-21 15:58:02 +09:00
runs : 'sync' ,
returns : 'document' ,
description : ` Perform operations on a document after it's updated in the database but *before* the mutation returns it. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .edit.async ` ,
2017-12-18 09:57:17 +09:00
arguments : [ { newDocument : 'The document after the edit' } , { document : 'The document before the edit' } , { currentUser : 'The current user' } , { collection : 'The collection the document belongs to' } ] ,
2017-10-21 15:58:02 +09:00
runs : 'async' ,
returns : null ,
description : ` Perform operations on a document after it's updated in the database asynchronously. `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .remove.validate ` ,
arguments : [ { document : 'The document being removed' } , { currentUser : 'The current user' } , { validationErrors : 'An object that can be used to accumulate validation errors' } ] ,
runs : 'sync' ,
returns : 'document' ,
description : ` Validate a document before removal (can be skipped when removing directly on server). `
} ) ;
registerCallback ( {
name : ` ${ collectionName } .remove.before ` ,
arguments : [ { document : 'The document being removed' } , { currentUser : 'The current user' } ] ,
runs : 'sync' ,
returns : null ,
description : ` Perform operations on a document before it's removed from the database. `
} ) ;
registerCallback ( {
2017-11-08 10:06:01 +09:00
name : ` ${ collectionName } .remove.async ` ,
2017-10-21 15:58:02 +09:00
arguments : [ { document : 'The document being removed' } , { currentUser : 'The current user' } , { collection : 'The collection the document belongs to' } ] ,
runs : 'async' ,
returns : null ,
description : ` Perform operations on a document after it's removed from the database asynchronously. `
} ) ;
2018-03-03 23:11:33 +01:00
}