Cleanup update (#1590)
* destructuring in DB controller * deleteObject in db adapter * Turns out we can't have delete by object ID because of ACLs... * Fix tests * destructure acl * Don't reject with object
This commit is contained in:
@@ -169,11 +169,11 @@ describe('Parse.ACL', () => {
|
|||||||
ok(object.get("ACL"));
|
ok(object.get("ACL"));
|
||||||
|
|
||||||
// Start making requests by the public, which should all fail.
|
// Start making requests by the public, which should all fail.
|
||||||
Parse.User.logOut();
|
Parse.User.logOut()
|
||||||
|
.then(() => object.destroy())
|
||||||
// Delete
|
.then(() => {
|
||||||
object.destroy().then(() => {
|
|
||||||
fail('destroy should fail');
|
fail('destroy should fail');
|
||||||
|
done();
|
||||||
}, error => {
|
}, error => {
|
||||||
expect(error.code).toEqual(Parse.Error.OBJECT_NOT_FOUND);
|
expect(error.code).toEqual(Parse.Error.OBJECT_NOT_FOUND);
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ describe('miscellaneous', function() {
|
|||||||
expect(data.get('password')).toBeUndefined();
|
expect(data.get('password')).toBeUndefined();
|
||||||
done();
|
done();
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
console.log(err);
|
|
||||||
fail(err);
|
fail(err);
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -37,50 +37,44 @@ describe('Hooks', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should CRUD a function registration", (done) => {
|
it("should CRUD a function registration", (done) => {
|
||||||
// Create
|
// Create
|
||||||
Parse.Hooks.createFunction("My-Test-Function", "http://someurl").then((res) => {
|
Parse.Hooks.createFunction("My-Test-Function", "http://someurl")
|
||||||
expect(res.functionName).toBe("My-Test-Function");
|
.then(response => {
|
||||||
expect(res.url).toBe("http://someurl")
|
expect(response.functionName).toBe("My-Test-Function");
|
||||||
// Find
|
expect(response.url).toBe("http://someurl")
|
||||||
return Parse.Hooks.getFunction("My-Test-Function");
|
// Find
|
||||||
}, (err) => {
|
return Parse.Hooks.getFunction("My-Test-Function")
|
||||||
fail(err);
|
}).then(response => {
|
||||||
done();
|
expect(response.url).toBe("http://someurl");
|
||||||
}).then((res) => {
|
return Parse.Hooks.updateFunction("My-Test-Function", "http://anotherurl");
|
||||||
expect(res).not.toBe(null);
|
})
|
||||||
expect(res).not.toBe(undefined);
|
.then((res) => {
|
||||||
expect(res.url).toBe("http://someurl");
|
expect(res.functionName).toBe("My-Test-Function");
|
||||||
// delete
|
expect(res.url).toBe("http://anotherurl")
|
||||||
return Parse.Hooks.updateFunction("My-Test-Function", "http://anotherurl");
|
// delete
|
||||||
}, (err) => {
|
return Parse.Hooks.deleteFunction("My-Test-Function")
|
||||||
fail(err);
|
})
|
||||||
done();
|
.then((res) => {
|
||||||
}).then((res) => {
|
// Find again! but should be deleted
|
||||||
expect(res.functionName).toBe("My-Test-Function");
|
return Parse.Hooks.getFunction("My-Test-Function")
|
||||||
expect(res.url).toBe("http://anotherurl")
|
.then(res => {
|
||||||
|
fail("Failed to delete hook")
|
||||||
return Parse.Hooks.deleteFunction("My-Test-Function");
|
fail(res)
|
||||||
}, (err) => {
|
done();
|
||||||
fail(err);
|
return Promise.resolve();
|
||||||
done();
|
}, (err) => {
|
||||||
}).then((res) => {
|
expect(err.code).toBe(143);
|
||||||
// Find again! but should be deleted
|
expect(err.error).toBe("no function named: My-Test-Function is defined")
|
||||||
return Parse.Hooks.getFunction("My-Test-Function");
|
done();
|
||||||
}, (err) => {
|
return Promise.resolve();
|
||||||
fail(err);
|
})
|
||||||
done();
|
})
|
||||||
}).then((res) => {
|
.catch(error => {
|
||||||
fail("Should not succeed")
|
fail(error);
|
||||||
done();
|
done();
|
||||||
}, (err) => {
|
})
|
||||||
expect(err).not.toBe(null);
|
});
|
||||||
expect(err).not.toBe(undefined);
|
|
||||||
expect(err.code).toBe(143);
|
|
||||||
expect(err.error).toBe("no function named: My-Test-Function is defined")
|
|
||||||
done();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should CRUD a trigger registration", (done) => {
|
it("should CRUD a trigger registration", (done) => {
|
||||||
// Create
|
// Create
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should work with write', (done) => {
|
it('should work with write', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -107,7 +107,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should let a proper user find', (done) => {
|
it('should let a proper user find', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -137,7 +137,7 @@ describe('Pointer Permissions', () => {
|
|||||||
let q = new Parse.Query('AnObject');
|
let q = new Parse.Query('AnObject');
|
||||||
return q.find();
|
return q.find();
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
expect(res.length).toBe(0);
|
expect(res.length).toBe(0);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return Parse.User.logIn('user2', 'password');
|
return Parse.User.logIn('user2', 'password');
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
@@ -167,7 +167,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow creating objects', (done) => {
|
it('should not allow creating objects', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -193,7 +193,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle multiple writeUserFields', (done) => {
|
it('should handle multiple writeUserFields', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -235,7 +235,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prevent creating pointer permission on missing field', (done) => {
|
it('should prevent creating pointer permission on missing field', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
config.database.loadSchema().then((schema) => {
|
config.database.loadSchema().then((schema) => {
|
||||||
@@ -248,7 +248,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prevent creating pointer permission on bad field', (done) => {
|
it('should prevent creating pointer permission on bad field', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
config.database.loadSchema().then((schema) => {
|
config.database.loadSchema().then((schema) => {
|
||||||
@@ -261,7 +261,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should prevent creating pointer permission on bad field', (done) => {
|
it('should prevent creating pointer permission on bad field', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let object = new Parse.Object('AnObject');
|
let object = new Parse.Object('AnObject');
|
||||||
@@ -278,14 +278,14 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL write (PP Locked)', (done) => {
|
it('tests CLP / Pointer Perms / ACL write (PP Locked)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
CLP: update open ({"*": true})
|
CLP: update open ({"*": true})
|
||||||
PointerPerm: "owner"
|
PointerPerm: "owner"
|
||||||
ACL: logged in user has access
|
ACL: logged in user has access
|
||||||
|
|
||||||
The owner is another user than the ACL
|
The owner is another user than the ACL
|
||||||
*/
|
*/
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
@@ -325,7 +325,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL write (ACL Locked)', (done) => {
|
it('tests CLP / Pointer Perms / ACL write (ACL Locked)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
@@ -370,7 +370,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL write (ACL/PP OK)', (done) => {
|
it('tests CLP / Pointer Perms / ACL write (ACL/PP OK)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
@@ -415,7 +415,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL read (PP locked)', (done) => {
|
it('tests CLP / Pointer Perms / ACL read (PP locked)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
@@ -462,7 +462,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => {
|
it('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
@@ -509,7 +509,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => {
|
it('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => {
|
||||||
/*
|
/*
|
||||||
tests:
|
tests:
|
||||||
@@ -554,7 +554,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should let master key find objects', (done) => {
|
it('should let master key find objects', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -569,7 +569,7 @@ describe('Pointer Permissions', () => {
|
|||||||
let q = new Parse.Query('AnObject');
|
let q = new Parse.Query('AnObject');
|
||||||
return q.find();
|
return q.find();
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
expect(err.code).toBe(101);
|
expect(err.code).toBe(101);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -584,7 +584,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should let master key get objects', (done) => {
|
it('should let master key get objects', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -599,7 +599,7 @@ describe('Pointer Permissions', () => {
|
|||||||
let q = new Parse.Query('AnObject');
|
let q = new Parse.Query('AnObject');
|
||||||
return q.get(object.id);
|
return q.get(object.id);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
expect(err.code).toBe(101);
|
expect(err.code).toBe(101);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -615,8 +615,8 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should let master key update objects', (done) => {
|
it('should let master key update objects', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -630,7 +630,7 @@ describe('Pointer Permissions', () => {
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
return object.save({'hello': 'bar'});
|
return object.save({'hello': 'bar'});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
expect(err.code).toBe(101);
|
expect(err.code).toBe(101);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -644,7 +644,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should let master key delete objects', (done) => {
|
it('should let master key delete objects', (done) => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
let user = new Parse.User();
|
let user = new Parse.User();
|
||||||
@@ -658,7 +658,7 @@ describe('Pointer Permissions', () => {
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
return object.destroy();
|
return object.destroy();
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
fail();
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
expect(err.code).toBe(101);
|
expect(err.code).toBe(101);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -671,7 +671,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail with invalid pointer perms', () => {
|
it('should fail with invalid pointer perms', () => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
config.database.loadSchema().then((schema) => {
|
config.database.loadSchema().then((schema) => {
|
||||||
@@ -682,7 +682,7 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail with invalid pointer perms', () => {
|
it('should fail with invalid pointer perms', () => {
|
||||||
let config = new Config(Parse.applicationId);
|
let config = new Config(Parse.applicationId);
|
||||||
config.database.loadSchema().then((schema) => {
|
config.database.loadSchema().then((schema) => {
|
||||||
@@ -693,5 +693,5 @@ describe('Pointer Permissions', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -121,39 +121,39 @@ describe('SchemaController', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('class-level permissions test get', (done) => {
|
it('class-level permissions test get', (done) => {
|
||||||
var user;
|
|
||||||
var obj;
|
var obj;
|
||||||
createTestUser().then((u) => {
|
createTestUser()
|
||||||
user = u;
|
.then(user => {
|
||||||
return config.database.loadSchema();
|
console.log(user);
|
||||||
}).then((schema) => {
|
return config.database.loadSchema()
|
||||||
// Just to create a valid class
|
// Create a valid class
|
||||||
return schema.validateObject('Stuff', {foo: 'bar'});
|
.then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
|
||||||
}).then((schema) => {
|
.then(schema => {
|
||||||
var find = {};
|
var find = {};
|
||||||
var get = {};
|
var get = {};
|
||||||
get[user.id] = true;
|
get[user.id] = true;
|
||||||
return schema.setPermissions('Stuff', {
|
return schema.setPermissions('Stuff', {
|
||||||
'find': find,
|
'find': find,
|
||||||
'get': get
|
'get': get
|
||||||
});
|
});
|
||||||
}).then((schema) => {
|
}).then((schema) => {
|
||||||
obj = new Parse.Object('Stuff');
|
obj = new Parse.Object('Stuff');
|
||||||
obj.set('foo', 'bar');
|
obj.set('foo', 'bar');
|
||||||
return obj.save();
|
return obj.save();
|
||||||
}).then((o) => {
|
}).then((o) => {
|
||||||
obj = o;
|
obj = o;
|
||||||
var query = new Parse.Query('Stuff');
|
var query = new Parse.Query('Stuff');
|
||||||
return query.find();
|
return query.find();
|
||||||
}).then((results) => {
|
}).then((results) => {
|
||||||
fail('Class permissions should have rejected this query.');
|
fail('Class permissions should have rejected this query.');
|
||||||
done();
|
|
||||||
}, (e) => {
|
|
||||||
var query = new Parse.Query('Stuff');
|
|
||||||
return query.get(obj.id).then((o) => {
|
|
||||||
done();
|
done();
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
fail('Class permissions should have allowed this get query');
|
var query = new Parse.Query('Stuff');
|
||||||
|
return query.get(obj.id).then((o) => {
|
||||||
|
done();
|
||||||
|
}, (e) => {
|
||||||
|
fail('Class permissions should have allowed this get query');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ beforeEach(function(done) {
|
|||||||
Parse.initialize('test', 'test', 'test');
|
Parse.initialize('test', 'test', 'test');
|
||||||
Parse.serverURL = 'http://localhost:' + port + '/1';
|
Parse.serverURL = 'http://localhost:' + port + '/1';
|
||||||
Parse.User.enableUnsafeCurrentUser();
|
Parse.User.enableUnsafeCurrentUser();
|
||||||
done();
|
return TestUtils.destroyAllDataPermanently().then(done, fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
|
|||||||
@@ -159,6 +159,37 @@ export class MongoStorageAdapter {
|
|||||||
.then(collection => collection.insertOne(mongoObject));
|
.then(collection => collection.insertOne(mongoObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all objects that match the given parse query. Parse Query should be in Parse Format.
|
||||||
|
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
|
||||||
|
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
|
||||||
|
|
||||||
|
// Currently accepts the acl, schemaController, validate
|
||||||
|
// for lecacy reasons, Parse Server should later integrate acl into the query. Database adapters
|
||||||
|
// shouldn't know about acl.
|
||||||
|
deleteObjectsByQuery(className, query, acl, schemaController, validate) {
|
||||||
|
return this.adaptiveCollection(className)
|
||||||
|
.then(collection => {
|
||||||
|
let mongoWhere = transform.transformWhere(
|
||||||
|
schemaController,
|
||||||
|
className,
|
||||||
|
query,
|
||||||
|
{ validate }
|
||||||
|
);
|
||||||
|
if (acl) {
|
||||||
|
mongoWhere = transform.addWriteACL(mongoWhere, acl);
|
||||||
|
}
|
||||||
|
return collection.deleteMany(mongoWhere)
|
||||||
|
})
|
||||||
|
.then(({ result }) => {
|
||||||
|
if (result.n === 0) {
|
||||||
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}, error => {
|
||||||
|
throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Database adapter error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
get transform() {
|
get transform() {
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,8 +195,7 @@ function transformWhere(schema, className, restWhere, options = {validate: true}
|
|||||||
let transformKeyOptions = {query: true};
|
let transformKeyOptions = {query: true};
|
||||||
transformKeyOptions.validate = options.validate;
|
transformKeyOptions.validate = options.validate;
|
||||||
for (let restKey in restWhere) {
|
for (let restKey in restWhere) {
|
||||||
let out = transformKeyValue(schema, className, restKey, restWhere[restKey],
|
let out = transformKeyValue(schema, className, restKey, restWhere[restKey], transformKeyOptions);
|
||||||
transformKeyOptions);
|
|
||||||
mongoWhere[out.key] = out.value;
|
mongoWhere[out.key] = out.value;
|
||||||
}
|
}
|
||||||
return mongoWhere;
|
return mongoWhere;
|
||||||
@@ -333,8 +332,7 @@ function transformUpdate(schema, className, restUpdate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (var restKey in restUpdate) {
|
for (var restKey in restUpdate) {
|
||||||
var out = transformKeyValue(schema, className, restKey, restUpdate[restKey],
|
var out = transformKeyValue(schema, className, restKey, restUpdate[restKey], {update: true});
|
||||||
{update: true});
|
|
||||||
|
|
||||||
// If the output value is an object with any $ keys, it's an
|
// If the output value is an object with any $ keys, it's an
|
||||||
// operator that needs to be lifted onto the top level update
|
// operator that needs to be lifted onto the top level update
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ DatabaseController.prototype.redirectClassNameForKey = function(className, key)
|
|||||||
// Returns a promise that resolves to the new schema.
|
// Returns a promise that resolves to the new schema.
|
||||||
// This does not update this.schema, because in a situation like a
|
// This does not update this.schema, because in a situation like a
|
||||||
// batch request, that could confuse other users of the schema.
|
// batch request, that could confuse other users of the schema.
|
||||||
DatabaseController.prototype.validateObject = function(className, object, query, options) {
|
DatabaseController.prototype.validateObject = function(className, object, query, { acl }) {
|
||||||
let schema;
|
let schema;
|
||||||
let isMaster = !('acl' in options);
|
let isMaster = acl === undefined;
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = acl || [];
|
||||||
return this.loadSchema().then(s => {
|
return this.loadSchema().then(s => {
|
||||||
schema = s;
|
schema = s;
|
||||||
if (isMaster) {
|
if (isMaster) {
|
||||||
@@ -131,14 +131,18 @@ DatabaseController.prototype.untransformObject = function(
|
|||||||
// acl: a list of strings. If the object to be updated has an ACL,
|
// acl: a list of strings. If the object to be updated has an ACL,
|
||||||
// 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, {
|
||||||
|
acl,
|
||||||
|
many,
|
||||||
|
upsert,
|
||||||
|
} = {}) {
|
||||||
|
|
||||||
const originalUpdate = update;
|
const originalUpdate = update;
|
||||||
// Make a copy of the object, so we don't mutate the incoming data.
|
// Make a copy of the object, so we don't mutate the incoming data.
|
||||||
update = deepcopy(update);
|
update = deepcopy(update);
|
||||||
|
|
||||||
var isMaster = !('acl' in options);
|
var isMaster = acl === undefined;
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = acl || [];
|
||||||
var mongoUpdate, schema;
|
var mongoUpdate, schema;
|
||||||
return this.loadSchema()
|
return this.loadSchema()
|
||||||
.then(s => {
|
.then(s => {
|
||||||
@@ -152,19 +156,19 @@ DatabaseController.prototype.update = function(className, query, update, options
|
|||||||
.then(() => this.adapter.adaptiveCollection(className))
|
.then(() => this.adapter.adaptiveCollection(className))
|
||||||
.then(collection => {
|
.then(collection => {
|
||||||
if (!isMaster) {
|
if (!isMaster) {
|
||||||
query = this.addPointerPermissions(schema, className, 'update', query, aclGroup);
|
query = this.addPointerPermissions(schema, className, 'update', query, aclGroup);
|
||||||
}
|
}
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
var mongoWhere = this.transform.transformWhere(schema, className, query, {validate: !this.skipValidation});
|
var mongoWhere = this.transform.transformWhere(schema, className, query, {validate: !this.skipValidation});
|
||||||
if (options.acl) {
|
if (acl) {
|
||||||
mongoWhere = this.transform.addWriteACL(mongoWhere, options.acl);
|
mongoWhere = this.transform.addWriteACL(mongoWhere, acl);
|
||||||
}
|
}
|
||||||
mongoUpdate = this.transform.transformUpdate(schema, className, update, {validate: !this.skipValidation});
|
mongoUpdate = this.transform.transformUpdate(schema, className, update, {validate: !this.skipValidation});
|
||||||
if (options.many) {
|
if (many) {
|
||||||
return collection.updateMany(mongoWhere, mongoUpdate);
|
return collection.updateMany(mongoWhere, mongoUpdate);
|
||||||
}else if (options.upsert) {
|
} else if (upsert) {
|
||||||
return collection.upsertOne(mongoWhere, mongoUpdate);
|
return collection.upsertOne(mongoWhere, mongoUpdate);
|
||||||
} else {
|
} else {
|
||||||
return collection.findOneAndUpdate(mongoWhere, mongoUpdate);
|
return collection.findOneAndUpdate(mongoWhere, mongoUpdate);
|
||||||
@@ -203,9 +207,7 @@ function sanitizeDatabaseResult(originalObject, result) {
|
|||||||
// Returns a promise that resolves successfully when these are
|
// Returns a promise that resolves successfully when these are
|
||||||
// processed.
|
// processed.
|
||||||
// This mutates update.
|
// This mutates update.
|
||||||
DatabaseController.prototype.handleRelationUpdates = function(className,
|
DatabaseController.prototype.handleRelationUpdates = function(className, objectId, update) {
|
||||||
objectId,
|
|
||||||
update) {
|
|
||||||
var pending = [];
|
var pending = [];
|
||||||
var deleteMe = [];
|
var deleteMe = [];
|
||||||
objectId = update.objectId || objectId;
|
objectId = update.objectId || objectId;
|
||||||
@@ -282,51 +284,42 @@ DatabaseController.prototype.removeRelation = function(key, fromClassName, fromI
|
|||||||
// acl: a list of strings. If the object to be updated has an ACL,
|
// acl: a list of strings. If the object to be updated has an ACL,
|
||||||
// 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.destroy = function(className, query, options = {}) {
|
DatabaseController.prototype.destroy = function(className, query, { acl } = {}) {
|
||||||
var isMaster = !('acl' in options);
|
const isMaster = acl === undefined;
|
||||||
var aclGroup = options.acl || [];
|
const aclGroup = acl || [];
|
||||||
|
|
||||||
var schema;
|
|
||||||
return this.loadSchema()
|
return this.loadSchema()
|
||||||
.then(s => {
|
.then(schemaController => {
|
||||||
schema = s;
|
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'delete'))
|
||||||
|
.then(() => {
|
||||||
if (!isMaster) {
|
if (!isMaster) {
|
||||||
return schema.validatePermission(className, aclGroup, 'delete');
|
query = this.addPointerPermissions(schemaController, className, 'delete', query, aclGroup);
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
})
|
|
||||||
.then(() => this.adapter.adaptiveCollection(className))
|
|
||||||
.then(collection => {
|
|
||||||
if (!isMaster) {
|
|
||||||
query = this.addPointerPermissions(schema, className, 'delete', query, aclGroup);
|
|
||||||
if (!query) {
|
if (!query) {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mongoWhere = this.transform.transformWhere(schema, className, query, {validate: !this.skipValidation});
|
// delete by query
|
||||||
if (options.acl) {
|
return this.adapter.deleteObjectsByQuery(className, query, acl, schemaController, !this.skipValidation)
|
||||||
mongoWhere = this.transform.addWriteACL(mongoWhere, options.acl);
|
.catch(error => {
|
||||||
}
|
// When deleting sessions while changing passwords, don't throw an error if they don't have any sessions.
|
||||||
return collection.deleteMany(mongoWhere);
|
if (className === "_Session" && error.code === Parse.Error.OBJECT_NOT_FOUND) {
|
||||||
})
|
return Promise.resolve({});
|
||||||
.then(resp => {
|
}
|
||||||
//Check _Session to avoid changing password failed without any session.
|
throw error;
|
||||||
// TODO: @nlutsenko Stop relying on `result.n`
|
});
|
||||||
if (resp.result.n === 0 && className !== "_Session") {
|
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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, { acl } = {}) {
|
||||||
// Make a copy of the object, so we don't mutate the incoming data.
|
// Make a copy of the object, so we don't mutate the incoming data.
|
||||||
let originalObject = object;
|
let originalObject = object;
|
||||||
object = deepcopy(object);
|
object = deepcopy(object);
|
||||||
|
|
||||||
var isMaster = !('acl' in options);
|
var isMaster = acl === undefined;
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = acl || [];
|
||||||
|
|
||||||
return this.validateClassName(className)
|
return this.validateClassName(className)
|
||||||
.then(() => this.loadSchema())
|
.then(() => this.loadSchema())
|
||||||
@@ -570,27 +563,33 @@ DatabaseController.prototype.addNotInObjectIdsIds = function(ids = null, query)
|
|||||||
// TODO: make userIds not needed here. The db adapter shouldn't know
|
// TODO: make userIds not needed here. The db adapter shouldn't know
|
||||||
// anything about users, ideally. Then, improve the format of the ACL
|
// anything about users, ideally. Then, improve the format of the ACL
|
||||||
// arg to work like the others.
|
// arg to work like the others.
|
||||||
DatabaseController.prototype.find = function(className, query, options = {}) {
|
DatabaseController.prototype.find = function(className, query, {
|
||||||
|
skip,
|
||||||
|
limit,
|
||||||
|
acl,
|
||||||
|
sort,
|
||||||
|
count,
|
||||||
|
} = {}) {
|
||||||
let mongoOptions = {};
|
let mongoOptions = {};
|
||||||
if (options.skip) {
|
if (skip) {
|
||||||
mongoOptions.skip = options.skip;
|
mongoOptions.skip = skip;
|
||||||
}
|
}
|
||||||
if (options.limit) {
|
if (limit) {
|
||||||
mongoOptions.limit = options.limit;
|
mongoOptions.limit = limit;
|
||||||
}
|
}
|
||||||
let isMaster = !('acl' in options);
|
let isMaster = acl === undefined;
|
||||||
let aclGroup = options.acl || [];
|
let aclGroup = acl || [];
|
||||||
let schema = null;
|
let schema = null;
|
||||||
let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ?
|
let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ?
|
||||||
'get' :
|
'get' :
|
||||||
'find';
|
'find';
|
||||||
return this.loadSchema().then(s => {
|
return this.loadSchema().then(s => {
|
||||||
schema = s;
|
schema = s;
|
||||||
if (options.sort) {
|
if (sort) {
|
||||||
mongoOptions.sort = {};
|
mongoOptions.sort = {};
|
||||||
for (let key in options.sort) {
|
for (let key in sort) {
|
||||||
let mongoKey = this.transform.transformKey(schema, className, key);
|
let mongoKey = this.transform.transformKey(schema, className, key);
|
||||||
mongoOptions.sort[mongoKey] = options.sort[key];
|
mongoOptions.sort[mongoKey] = sort[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,7 +603,7 @@ DatabaseController.prototype.find = function(className, query, options = {}) {
|
|||||||
.then(() => this.adapter.adaptiveCollection(className))
|
.then(() => this.adapter.adaptiveCollection(className))
|
||||||
.then(collection => {
|
.then(collection => {
|
||||||
if (!isMaster) {
|
if (!isMaster) {
|
||||||
query = this.addPointerPermissions(schema, className, op, query, aclGroup);
|
query = this.addPointerPermissions(schema, className, op, query, aclGroup);
|
||||||
}
|
}
|
||||||
if (!query) {
|
if (!query) {
|
||||||
if (op == 'get') {
|
if (op == 'get') {
|
||||||
@@ -618,7 +617,7 @@ DatabaseController.prototype.find = function(className, query, options = {}) {
|
|||||||
if (!isMaster) {
|
if (!isMaster) {
|
||||||
mongoWhere = this.transform.addReadACL(mongoWhere, aclGroup);
|
mongoWhere = this.transform.addReadACL(mongoWhere, aclGroup);
|
||||||
}
|
}
|
||||||
if (options.count) {
|
if (count) {
|
||||||
delete mongoOptions.limit;
|
delete mongoOptions.limit;
|
||||||
return collection.count(mongoWhere, mongoOptions);
|
return collection.count(mongoWhere, mongoOptions);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
var request = require("request");
|
var request = require("request");
|
||||||
const send = function(method, path, body) {
|
const send = function(method, path, body) {
|
||||||
|
|
||||||
var Parse = require("parse/node").Parse;
|
var Parse = require("parse/node").Parse;
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
@@ -12,7 +12,7 @@ const send = function(method, path, body) {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (body) {
|
if (body) {
|
||||||
if (typeof body == "object") {
|
if (typeof body == "object") {
|
||||||
options.body = JSON.stringify(body);
|
options.body = JSON.stringify(body);
|
||||||
@@ -20,7 +20,7 @@ const send = function(method, path, body) {
|
|||||||
options.body = body;
|
options.body = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var promise = new Parse.Promise();
|
var promise = new Parse.Promise();
|
||||||
request(options, function(err, response, body){
|
request(options, function(err, response, body){
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user