Merge pull request #924 from ParsePlatform/nlutsenko.hooks.acl

Make sure that ACLs propagate to before/after save hooks.
This commit is contained in:
Drew
2016-03-08 16:29:53 -08:00
2 changed files with 99 additions and 7 deletions

View File

@@ -4,6 +4,7 @@
var DatabaseAdapter = require('../src/DatabaseAdapter'); var DatabaseAdapter = require('../src/DatabaseAdapter');
var request = require('request'); var request = require('request');
const Parse = require("parse/node");
describe('miscellaneous', function() { describe('miscellaneous', function() {
it('create a GameScore object', function(done) { it('create a GameScore object', function(done) {
@@ -372,8 +373,8 @@ describe('miscellaneous', function() {
done(); 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) => { Parse.Cloud.run('echoKeys').then((result) => {
expect(result.applicationId).toEqual(Parse.applicationId); expect(result.applicationId).toEqual(Parse.applicationId);
expect(result.masterKey).toEqual(Parse.masterKey); expect(result.masterKey).toEqual(Parse.masterKey);
@@ -399,7 +400,7 @@ describe('miscellaneous', function() {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar'); expect(results[0]['foo']).toEqual('bar');
done(); done();
}).fail( err => { }).fail(err => {
fail(err); fail(err);
done(); done();
}) })
@@ -415,9 +416,9 @@ describe('miscellaneous', function() {
// Make sure the required mock for all tests is unset. // Make sure the required mock for all tests is unset.
Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore"); Parse.Cloud._removeHook("Triggers", "beforeSave", "GameScore");
done(); done();
}); });
it('object is set on create and update', done => { it('object is set on create and update', done => {
let triggerTime = 0; let triggerTime = 0;
// Register a mock beforeSave hook // Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', (req, res) => { Parse.Cloud.beforeSave('GameScore', (req, res) => {
@@ -683,7 +684,7 @@ describe('miscellaneous', function() {
// Make sure the checking has been triggered // Make sure the checking has been triggered
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
// Clear mock afterSave // Clear mock afterSave
Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore"); Parse.Cloud._removeHook("Triggers", "afterSave", "GameScore");
done(); done();
}, function(error) { }, function(error) {
console.error(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) => { it('test cloud function error handling', (done) => {
// Register a function which will fail // Register a function which will fail
Parse.Cloud.define('willFail', (req, res) => { Parse.Cloud.define('willFail', (req, res) => {

View File

@@ -6,6 +6,7 @@ var Parse = require('parse/node').Parse;
var Schema = require('./../Schema'); var Schema = require('./../Schema');
var transform = require('./../transform'); var transform = require('./../transform');
const deepcopy = require('deepcopy');
// options can contain: // options can contain:
// collectionPrefix: the string to put in front of every collection name. // 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 // one of the provided strings must provide the caller with
// write permissions. // write permissions.
DatabaseController.prototype.update = function(className, query, update, options) { 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) { var acceptor = function(schema) {
return schema.hasKeys(className, Object.keys(query)); return schema.hasKeys(className, Object.keys(query));
}; };
@@ -300,6 +304,9 @@ DatabaseController.prototype.destroy = function(className, query, options = {})
// Inserts an object into the database. // Inserts an object into the database.
// Returns a promise that resolves successfully iff the object saved. // Returns a promise that resolves successfully iff the object saved.
DatabaseController.prototype.create = function(className, object, options) { 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 schema;
var isMaster = !('acl' in options); var isMaster = !('acl' in options);
var aclGroup = options.acl || []; var aclGroup = options.acl || [];