Fix some stuff
This commit is contained in:
@@ -49,7 +49,7 @@ describe('MongoStorageAdapter', () => {
|
|||||||
|
|
||||||
it('stores objectId in _id', done => {
|
it('stores objectId in _id', done => {
|
||||||
let adapter = new MongoStorageAdapter({ uri: databaseURI });
|
let adapter = new MongoStorageAdapter({ uri: databaseURI });
|
||||||
adapter.createObject('Foo', {}, { objectId: 'abcde' })
|
adapter.createObject('Foo', { fields: {} }, { objectId: 'abcde' })
|
||||||
.then(() => adapter._rawFind('Foo', {}))
|
.then(() => adapter._rawFind('Foo', {}))
|
||||||
.then(results => {
|
.then(results => {
|
||||||
expect(results.length).toEqual(1);
|
expect(results.length).toEqual(1);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
var request = require('request');
|
var request = require('request');
|
||||||
var passwordCrypto = require('../src/password');
|
var passwordCrypto = require('../src/password');
|
||||||
var Config = require('../src/Config');
|
var Config = require('../src/Config');
|
||||||
|
const rp = require('request-promise');
|
||||||
|
|
||||||
function verifyACL(user) {
|
function verifyACL(user) {
|
||||||
const ACL = user.getACL();
|
const ACL = user.getACL();
|
||||||
@@ -2131,7 +2132,7 @@ describe('Parse.User testing', () => {
|
|||||||
let database = new Config(Parse.applicationId).database;
|
let database = new Config(Parse.applicationId).database;
|
||||||
database.create('_User', {
|
database.create('_User', {
|
||||||
username: 'user',
|
username: 'user',
|
||||||
password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
|
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
|
||||||
_auth_data_facebook: null
|
_auth_data_facebook: null
|
||||||
}, {}).then(() => {
|
}, {}).then(() => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -2258,42 +2259,43 @@ describe('Parse.User testing', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to become user with expired token', (done) => {
|
it('should fail to become user with expired token', (done) => {
|
||||||
Parse.User.signUp("auser", "somepass", null, {
|
let token;
|
||||||
success: function(user) {
|
Parse.User.signUp("auser", "somepass", null)
|
||||||
request.get({
|
.then(user => rp({
|
||||||
url: 'http://localhost:8378/1/classes/_Session',
|
method: 'GET',
|
||||||
json: true,
|
url: 'http://localhost:8378/1/classes/_Session',
|
||||||
headers: {
|
json: true,
|
||||||
'X-Parse-Application-Id': 'test',
|
headers: {
|
||||||
'X-Parse-Master-Key': 'test',
|
'X-Parse-Application-Id': 'test',
|
||||||
},
|
'X-Parse-Master-Key': 'test',
|
||||||
}, (error, response, body) => {
|
},
|
||||||
var id = body.results[0].objectId;
|
}))
|
||||||
var expiresAt = new Date((new Date()).setYear(2015));
|
.then(body => {
|
||||||
var token = body.results[0].sessionToken;
|
var id = body.results[0].objectId;
|
||||||
request.put({
|
var expiresAt = new Date((new Date()).setYear(2015));
|
||||||
url: "http://localhost:8378/1/classes/_Session/" + id,
|
token = body.results[0].sessionToken;
|
||||||
json: true,
|
return rp({
|
||||||
headers: {
|
method: 'PUT',
|
||||||
'X-Parse-Application-Id': 'test',
|
url: "http://localhost:8378/1/classes/_Session/" + id,
|
||||||
'X-Parse-Master-Key': 'test',
|
json: true,
|
||||||
},
|
headers: {
|
||||||
body: {
|
'X-Parse-Application-Id': 'test',
|
||||||
expiresAt: { __type: "Date", iso: expiresAt.toISOString() },
|
'X-Parse-Master-Key': 'test',
|
||||||
},
|
},
|
||||||
}, (error, response, body) => {
|
body: {
|
||||||
Parse.User.become(token)
|
expiresAt: { __type: "Date", iso: expiresAt.toISOString() },
|
||||||
.then(() => { fail("Should not have succeded"); })
|
},
|
||||||
.fail((err) => {
|
})
|
||||||
expect(err.code).toEqual(209);
|
})
|
||||||
expect(err.message).toEqual("Session token is expired.");
|
.then(() => Parse.User.become(token))
|
||||||
Parse.User.logOut() // Logout to prevent polluting CLI with messages
|
.then(() => {
|
||||||
.then(done);
|
fail("Should not have succeded")
|
||||||
});
|
done();
|
||||||
});
|
}, error => {
|
||||||
});
|
expect(error.code).toEqual(209);
|
||||||
}
|
expect(error.message).toEqual("Session token is expired.");
|
||||||
});
|
done();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not create extraneous session tokens', (done) => {
|
it('should not create extraneous session tokens', (done) => {
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ describe('Pointer Permissions', () => {
|
|||||||
expect(res.length).toBe(1);
|
expect(res.length).toBe(1);
|
||||||
expect(res[0].id).toBe(obj.id);
|
expect(res[0].id).toBe(obj.id);
|
||||||
done();
|
done();
|
||||||
}).catch((err) => {
|
}).catch(error => {
|
||||||
fail('Should not fail');
|
fail(JSON.stringify(error));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ describe('SchemaController', () => {
|
|||||||
});
|
});
|
||||||
Promise.all([p1,p2])
|
Promise.all([p1,p2])
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
|
expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
|
||||||
expect(error.message).toEqual('Class NewClass already exists.');
|
expect(error.message).toEqual('Class NewClass already exists.');
|
||||||
done();
|
done();
|
||||||
@@ -693,7 +694,7 @@ describe('SchemaController', () => {
|
|||||||
objectId: { type: 'String' },
|
objectId: { type: 'String' },
|
||||||
updatedAt: { type: 'Date' },
|
updatedAt: { type: 'Date' },
|
||||||
createdAt: { type: 'Date' },
|
createdAt: { type: 'Date' },
|
||||||
ACL: { type: 'ACL' }
|
ACL: { type: 'ACL' },
|
||||||
};
|
};
|
||||||
expect(dd(schema.data.NewClass, expectedSchema)).toEqual(undefined);
|
expect(dd(schema.data.NewClass, expectedSchema)).toEqual(undefined);
|
||||||
done();
|
done();
|
||||||
|
|||||||
@@ -100,12 +100,4 @@ describe('Uniqueness', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adding a unique index to an existing field works even if it has nulls', done => {
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adding a unique index to an existing field doesnt prevent you from adding new documents with nulls', done => {
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -140,6 +140,12 @@ beforeEach(done => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
|
let afterLogOut = () => {
|
||||||
|
if (Object.keys(openConnections).length > 0) {
|
||||||
|
fail('There were open connections to the server left after the test finished');
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
};
|
||||||
Parse.Cloud._removeAllHooks();
|
Parse.Cloud._removeAllHooks();
|
||||||
databaseAdapter.getAllClasses()
|
databaseAdapter.getAllClasses()
|
||||||
.then(allSchemas => {
|
.then(allSchemas => {
|
||||||
@@ -157,16 +163,7 @@ afterEach(function(done) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(() => Parse.User.logOut())
|
.then(() => Parse.User.logOut())
|
||||||
.then(() => {
|
.then(afterLogOut, afterLogOut)
|
||||||
if (Object.keys(openConnections).length > 0) {
|
|
||||||
fail('There were open connections to the server left after the test finished');
|
|
||||||
}
|
|
||||||
done();
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
fail(JSON.stringify(error));
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var TestObject = Parse.Object.extend({
|
var TestObject = Parse.Object.extend({
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ const storageAdapterAllCollections = mongoAdapter => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const convertParseSchemaToMongoSchema = ({...schema}) => {
|
||||||
|
delete schema.fields._rperm;
|
||||||
|
delete schema.fields._wperm;
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
export class MongoStorageAdapter {
|
export class MongoStorageAdapter {
|
||||||
// Private
|
// Private
|
||||||
_uri: string;
|
_uri: string;
|
||||||
@@ -97,6 +103,7 @@ export class MongoStorageAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createClass(className, schema) {
|
createClass(className, schema) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
return this._schemaCollection()
|
return this._schemaCollection()
|
||||||
.then(schemaCollection => schemaCollection.addSchema(className, schema.fields, schema.classLevelPermissions));
|
.then(schemaCollection => schemaCollection.addSchema(className, schema.fields, schema.classLevelPermissions));
|
||||||
}
|
}
|
||||||
@@ -192,6 +199,7 @@ export class MongoStorageAdapter {
|
|||||||
// and should infer from the type. Or maybe does need the schema for validations. Or maybe needs
|
// and should infer from the type. Or maybe does need the schema for validations. Or maybe needs
|
||||||
// the schem only for the legacy mongo format. We'll figure that out later.
|
// the schem only for the legacy mongo format. We'll figure that out later.
|
||||||
createObject(className, schema, object) {
|
createObject(className, schema, object) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const mongoObject = parseObjectToMongoObjectForCreate(className, object, schema);
|
const mongoObject = parseObjectToMongoObjectForCreate(className, object, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then(collection => collection.insertOne(mongoObject))
|
.then(collection => collection.insertOne(mongoObject))
|
||||||
@@ -208,6 +216,7 @@ 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.
|
||||||
deleteObjectsByQuery(className, schema, query) {
|
deleteObjectsByQuery(className, schema, query) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then(collection => {
|
.then(collection => {
|
||||||
let mongoWhere = transformWhere(className, query, schema);
|
let mongoWhere = transformWhere(className, query, schema);
|
||||||
@@ -225,6 +234,7 @@ export class MongoStorageAdapter {
|
|||||||
|
|
||||||
// Apply the update to all objects that match the given Parse Query.
|
// Apply the update to all objects that match the given Parse Query.
|
||||||
updateObjectsByQuery(className, schema, query, update) {
|
updateObjectsByQuery(className, schema, query, update) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
@@ -234,6 +244,7 @@ export class MongoStorageAdapter {
|
|||||||
// Atomically finds and updates an object based on query.
|
// Atomically finds and updates an object based on query.
|
||||||
// Return value not currently well specified.
|
// Return value not currently well specified.
|
||||||
findOneAndUpdate(className, schema, query, update) {
|
findOneAndUpdate(className, schema, query, update) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
@@ -243,6 +254,7 @@ export class MongoStorageAdapter {
|
|||||||
|
|
||||||
// Hopefully we can get rid of this. It's only used for config and hooks.
|
// Hopefully we can get rid of this. It's only used for config and hooks.
|
||||||
upsertOneObject(className, schema, query, update) {
|
upsertOneObject(className, schema, query, update) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
@@ -251,6 +263,7 @@ export class MongoStorageAdapter {
|
|||||||
|
|
||||||
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
||||||
find(className, schema, query, { skip, limit, sort }) {
|
find(className, schema, query, { skip, limit, sort }) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
let mongoWhere = transformWhere(className, query, schema);
|
let mongoWhere = transformWhere(className, query, schema);
|
||||||
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
|
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
@@ -264,6 +277,7 @@ export class MongoStorageAdapter {
|
|||||||
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
|
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
|
||||||
// which is why we use sparse indexes.
|
// which is why we use sparse indexes.
|
||||||
ensureUniqueness(className, schema, fieldNames) {
|
ensureUniqueness(className, schema, fieldNames) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
let indexCreationRequest = {};
|
let indexCreationRequest = {};
|
||||||
let mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
|
let mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
|
||||||
mongoFieldNames.forEach(fieldName => {
|
mongoFieldNames.forEach(fieldName => {
|
||||||
@@ -287,6 +301,7 @@ export class MongoStorageAdapter {
|
|||||||
|
|
||||||
// Executs a count.
|
// Executs a count.
|
||||||
count(className, schema, query) {
|
count(className, schema, query) {
|
||||||
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then(collection => collection.count(transformWhere(className, query, schema)));
|
.then(collection => collection.count(transformWhere(className, query, schema)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ const validateQuery = query => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(query).forEach(key => {
|
Object.keys(query).forEach(key => {
|
||||||
if (query[key].$regex) {
|
if (query && query[key] && query[key].$regex) {
|
||||||
if (typeof query[key].$options === 'string') {g
|
if (typeof query[key].$options === 'string') {
|
||||||
if (!query[key].$options.match(/^[imxs]+$/)) {
|
if (!query[key].$options.match(/^[imxs]+$/)) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, `Bad $options value for query: ${query[key].$options}`);
|
throw new Parse.Error(Parse.Error.INVALID_QUERY, `Bad $options value for query: ${query[key].$options}`);
|
||||||
}
|
}
|
||||||
@@ -764,7 +764,7 @@ DatabaseController.prototype.deleteSchema = function(className) {
|
|||||||
})
|
})
|
||||||
.then(schema => {
|
.then(schema => {
|
||||||
return this.collectionExists(className)
|
return this.collectionExists(className)
|
||||||
.then(exist => this.adapter.count(className))
|
.then(exist => this.adapter.count(className, { fields: {} }))
|
||||||
.then(count => {
|
.then(count => {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
|
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);
|
||||||
|
|||||||
@@ -234,6 +234,20 @@ const convertSchemaToAdapterSchema = schema => {
|
|||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const convertAdapterSchemaToParseSchema = ({...schema}) => {
|
||||||
|
delete schema.fields._rperm;
|
||||||
|
delete schema.fields._wperm;
|
||||||
|
|
||||||
|
schema.fields.ACL = { type: 'ACL' };
|
||||||
|
|
||||||
|
if (schema.className === '_User') {
|
||||||
|
delete schema.fields._hashed_password;
|
||||||
|
schema.fields.password = { type: 'String' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
const injectDefaultSchema = schema => ({
|
const injectDefaultSchema = schema => ({
|
||||||
className: schema.className,
|
className: schema.className,
|
||||||
fields: {
|
fields: {
|
||||||
@@ -316,6 +330,7 @@ class SchemaController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this._dbAdapter.createClass(className, convertSchemaToAdapterSchema({ fields, classLevelPermissions, className }))
|
return this._dbAdapter.createClass(className, convertSchemaToAdapterSchema({ fields, classLevelPermissions, className }))
|
||||||
|
.then(convertAdapterSchemaToParseSchema)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error && error.code === Parse.Error.DUPLICATE_VALUE) {
|
if (error && error.code === Parse.Error.DUPLICATE_VALUE) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, `Class ${className} already exists.`);
|
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, `Class ${className} already exists.`);
|
||||||
@@ -342,6 +357,8 @@ class SchemaController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delete existingFields._rperm;
|
||||||
|
delete existingFields._wperm;
|
||||||
let newSchema = buildMergedSchemaObject(existingFields, submittedFields);
|
let newSchema = buildMergedSchemaObject(existingFields, submittedFields);
|
||||||
let validationError = this.validateSchemaData(className, newSchema, classLevelPermissions);
|
let validationError = this.validateSchemaData(className, newSchema, classLevelPermissions);
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
|
|||||||
Reference in New Issue
Block a user