diff --git a/.meteor/versions b/.meteor/versions index 8ddf3ef54..2df69ce5c 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -1,6 +1,5 @@ accounts-base@1.2.15 accounts-password@1.3.4 -aldeed:collection2-core@2.0.0 allow-deny@1.0.5 autoupdate@1.3.12 babel-compiler@6.14.1 @@ -53,7 +52,6 @@ observe-sequence@1.0.16 ordered-dict@1.0.9 percolatestudio:synced-cron@1.1.0 promise@0.8.8 -raix:eventemitter@0.1.3 random@1.0.10 rate-limit@1.0.7 reactive-dict@1.1.8 @@ -71,7 +69,6 @@ srp@1.0.10 standard-minifier-css@1.3.4 standard-minifier-js@1.2.3 standard-minifiers@1.0.6 -tmeasday:check-npm-versions@0.3.1 tracker@1.1.2 ui@1.0.12 underscore@1.0.10 diff --git a/packages/example-movies/lib/modules/movies/schema.js b/packages/example-movies/lib/modules/movies/schema.js index 1ef60f0d9..072596003 100644 --- a/packages/example-movies/lib/modules/movies/schema.js +++ b/packages/example-movies/lib/modules/movies/schema.js @@ -10,10 +10,12 @@ const schema = { _id: { type: String, + optional: true, viewableBy: ['guests'], }, createdAt: { type: Date, + optional: true, viewableBy: ['guests'], autoValue: (documentOrModifier) => { if (documentOrModifier && !documentOrModifier.$set) return new Date() // if this is an insert, set createdAt to current timestamp @@ -21,6 +23,7 @@ const schema = { }, userId: { type: String, + optional: true, viewableBy: ['guests'], resolveAs: 'user: User', }, diff --git a/packages/vulcan-lib/lib/modules/collections.js b/packages/vulcan-lib/lib/modules/collections.js index 4277fe18f..f6dfa5f43 100644 --- a/packages/vulcan-lib/lib/modules/collections.js +++ b/packages/vulcan-lib/lib/modules/collections.js @@ -14,13 +14,13 @@ SimpleSchema.extendOptions([ * @summary replacement for Collection2's attachSchema * @class Mongo.Collection */ -// Mongo.Collection.prototype.attachSchema = function (schemaOrFields) { -// if (schemaOrFields instanceof SimpleSchema) { -// this.simpleSchema = () => schemaOrFields; -// } else { -// this.simpleSchema().extend(schemaOrFields) -// } -// } +Mongo.Collection.prototype.attachSchema = function (schemaOrFields) { + if (schemaOrFields instanceof SimpleSchema) { + this.simpleSchema = () => schemaOrFields; + } else { + this.simpleSchema().extend(schemaOrFields) + } +} /** * @summary Add an additional field (or an array of fields) to a schema. diff --git a/packages/vulcan-lib/lib/server/mutations.js b/packages/vulcan-lib/lib/server/mutations.js index 55383558f..b7821ce21 100644 --- a/packages/vulcan-lib/lib/server/mutations.js +++ b/packages/vulcan-lib/lib/server/mutations.js @@ -37,17 +37,20 @@ export const newMutation = ({ collection, document, currentUser, validate, conte // we don't want to modify the original document let newDocument = Object.assign({}, document); - + const collectionName = collection._name; const schema = collection.simpleSchema()._schema; // if document is not trusted, run validation steps if (validate) { + // validate document + collection.simpleSchema().validate(document); + // check that the current user has permission to insert each field - _.keys(newDocument).forEach(function (fieldName) { + _.keys(newDocument).forEach(fieldName => { var field = schema[fieldName]; - if (!context.Users.canInsertField (currentUser, field)) { + if (!field || !context.Users.canInsertField (currentUser, field)) { throw new Error(Utils.encodeIntlError({id: 'app.disallowed_property_detected', value: fieldName})); } }); @@ -55,11 +58,21 @@ export const newMutation = ({ collection, document, currentUser, validate, conte // run validation callbacks newDocument = runCallbacks(`${collectionName}.new.validate`, newDocument, currentUser); } - + // check if userId field is in the schema and add it to document if needed const userIdInSchema = Object.keys(schema).find(key => key === 'userId'); if (!!userIdInSchema && !newDocument.userId) newDocument.userId = currentUser._id; + // run autoValue step + _.keys(schema).forEach(fieldName => { + if (!newDocument[fieldName] && schema[fieldName].autoValue) { + const autoValue = schema[fieldName].autoValue(newDocument); + if (autoValue && typeof autoValue.$setOnInsert === 'undefined') { + newDocument[fieldName] = autoValue; + } + } + }); + // TODO: find that info in GraphQL mutations // if (Meteor.isServer && this.connection) { // post.userIP = this.connection.clientAddress; @@ -105,11 +118,14 @@ export const editMutation = ({ collection, documentId, set, unset, currentUser, // if document is not trusted, run validation steps if (validate) { + // validate modifiers + collection.simpleSchema().newContext().validate({$set: set, $unset: unset}, { modifier: true }); + // check that the current user has permission to edit each field const modifiedProperties = _.keys(set).concat(_.keys(unset)); modifiedProperties.forEach(function (fieldName) { var field = schema[fieldName]; - if (!context.Users.canEditField(currentUser, field, document)) { + if (!field || !context.Users.canEditField(currentUser, field, document)) { throw new Error(Utils.encodeIntlError({id: 'app.disallowed_property_detected', value: fieldName})); } }); @@ -118,11 +134,29 @@ export const editMutation = ({ collection, documentId, set, unset, currentUser, modifier = runCallbacks(`${collectionName}.edit.validate`, modifier, document, currentUser); } + // run autoValue step + _.keys(schema).forEach(fieldName => { + if (!modifier.$set[fieldName] && schema[fieldName].autoValue) { + const autoValue = schema[fieldName].autoValue(modifier); + if (autoValue && typeof autoValue.$setOnInsert === 'undefined') { + modifier.$set[fieldName] = autoValue; + } + } + }); + // run sync callbacks (on mongo modifier) modifier = runCallbacks(`${collectionName}.edit.sync`, modifier, document, currentUser); + // remove empty modifiers + if (_.isEmpty(modifier.$set)) { + delete modifier.$set; + } + if (_.isEmpty(modifier.$unset)) { + delete modifier.$unset; + } + // update document - collection.update(documentId, modifier); + collection.update(documentId, modifier, {removeEmptyStrings: false}); // get fresh copy of document from db const newDocument = collection.findOne(documentId); @@ -131,6 +165,7 @@ export const editMutation = ({ collection, documentId, set, unset, currentUser, runCallbacksAsync(`${collectionName}.edit.async`, newDocument, document, currentUser, collection); // console.log("// edit mutation finished") + // console.log(modifier) // console.log(newDocument) return newDocument; diff --git a/packages/vulcan-lib/package.js b/packages/vulcan-lib/package.js index 61de668a4..5f877df2e 100644 --- a/packages/vulcan-lib/package.js +++ b/packages/vulcan-lib/package.js @@ -29,7 +29,7 @@ Package.onUse(function (api) { // Third-party packages - 'aldeed:collection2-core@2.0.0', + // 'aldeed:collection2-core@2.0.0', 'meteorhacks:picker@1.0.3', 'percolatestudio:synced-cron@1.1.0', 'meteorhacks:inject-initial@1.0.4',