diff --git a/spec/schemas.spec.js b/spec/schemas.spec.js index b3c8453f56..a5a8256d84 100644 --- a/spec/schemas.spec.js +++ b/spec/schemas.spec.js @@ -1667,7 +1667,48 @@ describe('schemas', () => { fail(JSON.stringify(error)); done(); }) - }) + }); + + it('unset field in beforeSave should not stop object creation', (done) => { + const hook = { + method: function(req, res) { + if (req.object.get('undesiredField')) { + req.object.unset('undesiredField'); + } + return res.success(); + } + }; + spyOn(hook, 'method').and.callThrough(); + Parse.Cloud.beforeSave('AnObject', hook.method); + setPermissionsOnClass('AnObject', { + get: {"*": true}, + find: {"*": true}, + create: {'*': true}, + update: {'*': true}, + delete: {'*': true}, + addField:{} + }).then(() => { + const obj = new Parse.Object('AnObject'); + obj.set('desiredField', 'createMe'); + return obj.save(null, {useMasterKey: true}); + }).then(() => { + const obj = new Parse.Object('AnObject'); + obj.set('desiredField', 'This value should be kept'); + obj.set('undesiredField', 'This value should be IGNORED'); + return obj.save(); + }).then(() => { + const query = new Parse.Query('AnObject'); + return query.find(); + }).then((results) => { + expect(results.length).toBe(2); + expect(results[0].has('desiredField')).toBe(true); + expect(results[1].has('desiredField')).toBe(true); + expect(results[0].has('undesiredField')).toBe(false); + expect(results[1].has('undesiredField')).toBe(false); + expect(hook.method).toHaveBeenCalled(); + done(); + }); + }); it('gives correct response when deleting a schema with CLPs (regression test #1919)', done => { new Parse.Object('MyClass').save({ data: 'foo'}) diff --git a/src/Controllers/DatabaseController.js b/src/Controllers/DatabaseController.js index 349ac09063..786e69ac05 100644 --- a/src/Controllers/DatabaseController.js +++ b/src/Controllers/DatabaseController.js @@ -622,8 +622,12 @@ class DatabaseController { const fields = Object.keys(object); const schemaFields = Object.keys(classSchema); const newKeys = fields.filter((field) => { + // Skip fields that are unset + if (object[field] && object[field].__op && object[field].__op === 'Delete') { + return false; + } return schemaFields.indexOf(field) < 0; - }) + }); if (newKeys.length > 0) { return schema.validatePermission(className, aclGroup, 'addField'); }