diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index b4f7f8e024..bd29bcc791 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -4,6 +4,7 @@ var DatabaseAdapter = require('../src/DatabaseAdapter'); var request = require('request'); +const Parse = require("parse/node"); describe('miscellaneous', function() { it('create a GameScore object', function(done) { @@ -372,8 +373,8 @@ describe('miscellaneous', function() { done(); }); }); - - it('test cloud function shoud echo keys', function(done) { + + it('test cloud function should echo keys', function(done) { Parse.Cloud.run('echoKeys').then((result) => { expect(result.applicationId).toEqual(Parse.applicationId); expect(result.masterKey).toEqual(Parse.masterKey); @@ -399,7 +400,7 @@ describe('miscellaneous', function() { expect(results.length).toEqual(1); expect(results[0]['foo']).toEqual('bar'); done(); - }).fail( err => { + }).fail(err => { fail(err); done(); }) @@ -415,9 +416,9 @@ describe('miscellaneous', function() { // Make sure the required mock for all tests is unset. Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); done(); - }); - - it('object is set on create and update', done => { + }); + + it('object is set on create and update', done => { let triggerTime = 0; // Register a mock beforeSave hook Parse.Cloud.beforeSave('GameScore', (req, res) => { @@ -683,7 +684,7 @@ describe('miscellaneous', function() { // Make sure the checking has been triggered expect(triggerTime).toBe(2); // Clear mock afterSave - Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); + Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); done(); }, function(error) { console.error(error); @@ -732,6 +733,90 @@ describe('miscellaneous', function() { }); }); + it('beforeSave receives ACL', done => { + let triggerTime = 0; + // Register a mock beforeSave hook + Parse.Cloud.beforeSave('GameScore', function(req, res) { + let object = req.object; + if (triggerTime == 0) { + let acl = object.getACL(); + expect(acl.getPublicReadAccess()).toBeTruthy(); + expect(acl.getPublicWriteAccess()).toBeTruthy(); + } else if (triggerTime == 1) { + let acl = object.getACL(); + expect(acl.getPublicReadAccess()).toBeFalsy(); + expect(acl.getPublicWriteAccess()).toBeTruthy(); + } else { + res.error(); + } + triggerTime++; + res.success(); + }); + + let obj = new Parse.Object('GameScore'); + let acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + obj.setACL(acl); + obj.save().then(() => { + acl.setPublicReadAccess(false); + obj.setACL(acl); + return obj.save(); + }).then(() => { + // Make sure the checking has been triggered + expect(triggerTime).toBe(2); + // Clear mock afterSave + Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); + done(); + }, error => { + console.error(error); + fail(error); + done(); + }); + }); + + it('afterSave receives ACL', done => { + let triggerTime = 0; + // Register a mock beforeSave hook + Parse.Cloud.afterSave('GameScore', function(req, res) { + let object = req.object; + if (triggerTime == 0) { + let acl = object.getACL(); + expect(acl.getPublicReadAccess()).toBeTruthy(); + expect(acl.getPublicWriteAccess()).toBeTruthy(); + } else if (triggerTime == 1) { + let acl = object.getACL(); + expect(acl.getPublicReadAccess()).toBeFalsy(); + expect(acl.getPublicWriteAccess()).toBeTruthy(); + } else { + res.error(); + } + triggerTime++; + res.success(); + }); + + let obj = new Parse.Object('GameScore'); + let acl = new Parse.ACL(); + acl.setPublicReadAccess(true); + acl.setPublicWriteAccess(true); + obj.setACL(acl); + obj.save().then(() => { + acl.setPublicReadAccess(false); + obj.setACL(acl); + return obj.save(); + }).then(() => { + // Make sure the checking has been triggered + expect(triggerTime).toBe(2); + // Clear mock afterSave + Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); + done(); + }, error => { + console.error(error); + fail(error); + done(); + }); + }); + it('test cloud function error handling', (done) => { // Register a function which will fail Parse.Cloud.define('willFail', (req, res) => { diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index f261db5624..80eea63bb6 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -6,6 +6,7 @@ var Parse = require('parse/node').Parse; var Schema = require('./../Schema'); var transform = require('./../transform'); +const deepcopy = require('deepcopy'); // options can contain: // collectionPrefix: the string to put in front of every collection name. @@ -130,6 +131,9 @@ DatabaseController.prototype.untransformObject = function( // one of the provided strings must provide the caller with // write permissions. DatabaseController.prototype.update = function(className, query, update, options) { + // Make a copy of the object, so we don't mutate the incoming data. + update = deepcopy(update); + var acceptor = function(schema) { return schema.hasKeys(className, Object.keys(query)); }; @@ -300,6 +304,9 @@ DatabaseController.prototype.destroy = function(className, query, options = {}) // Inserts an object into the database. // Returns a promise that resolves successfully iff the object saved. DatabaseController.prototype.create = function(className, object, options) { + // Make a copy of the object, so we don't mutate the incoming data. + object = deepcopy(object); + var schema; var isMaster = !('acl' in options); var aclGroup = options.acl || [];