Merge pull request #1644 from drew-gross/refactor-query-transform
Break dependency of deleteObjectsByQuery on schemaController
This commit is contained in:
@@ -106,7 +106,7 @@ describe('parseObjectToMongoObjectForCreate', () => {
|
|||||||
|
|
||||||
describe('transformWhere', () => {
|
describe('transformWhere', () => {
|
||||||
it('objectId', (done) => {
|
it('objectId', (done) => {
|
||||||
var out = transform.transformWhere(dummySchema, null, {objectId: 'foo'});
|
var out = transform.transformWhere(null, {objectId: 'foo'});
|
||||||
expect(out._id).toEqual('foo');
|
expect(out._id).toEqual('foo');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -115,7 +115,7 @@ describe('transformWhere', () => {
|
|||||||
var input = {
|
var input = {
|
||||||
objectId: {'$in': ['one', 'two', 'three']},
|
objectId: {'$in': ['one', 'two', 'three']},
|
||||||
};
|
};
|
||||||
var output = transform.transformWhere(dummySchema, null, input);
|
var output = transform.transformWhere(null, input);
|
||||||
jequal(input.objectId, output._id);
|
jequal(input.objectId, output._id);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ describe('Hooks', () => {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should CRUD a trigger registration", (done) => {
|
it("should CRUD a trigger registration", (done) => {
|
||||||
// Create
|
// Create
|
||||||
Parse.Hooks.createTrigger("MyClass","beforeDelete", "http://someurl").then((res) => {
|
Parse.Hooks.createTrigger("MyClass","beforeDelete", "http://someurl").then((res) => {
|
||||||
expect(res.className).toBe("MyClass");
|
expect(res.className).toBe("MyClass");
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ describe('SchemaController', () => {
|
|||||||
var obj;
|
var obj;
|
||||||
createTestUser()
|
createTestUser()
|
||||||
.then(user => {
|
.then(user => {
|
||||||
console.log(user);
|
|
||||||
return config.database.loadSchema()
|
return config.database.loadSchema()
|
||||||
// Create a valid class
|
// Create a valid class
|
||||||
.then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
|
.then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
|
||||||
|
|||||||
@@ -173,16 +173,11 @@ export class MongoStorageAdapter {
|
|||||||
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
|
// 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.
|
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
|
||||||
|
|
||||||
// Currently accepts the schemaController, and validate for lecacy reasons
|
// Currently accepts validate for legacy reasons. Currently accepts the schema, that may not actually be necessary.
|
||||||
deleteObjectsByQuery(className, query, schemaController, validate) {
|
deleteObjectsByQuery(className, query, validate, schema) {
|
||||||
return this.adaptiveCollection(className)
|
return this.adaptiveCollection(className)
|
||||||
.then(collection => {
|
.then(collection => {
|
||||||
let mongoWhere = transform.transformWhere(
|
let mongoWhere = transform.transformWhere(className, query, { validate }, schema);
|
||||||
schemaController,
|
|
||||||
className,
|
|
||||||
query,
|
|
||||||
{ validate }
|
|
||||||
);
|
|
||||||
return collection.deleteMany(mongoWhere)
|
return collection.deleteMany(mongoWhere)
|
||||||
})
|
})
|
||||||
.then(({ result }) => {
|
.then(({ result }) => {
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ var Parse = require('parse/node').Parse;
|
|||||||
//
|
//
|
||||||
// There are several options that can help transform:
|
// There are several options that can help transform:
|
||||||
//
|
//
|
||||||
// query: true indicates that query constraints like $lt are allowed in
|
|
||||||
// the value.
|
|
||||||
//
|
|
||||||
// update: true indicates that __op operators like Add and Delete
|
// update: true indicates that __op operators like Add and Delete
|
||||||
// in the value are converted to a mongo update form. Otherwise they are
|
// in the value are converted to a mongo update form. Otherwise they are
|
||||||
// converted to static data.
|
// converted to static data.
|
||||||
@@ -21,10 +18,9 @@ var Parse = require('parse/node').Parse;
|
|||||||
// validate: true indicates that key names are to be validated.
|
// validate: true indicates that key names are to be validated.
|
||||||
//
|
//
|
||||||
// Returns an object with {key: key, value: value}.
|
// Returns an object with {key: key, value: value}.
|
||||||
export function transformKeyValue(schema, className, restKey, restValue, {
|
function transformKeyValue(schema, className, restKey, restValue, {
|
||||||
inArray,
|
inArray,
|
||||||
inObject,
|
inObject,
|
||||||
query,
|
|
||||||
update,
|
update,
|
||||||
validate,
|
validate,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@@ -66,47 +62,17 @@ export function transformKeyValue(schema, className, restKey, restValue, {
|
|||||||
return {key: key, value: restValue};
|
return {key: key, value: restValue};
|
||||||
break;
|
break;
|
||||||
case '$or':
|
case '$or':
|
||||||
if (!query) {
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'you can only use $or in queries');
|
||||||
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
|
|
||||||
'you can only use $or in queries');
|
|
||||||
}
|
|
||||||
if (!(restValue instanceof Array)) {
|
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY,
|
|
||||||
'bad $or format - use an array value');
|
|
||||||
}
|
|
||||||
var mongoSubqueries = restValue.map((s) => {
|
|
||||||
return transformWhere(schema, className, s);
|
|
||||||
});
|
|
||||||
return {key: '$or', value: mongoSubqueries};
|
|
||||||
case '$and':
|
case '$and':
|
||||||
if (!query) {
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'you can only use $and in queries');
|
||||||
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
|
|
||||||
'you can only use $and in queries');
|
|
||||||
}
|
|
||||||
if (!(restValue instanceof Array)) {
|
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY,
|
|
||||||
'bad $and format - use an array value');
|
|
||||||
}
|
|
||||||
var mongoSubqueries = restValue.map((s) => {
|
|
||||||
return transformWhere(schema, className, s);
|
|
||||||
});
|
|
||||||
return {key: '$and', value: mongoSubqueries};
|
|
||||||
default:
|
default:
|
||||||
// Other auth data
|
// Other auth data
|
||||||
var authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
|
var authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
|
||||||
if (authDataMatch) {
|
if (authDataMatch) {
|
||||||
if (query) {
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'can only query on ' + key);
|
||||||
var provider = authDataMatch[1];
|
}
|
||||||
// Special-case auth data.
|
|
||||||
return {key: '_auth_data_'+provider+'.id', value: restValue};
|
|
||||||
}
|
|
||||||
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
|
|
||||||
'can only query on ' + key);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
|
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid key name: ' + key);
|
||||||
'invalid key name: ' + key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,20 +89,6 @@ export function transformKeyValue(schema, className, restKey, restValue, {
|
|||||||
}
|
}
|
||||||
var expectedTypeIsArray = (expected && expected.type === 'Array');
|
var expectedTypeIsArray = (expected && expected.type === 'Array');
|
||||||
|
|
||||||
// Handle query constraints
|
|
||||||
if (query) {
|
|
||||||
value = transformConstraint(restValue, expectedTypeIsArray);
|
|
||||||
if (value !== CannotTransform) {
|
|
||||||
return {key: key, value: value};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expectedTypeIsArray && query && !(restValue instanceof Array)) {
|
|
||||||
return {
|
|
||||||
key: key, value: { '$all' : [restValue] }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle atomic values
|
// Handle atomic values
|
||||||
var value = transformAtom(restValue, false, { inArray, inObject });
|
var value = transformAtom(restValue, false, { inArray, inObject });
|
||||||
if (value !== CannotTransform) {
|
if (value !== CannotTransform) {
|
||||||
@@ -154,10 +106,6 @@ export function transformKeyValue(schema, className, restKey, restValue, {
|
|||||||
|
|
||||||
// Handle arrays
|
// Handle arrays
|
||||||
if (restValue instanceof Array) {
|
if (restValue instanceof Array) {
|
||||||
if (query) {
|
|
||||||
throw new Parse.Error(Parse.Error.INVALID_JSON,
|
|
||||||
'cannot use array as query param');
|
|
||||||
}
|
|
||||||
value = restValue.map((restObj) => {
|
value = restValue.map((restObj) => {
|
||||||
var out = transformKeyValue(schema, className, restKey, restObj, { inArray: true });
|
var out = transformKeyValue(schema, className, restKey, restObj, { inArray: true });
|
||||||
return out.value;
|
return out.value;
|
||||||
@@ -182,20 +130,105 @@ export function transformKeyValue(schema, className, restKey, restValue, {
|
|||||||
return {key: key, value: value};
|
return {key: key, value: value};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const valueAsDate = value => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return new Date(value);
|
||||||
|
} else if (value instanceof Date) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformQueryKeyValue(className, key, value, { validate } = {}, schema) {
|
||||||
|
switch(key) {
|
||||||
|
case 'createdAt':
|
||||||
|
if (valueAsDate(value)) {
|
||||||
|
return {key: '_created_at', value: valueAsDate(value)}
|
||||||
|
}
|
||||||
|
key = '_created_at';
|
||||||
|
break;
|
||||||
|
case 'updatedAt':
|
||||||
|
if (valueAsDate(value)) {
|
||||||
|
return {key: '_updated_at', value: valueAsDate(value)}
|
||||||
|
}
|
||||||
|
key = '_updated_at';
|
||||||
|
break;
|
||||||
|
case 'expiresAt':
|
||||||
|
if (valueAsDate(value)) {
|
||||||
|
return {key: 'expiresAt', value: valueAsDate(value)}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'objectId': return {key: '_id', value}
|
||||||
|
case 'sessionToken': return {key: '_session_token', value}
|
||||||
|
case '_rperm':
|
||||||
|
case '_wperm':
|
||||||
|
case '_perishable_token':
|
||||||
|
case '_email_verify_token': return {key, value}
|
||||||
|
case '$or':
|
||||||
|
if (!(value instanceof Array)) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $or format - use an array value');
|
||||||
|
}
|
||||||
|
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, {}, schema))};
|
||||||
|
case '$and':
|
||||||
|
if (!(value instanceof Array)) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $and format - use an array value');
|
||||||
|
}
|
||||||
|
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, {}, schema))};
|
||||||
|
default:
|
||||||
|
// Other auth data
|
||||||
|
const authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
|
||||||
|
if (authDataMatch) {
|
||||||
|
const provider = authDataMatch[1];
|
||||||
|
// Special-case auth data.
|
||||||
|
return {key: `_auth_data_${provider}.id`, value};
|
||||||
|
}
|
||||||
|
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid key name: ' + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectedTypeIsArray =
|
||||||
|
schema &&
|
||||||
|
schema.fields[key] &&
|
||||||
|
schema.fields[key].type === 'Array';
|
||||||
|
|
||||||
|
const expectedTypeIsPointer =
|
||||||
|
schema &&
|
||||||
|
schema.fields[key] &&
|
||||||
|
schema.fields[key].type === 'Pointer';
|
||||||
|
|
||||||
|
if (expectedTypeIsPointer || !schema && value && value.__type === 'Pointer') {
|
||||||
|
key = '_p_' + key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle query constraints
|
||||||
|
if (transformConstraint(value, expectedTypeIsArray) !== CannotTransform) {
|
||||||
|
return {key, value: transformConstraint(value, expectedTypeIsArray)};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedTypeIsArray && !(value instanceof Array)) {
|
||||||
|
return {key, value: { '$all' : [value] }};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle atomic values
|
||||||
|
if (transformAtom(value, false) !== CannotTransform) {
|
||||||
|
return {key, value: transformAtom(value, false)};
|
||||||
|
} else {
|
||||||
|
throw new Parse.Error(Parse.Error.INVALID_JSON, `You cannot use ${value} as a query parameter.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Main exposed method to help run queries.
|
// Main exposed method to help run queries.
|
||||||
// restWhere is the "where" clause in REST API form.
|
// restWhere is the "where" clause in REST API form.
|
||||||
// Returns the mongo form of the query.
|
// Returns the mongo form of the query.
|
||||||
// Throws a Parse.Error if the input query is invalid.
|
// Throws a Parse.Error if the input query is invalid.
|
||||||
function transformWhere(schema, className, restWhere, options = {validate: true}) {
|
function transformWhere(className, restWhere, { validate = true } = {}, schema) {
|
||||||
let mongoWhere = {};
|
let mongoWhere = {};
|
||||||
if (restWhere['ACL']) {
|
if (restWhere['ACL']) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
|
||||||
}
|
}
|
||||||
let transformKeyOptions = {query: true};
|
|
||||||
transformKeyOptions.validate = options.validate;
|
|
||||||
for (let restKey in restWhere) {
|
for (let restKey in restWhere) {
|
||||||
let out = transformKeyValue(schema, className, restKey, restWhere[restKey], transformKeyOptions);
|
let out = transformQueryKeyValue(className, restKey, restWhere[restKey], { validate }, schema);
|
||||||
mongoWhere[out.key] = out.value;
|
mongoWhere[out.key] = out.value;
|
||||||
}
|
}
|
||||||
return mongoWhere;
|
return mongoWhere;
|
||||||
|
|||||||
@@ -52,11 +52,7 @@ var getAuthForSessionToken = function({ config, sessionToken, installationId } =
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
include: 'user'
|
include: 'user'
|
||||||
};
|
};
|
||||||
var restWhere = {
|
var query = new RestQuery(config, master(config), '_Session', { sessionToken }, restOptions);
|
||||||
_session_token: sessionToken
|
|
||||||
};
|
|
||||||
var query = new RestQuery(config, master(config), '_Session',
|
|
||||||
restWhere, restOptions);
|
|
||||||
return query.execute().then((response) => {
|
return query.execute().then((response) => {
|
||||||
var results = response.results;
|
var results = response.results;
|
||||||
if (results.length !== 1 || !results[0]['user']) {
|
if (results.length !== 1 || !results[0]['user']) {
|
||||||
|
|||||||
@@ -158,20 +158,15 @@ DatabaseController.prototype.update = function(className, query, update, {
|
|||||||
|
|
||||||
var isMaster = acl === undefined;
|
var isMaster = acl === undefined;
|
||||||
var aclGroup = acl || [];
|
var aclGroup = acl || [];
|
||||||
var mongoUpdate, schema;
|
var mongoUpdate;
|
||||||
return this.loadSchema()
|
return this.loadSchema()
|
||||||
.then(s => {
|
.then(schemaController => {
|
||||||
schema = s;
|
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'update'))
|
||||||
if (!isMaster) {
|
|
||||||
return schema.validatePermission(className, aclGroup, 'update');
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
})
|
|
||||||
.then(() => this.handleRelationUpdates(className, query.objectId, update))
|
.then(() => this.handleRelationUpdates(className, query.objectId, update))
|
||||||
.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(schemaController, className, 'update', query, aclGroup);
|
||||||
}
|
}
|
||||||
if (!query) {
|
if (!query) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -179,26 +174,42 @@ DatabaseController.prototype.update = function(className, query, update, {
|
|||||||
if (acl) {
|
if (acl) {
|
||||||
query = addWriteACL(query, acl);
|
query = addWriteACL(query, acl);
|
||||||
}
|
}
|
||||||
var mongoWhere = this.transform.transformWhere(schema, className, query, {validate: !this.skipValidation});
|
return schemaController.getOneSchema(className)
|
||||||
mongoUpdate = this.transform.transformUpdate(schema, className, update, {validate: !this.skipValidation});
|
.catch(error => {
|
||||||
if (many) {
|
// If the schema doesn't exist, pretend it exists with no fields. This behaviour
|
||||||
return collection.updateMany(mongoWhere, mongoUpdate);
|
// will likely need revisiting.
|
||||||
} else if (upsert) {
|
if (error === undefined) {
|
||||||
return collection.upsertOne(mongoWhere, mongoUpdate);
|
return { fields: {} };
|
||||||
} else {
|
}
|
||||||
return collection.findOneAndUpdate(mongoWhere, mongoUpdate);
|
throw error;
|
||||||
}
|
})
|
||||||
|
.then(parseFormatSchema => {
|
||||||
|
var mongoWhere = this.transform.transformWhere(className, query, {validate: !this.skipValidation}, parseFormatSchema);
|
||||||
|
mongoUpdate = this.transform.transformUpdate(
|
||||||
|
schemaController,
|
||||||
|
className,
|
||||||
|
update,
|
||||||
|
{validate: !this.skipValidation}
|
||||||
|
);
|
||||||
|
if (many) {
|
||||||
|
return collection.updateMany(mongoWhere, mongoUpdate);
|
||||||
|
} else if (upsert) {
|
||||||
|
return collection.upsertOne(mongoWhere, mongoUpdate);
|
||||||
|
} else {
|
||||||
|
return collection.findOneAndUpdate(mongoWhere, mongoUpdate);
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'));
|
||||||
'Object not found.'));
|
|
||||||
}
|
}
|
||||||
if (this.skipValidation) {
|
if (this.skipValidation) {
|
||||||
return Promise.resolve(result);
|
return Promise.resolve(result);
|
||||||
}
|
}
|
||||||
return sanitizeDatabaseResult(originalUpdate, result);
|
return sanitizeDatabaseResult(originalUpdate, result);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function sanitizeDatabaseResult(originalObject, result) {
|
function sanitizeDatabaseResult(originalObject, result) {
|
||||||
@@ -317,7 +328,16 @@ DatabaseController.prototype.destroy = function(className, query, { acl } = {})
|
|||||||
if (acl) {
|
if (acl) {
|
||||||
query = addWriteACL(query, acl);
|
query = addWriteACL(query, acl);
|
||||||
}
|
}
|
||||||
return this.adapter.deleteObjectsByQuery(className, query, schemaController, !this.skipValidation)
|
return schemaController.getOneSchema(className)
|
||||||
|
.catch(error => {
|
||||||
|
// If the schema doesn't exist, pretend it exists with no fields. This behaviour
|
||||||
|
// will likely need revisiting.
|
||||||
|
if (error === undefined) {
|
||||||
|
return { fields: {} };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.then(parseFormatSchema => this.adapter.deleteObjectsByQuery(className, query, !this.skipValidation, parseFormatSchema))
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// When deleting sessions while changing passwords, don't throw an error if they don't have any sessions.
|
// When deleting sessions while changing passwords, don't throw an error if they don't have any sessions.
|
||||||
if (className === "_Session" && error.code === Parse.Error.OBJECT_NOT_FOUND) {
|
if (className === "_Session" && error.code === Parse.Error.OBJECT_NOT_FOUND) {
|
||||||
@@ -593,56 +613,59 @@ DatabaseController.prototype.find = function(className, query, {
|
|||||||
}
|
}
|
||||||
let isMaster = acl === undefined;
|
let isMaster = acl === undefined;
|
||||||
let aclGroup = acl || [];
|
let aclGroup = acl || [];
|
||||||
let schema = null;
|
let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find';
|
||||||
let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ?
|
return this.loadSchema()
|
||||||
'get' :
|
.then(schemaController => {
|
||||||
'find';
|
|
||||||
return this.loadSchema().then(s => {
|
|
||||||
schema = s;
|
|
||||||
if (sort) {
|
if (sort) {
|
||||||
mongoOptions.sort = {};
|
mongoOptions.sort = {};
|
||||||
for (let key in sort) {
|
for (let key in sort) {
|
||||||
let mongoKey = this.transform.transformKey(schema, className, key);
|
let mongoKey = this.transform.transformKey(schemaController, className, key);
|
||||||
mongoOptions.sort[mongoKey] = sort[key];
|
mongoOptions.sort[mongoKey] = sort[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op))
|
||||||
if (!isMaster) {
|
.then(() => this.reduceRelationKeys(className, query))
|
||||||
return schema.validatePermission(className, aclGroup, op);
|
.then(() => this.reduceInRelation(className, query, schemaController))
|
||||||
}
|
.then(() => this.adapter.adaptiveCollection(className))
|
||||||
return Promise.resolve();
|
.then(collection => {
|
||||||
})
|
if (!isMaster) {
|
||||||
.then(() => this.reduceRelationKeys(className, query))
|
query = this.addPointerPermissions(schemaController, className, op, query, aclGroup);
|
||||||
.then(() => this.reduceInRelation(className, query, schema))
|
|
||||||
.then(() => this.adapter.adaptiveCollection(className))
|
|
||||||
.then(collection => {
|
|
||||||
if (!isMaster) {
|
|
||||||
query = this.addPointerPermissions(schema, className, op, query, aclGroup);
|
|
||||||
}
|
|
||||||
if (!query) {
|
|
||||||
if (op == 'get') {
|
|
||||||
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
|
||||||
'Object not found.'));
|
|
||||||
} else {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
}
|
||||||
}
|
if (!query) {
|
||||||
if (!isMaster) {
|
if (op == 'get') {
|
||||||
query = addReadACL(query, aclGroup);
|
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
|
||||||
}
|
'Object not found.'));
|
||||||
let mongoWhere = this.transform.transformWhere(schema, className, query);
|
} else {
|
||||||
if (count) {
|
return Promise.resolve([]);
|
||||||
delete mongoOptions.limit;
|
}
|
||||||
return collection.count(mongoWhere, mongoOptions);
|
}
|
||||||
} else {
|
if (!isMaster) {
|
||||||
return collection.find(mongoWhere, mongoOptions)
|
query = addReadACL(query, aclGroup);
|
||||||
.then((mongoResults) => {
|
}
|
||||||
return mongoResults.map((r) => {
|
return schemaController.getOneSchema(className)
|
||||||
return this.untransformObject(
|
.catch(error => {
|
||||||
schema, isMaster, aclGroup, className, r);
|
// If the schema doesn't exist, pretend it exists with no fields. This behaviour
|
||||||
|
// will likely need revisiting.
|
||||||
|
if (error === undefined) {
|
||||||
|
return { fields: {} };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
.then(parseFormatSchema => {
|
||||||
|
let mongoWhere = this.transform.transformWhere(className, query, {}, parseFormatSchema);
|
||||||
|
if (count) {
|
||||||
|
delete mongoOptions.limit;
|
||||||
|
return collection.count(mongoWhere, mongoOptions);
|
||||||
|
} else {
|
||||||
|
return collection.find(mongoWhere, mongoOptions)
|
||||||
|
.then((mongoResults) => {
|
||||||
|
return mongoResults.map((r) => {
|
||||||
|
return this.untransformObject(schemaController, isMaster, aclGroup, className, r);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
// global_config.js
|
// global_config.js
|
||||||
|
|
||||||
import PromiseRouter from '../PromiseRouter';
|
import PromiseRouter from '../PromiseRouter';
|
||||||
import * as middleware from "../middlewares";
|
import * as middleware from "../middlewares";
|
||||||
|
|
||||||
export class GlobalConfigRouter extends PromiseRouter {
|
export class GlobalConfigRouter extends PromiseRouter {
|
||||||
getGlobalConfig(req) {
|
getGlobalConfig(req) {
|
||||||
let database = req.config.database.WithoutValidation();
|
let database = req.config.database.WithoutValidation();
|
||||||
return database.find('_GlobalConfig', { '_id': 1 }, { limit: 1 }).then((results) => {
|
return database.find('_GlobalConfig', { objectId: 1 }, { limit: 1 }).then((results) => {
|
||||||
if (results.length != 1) {
|
if (results.length != 1) {
|
||||||
// If there is no config in the database - return empty config.
|
// If there is no config in the database - return empty config.
|
||||||
return { response: { params: {} } };
|
return { response: { params: {} } };
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import ClassesRouter from './ClassesRouter';
|
import ClassesRouter from './ClassesRouter';
|
||||||
import PromiseRouter from '../PromiseRouter';
|
import PromiseRouter from '../PromiseRouter';
|
||||||
import rest from '../rest';
|
import rest from '../rest';
|
||||||
import Auth from '../Auth';
|
import Auth from '../Auth';
|
||||||
|
|
||||||
export class SessionsRouter extends ClassesRouter {
|
export class SessionsRouter extends ClassesRouter {
|
||||||
handleFind(req) {
|
handleFind(req) {
|
||||||
@@ -36,7 +36,7 @@ export class SessionsRouter extends ClassesRouter {
|
|||||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
|
||||||
'Session token required.');
|
'Session token required.');
|
||||||
}
|
}
|
||||||
return rest.find(req.config, Auth.master(req.config), '_Session', { _session_token: req.info.sessionToken })
|
return rest.find(req.config, Auth.master(req.config), '_Session', { sessionToken: req.info.sessionToken })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response.results || response.results.length == 0) {
|
if (!response.results || response.results.length == 0) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
|
throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN,
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
}
|
}
|
||||||
let sessionToken = req.info.sessionToken;
|
let sessionToken = req.info.sessionToken;
|
||||||
return rest.find(req.config, Auth.master(req.config), '_Session',
|
return rest.find(req.config, Auth.master(req.config), '_Session',
|
||||||
{ _session_token: sessionToken },
|
{ sessionToken },
|
||||||
{ include: 'user' })
|
{ include: 'user' })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response.results ||
|
if (!response.results ||
|
||||||
@@ -139,7 +139,7 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
let success = {response: {}};
|
let success = {response: {}};
|
||||||
if (req.info && req.info.sessionToken) {
|
if (req.info && req.info.sessionToken) {
|
||||||
return rest.find(req.config, Auth.master(req.config), '_Session',
|
return rest.find(req.config, Auth.master(req.config), '_Session',
|
||||||
{ _session_token: req.info.sessionToken }
|
{ sessionToken: req.info.sessionToken }
|
||||||
).then((records) => {
|
).then((records) => {
|
||||||
if (records.results && records.results.length) {
|
if (records.results && records.results.length) {
|
||||||
return rest.del(req.config, Auth.master(req.config), '_Session',
|
return rest.del(req.config, Auth.master(req.config), '_Session',
|
||||||
|
|||||||
Reference in New Issue
Block a user