Merge branch 'master' of https://github.com/ParsePlatform/parse-server into mcdonald-gcs-adapter
* 'master' of https://github.com/ParsePlatform/parse-server: Remove limit when counting results. beforeSave changes should propagate to the response Fix delete relation field when _Join collection not exist Test empty authData block on login for #413 Fix for related query on non-existing column Fix Markdown format: make checkboxes visible Fix create wrong _Session for Facebook login Modified the npm dev script to support Windows Improves tests, ensure unicity of roleIds Fix reversed roles lookup Fix leak warnings in tests, use mongodb-runner from node_modules Improves documentation, add loading tests Improves loading of Push Adapter, fix loading of S3Adapter Adds public_html and views for packaging Removes shebang for windows Better support for windows builds Fix add field to system schema Convert Schema.js to ES6 class.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
|
||||
var loadAdapter = require("../src/Adapters/AdapterLoader").loadAdapter;
|
||||
var FilesAdapter = require("../src/Adapters/Files/FilesAdapter").default;
|
||||
var ParsePushAdapter = require("../src/Adapters/Push/ParsePushAdapter");
|
||||
var S3Adapter = require("../src/Adapters/Files/S3Adapter").default;
|
||||
|
||||
describe("AdapterLoader", ()=>{
|
||||
|
||||
@@ -84,4 +86,27 @@ describe("AdapterLoader", ()=>{
|
||||
}).not.toThrow("foo is required for that adapter");
|
||||
done();
|
||||
});
|
||||
|
||||
it("should load push adapter from options", (done) => {
|
||||
var options = {
|
||||
ios: {
|
||||
bundleId: 'bundle.id'
|
||||
}
|
||||
}
|
||||
expect(() => {
|
||||
var adapter = loadAdapter(undefined, ParsePushAdapter, options);
|
||||
expect(adapter.constructor).toBe(ParsePushAdapter);
|
||||
expect(adapter).not.toBe(undefined);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it("should load S3Adapter from direct passing", (done) => {
|
||||
var s3Adapter = new S3Adapter("key", "secret", "bucket")
|
||||
expect(() => {
|
||||
var adapter = loadAdapter(s3Adapter, FilesAdapter);
|
||||
expect(adapter).toBe(s3Adapter);
|
||||
}).not.toThrow();
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
@@ -967,6 +967,23 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('beforeSave change propagates through the save response', (done) => {
|
||||
Parse.Cloud.beforeSave('ChangingObject', function(request, response) {
|
||||
request.object.set('foo', 'baz');
|
||||
response.success();
|
||||
});
|
||||
let obj = new Parse.Object('ChangingObject');
|
||||
obj.save({ foo: 'bar' }).then((objAgain) => {
|
||||
expect(objAgain.get('foo')).toEqual('baz');
|
||||
Parse.Cloud._removeHook("Triggers", "beforeSave", "ChangingObject");
|
||||
done();
|
||||
}, (e) => {
|
||||
Parse.Cloud._removeHook("Triggers", "beforeSave", "ChangingObject");
|
||||
fail('Should not have failed to save.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('dedupes an installation properly and returns updatedAt', (done) => {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -995,4 +1012,32 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('android login providing empty authData block works', (done) => {
|
||||
let headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Parse-Application-Id': 'test',
|
||||
'X-Parse-REST-API-Key': 'rest'
|
||||
};
|
||||
let data = {
|
||||
username: 'pulse1989',
|
||||
password: 'password1234',
|
||||
authData: {}
|
||||
};
|
||||
let requestOptions = {
|
||||
headers: headers,
|
||||
url: 'http://localhost:8378/1/users',
|
||||
body: JSON.stringify(data)
|
||||
};
|
||||
request.post(requestOptions, (error, response, body) => {
|
||||
expect(error).toBe(null);
|
||||
requestOptions.url = 'http://localhost:8378/1/login';
|
||||
request.get(requestOptions, (error, response, body) => {
|
||||
expect(error).toBe(null);
|
||||
let b = JSON.parse(body);
|
||||
expect(typeof b['sessionToken']).toEqual('string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Roles are not accessible without the master key, so they are not intended
|
||||
// for use by clients. We can manually test them using the master key.
|
||||
@@ -64,26 +64,30 @@ describe('Parse Role testing', () => {
|
||||
|
||||
var rolesNames = ["FooRole", "BarRole", "BazRole"];
|
||||
|
||||
var createRole = function(name, parent, user) {
|
||||
var createRole = function(name, sibling, user) {
|
||||
var role = new Parse.Role(name, new Parse.ACL());
|
||||
if (user) {
|
||||
var users = role.relation('users');
|
||||
users.add(user);
|
||||
}
|
||||
if (parent) {
|
||||
role.relation('roles').add(parent);
|
||||
if (sibling) {
|
||||
role.relation('roles').add(sibling);
|
||||
}
|
||||
return role.save({}, { useMasterKey: true });
|
||||
}
|
||||
var roleIds = {};
|
||||
createTestUser().then( (user) => {
|
||||
|
||||
return createRole(rolesNames[0], null, null).then( (aRole) => {
|
||||
// Put the user on the 1st role
|
||||
return createRole(rolesNames[0], null, user).then( (aRole) => {
|
||||
roleIds[aRole.get("name")] = aRole.id;
|
||||
// set the 1st role as a sibling of the second
|
||||
// user will should have 2 role now
|
||||
return createRole(rolesNames[1], aRole, null);
|
||||
}).then( (anotherRole) => {
|
||||
roleIds[anotherRole.get("name")] = anotherRole.id;
|
||||
return createRole(rolesNames[2], anotherRole, user);
|
||||
// set this role as a sibling of the last
|
||||
// the user should now have 3 roles
|
||||
return createRole(rolesNames[2], anotherRole, null);
|
||||
}).then( (lastRole) => {
|
||||
roleIds[lastRole.get("name")] = lastRole.id;
|
||||
var auth = new Auth({ config: new Config("test"), isMaster: true, user: user });
|
||||
@@ -118,6 +122,80 @@ describe('Parse Role testing', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Should properly resolve roles", (done) => {
|
||||
let admin = new Parse.Role("Admin", new Parse.ACL());
|
||||
let moderator = new Parse.Role("Moderator", new Parse.ACL());
|
||||
let superModerator = new Parse.Role("SuperModerator", new Parse.ACL());
|
||||
let contentManager = new Parse.Role('ContentManager', new Parse.ACL());
|
||||
let superContentManager = new Parse.Role('SuperContentManager', new Parse.ACL());
|
||||
Parse.Object.saveAll([admin, moderator, contentManager, superModerator, superContentManager], {useMasterKey: true}).then(() => {
|
||||
contentManager.getRoles().add([moderator, superContentManager]);
|
||||
moderator.getRoles().add([admin, superModerator]);
|
||||
superContentManager.getRoles().add(superModerator);
|
||||
return Parse.Object.saveAll([admin, moderator, contentManager, superModerator, superContentManager], {useMasterKey: true});
|
||||
}).then(() => {
|
||||
var auth = new Auth({ config: new Config("test"), isMaster: true });
|
||||
// For each role, fetch their sibling, what they inherit
|
||||
// return with result and roleId for later comparison
|
||||
let promises = [admin, moderator, contentManager, superModerator].map((role) => {
|
||||
return auth._getAllRoleNamesForId(role.id).then((result) => {
|
||||
return Parse.Promise.as({
|
||||
id: role.id,
|
||||
name: role.get('name'),
|
||||
roleIds: result
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
return Parse.Promise.when(promises);
|
||||
}).then((results) => {
|
||||
results.forEach((result) => {
|
||||
let id = result.id;
|
||||
let roleIds = result.roleIds;
|
||||
if (id == admin.id) {
|
||||
expect(roleIds.length).toBe(2);
|
||||
expect(roleIds.indexOf(moderator.id)).not.toBe(-1);
|
||||
expect(roleIds.indexOf(contentManager.id)).not.toBe(-1);
|
||||
} else if (id == moderator.id) {
|
||||
expect(roleIds.length).toBe(1);
|
||||
expect(roleIds.indexOf(contentManager.id)).toBe(0);
|
||||
} else if (id == contentManager.id) {
|
||||
expect(roleIds.length).toBe(0);
|
||||
} else if (id == superModerator.id) {
|
||||
expect(roleIds.length).toBe(3);
|
||||
expect(roleIds.indexOf(moderator.id)).not.toBe(-1);
|
||||
expect(roleIds.indexOf(contentManager.id)).not.toBe(-1);
|
||||
expect(roleIds.indexOf(superContentManager.id)).not.toBe(-1);
|
||||
}
|
||||
});
|
||||
done();
|
||||
}).fail((err) => {
|
||||
console.error(err);
|
||||
done();
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
it('can create role and query empty users', (done)=> {
|
||||
var roleACL = new Parse.ACL();
|
||||
roleACL.setPublicReadAccess(true);
|
||||
var role = new Parse.Role('subscribers', roleACL);
|
||||
role.save({}, {useMasterKey : true})
|
||||
.then((x)=>{
|
||||
var query = role.relation('users').query();
|
||||
query.find({useMasterKey : true})
|
||||
.then((users)=>{
|
||||
done();
|
||||
}, (e)=>{
|
||||
fail('should not have errors');
|
||||
done();
|
||||
});
|
||||
}, (e) => {
|
||||
console.log(e);
|
||||
fail('should not have errored');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -175,17 +175,26 @@ describe('rest create', () => {
|
||||
}
|
||||
}
|
||||
};
|
||||
var newUserSignedUpByFacebookObjectId;
|
||||
rest.create(config, auth.nobody(config), '_User', data)
|
||||
.then((r) => {
|
||||
expect(typeof r.response.objectId).toEqual('string');
|
||||
expect(typeof r.response.createdAt).toEqual('string');
|
||||
expect(typeof r.response.sessionToken).toEqual('string');
|
||||
newUserSignedUpByFacebookObjectId = r.response.objectId;
|
||||
return rest.create(config, auth.nobody(config), '_User', data);
|
||||
}).then((r) => {
|
||||
expect(typeof r.response.objectId).toEqual('string');
|
||||
expect(typeof r.response.createdAt).toEqual('string');
|
||||
expect(typeof r.response.username).toEqual('string');
|
||||
expect(typeof r.response.updatedAt).toEqual('string');
|
||||
expect(r.response.objectId).toEqual(newUserSignedUpByFacebookObjectId);
|
||||
return rest.find(config, auth.master(config),
|
||||
'_Session', {sessionToken: r.response.sessionToken});
|
||||
}).then((response) => {
|
||||
expect(response.results.length).toEqual(1);
|
||||
var output = response.results[0];
|
||||
expect(output.user.objectId).toEqual(newUserSignedUpByFacebookObjectId);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -180,20 +180,18 @@ describe('Schema', () => {
|
||||
|
||||
it('will fail to create a class if that class was already created by an object', done => {
|
||||
config.database.loadSchema()
|
||||
.then(schema => {
|
||||
schema.validateObject('NewClass', {foo: 7})
|
||||
.then(() => {
|
||||
schema.reload()
|
||||
.then(schema => schema.addClassIfNotExists('NewClass', {
|
||||
foo: {type: 'String'}
|
||||
}))
|
||||
.catch(error => {
|
||||
expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
|
||||
expect(error.message).toEqual('Class NewClass already exists.');
|
||||
done();
|
||||
});
|
||||
.then(schema => {
|
||||
schema.validateObject('NewClass', { foo: 7 })
|
||||
.then(() => schema.reloadData())
|
||||
.then(() => schema.addClassIfNotExists('NewClass', {
|
||||
foo: { type: 'String' }
|
||||
}))
|
||||
.catch(error => {
|
||||
expect(error.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
|
||||
expect(error.message).toEqual('Class NewClass already exists.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('will resolve class creation races appropriately', done => {
|
||||
@@ -579,6 +577,38 @@ describe('Schema', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('can delete relation field when related _Join collection not exist', done => {
|
||||
config.database.loadSchema()
|
||||
.then(schema => {
|
||||
schema.addClassIfNotExists('NewClass', {
|
||||
relationField: {type: 'Relation', targetClass: '_User'}
|
||||
})
|
||||
.then(mongoObj => {
|
||||
expect(mongoObj).toEqual({
|
||||
_id: 'NewClass',
|
||||
objectId: 'string',
|
||||
updatedAt: 'string',
|
||||
createdAt: 'string',
|
||||
relationField: 'relation<_User>',
|
||||
});
|
||||
})
|
||||
.then(() => config.database.collectionExists('_Join:relationField:NewClass'))
|
||||
.then(exist => {
|
||||
expect(exist).toEqual(false);
|
||||
})
|
||||
.then(() => schema.deleteField('relationField', 'NewClass', config.database))
|
||||
.then(() => schema.reloadData())
|
||||
.then(() => {
|
||||
expect(schema['data']['NewClass']).toEqual({
|
||||
objectId: 'string',
|
||||
updatedAt: 'string',
|
||||
createdAt: 'string'
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('can delete string fields and resave as number field', done => {
|
||||
Parse.Object.disableSingleInstance();
|
||||
var obj1 = hasAllPODobject();
|
||||
|
||||
@@ -561,6 +561,63 @@ describe('schemas', () => {
|
||||
})
|
||||
});
|
||||
|
||||
it('lets you add fields to system schema', done => {
|
||||
request.post({
|
||||
url: 'http://localhost:8378/1/schemas/_User',
|
||||
headers: masterKeyHeaders,
|
||||
json: true
|
||||
}, (error, response, body) => {
|
||||
request.put({
|
||||
url: 'http://localhost:8378/1/schemas/_User',
|
||||
headers: masterKeyHeaders,
|
||||
json: true,
|
||||
body: {
|
||||
fields: {
|
||||
newField: {type: 'String'}
|
||||
}
|
||||
}
|
||||
}, (error, response, body) => {
|
||||
expect(body).toEqual({
|
||||
className: '_User',
|
||||
fields: {
|
||||
objectId: {type: 'String'},
|
||||
updatedAt: {type: 'Date'},
|
||||
createdAt: {type: 'Date'},
|
||||
username: {type: 'String'},
|
||||
password: {type: 'String'},
|
||||
authData: {type: 'Object'},
|
||||
email: {type: 'String'},
|
||||
emailVerified: {type: 'Boolean'},
|
||||
newField: {type: 'String'},
|
||||
ACL: {type: 'ACL'}
|
||||
}
|
||||
});
|
||||
request.get({
|
||||
url: 'http://localhost:8378/1/schemas/_User',
|
||||
headers: masterKeyHeaders,
|
||||
json: true
|
||||
}, (error, response, body) => {
|
||||
expect(body).toEqual({
|
||||
className: '_User',
|
||||
fields: {
|
||||
objectId: {type: 'String'},
|
||||
updatedAt: {type: 'Date'},
|
||||
createdAt: {type: 'Date'},
|
||||
username: {type: 'String'},
|
||||
password: {type: 'String'},
|
||||
authData: {type: 'Object'},
|
||||
email: {type: 'String'},
|
||||
emailVerified: {type: 'Boolean'},
|
||||
newField: {type: 'String'},
|
||||
ACL: {type: 'ACL'}
|
||||
}
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('lets you delete multiple fields and add fields', done => {
|
||||
var obj1 = hasAllPODobject();
|
||||
obj1.save()
|
||||
|
||||
Reference in New Issue
Block a user