Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ParsePlatform/parse-server
Browse files Browse the repository at this point in the history
…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 parse-community#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.
  • Loading branch information
asciimike committed Mar 6, 2016
2 parents 5b8ad9d + e92ee7e commit 8463535
Show file tree
Hide file tree
Showing 20 changed files with 737 additions and 466 deletions.
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
Make sure these boxes are checked before submitting your issue -- thanks for reporting issues back to Parse Server!

-[ ] You've met the [prerequisites](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#prerequisites).
- [ ] You've met the [prerequisites](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide#prerequisites).

-[ ] You're running the [latest version](https://github.com/ParsePlatform/parse-server/releases) of Parse Server.
- [ ] You're running the [latest version](https://github.com/ParsePlatform/parse-server/releases) of Parse Server.

-[ ] You've searched through [existing issues](https://github.com/ParsePlatform/parse-server/issues?utf8=%E2%9C%93&q=). Chances are that your issue has been reported or resolved before.
- [ ] You've searched through [existing issues](https://github.com/ParsePlatform/parse-server/issues?utf8=%E2%9C%93&q=). Chances are that your issue has been reported or resolved before.

#### Environment Setup

Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ node_js:
- "4.3"
env:
global:
- CODE_COVERAGE=1
- COVERAGE_OPTION='./node_modules/babel-istanbul/lib/cli.js cover -x **/spec/**'
matrix:
- MONGODB_VERSION=2.6.11
- MONGODB_VERSION=3.0.8
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ PARSE_SERVER_MAX_UPLOAD_SIZE

```

##### Configuring S3 Adapter

You can use the following environment variable setup the S3 adapter

```js
S3_ACCESS_KEY
S3_SECRET_KEY
S3_BUCKET
S3_REGION
S3_BUCKET_PREFIX
S3_DIRECT_ACCESS

```

## Contributing

We really want Parse to be yours, to see it grow and thrive in the open source community. Please see the [Contributing to Parse Server guide](CONTRIBUTING.md).
1 change: 0 additions & 1 deletion bin/parse-server
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
#!/usr/bin/env node
require("../lib/cli/parse-server");
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"files": [
"bin/",
"lib/",
"public_html/",
"views/",
"LICENSE",
"PATENTS",
"README.md"
Expand Down Expand Up @@ -54,12 +56,13 @@
"nodemon": "^1.8.1"
},
"scripts": {
"dev": "npm run build && bin/dev",
"dev": "npm run build && node bin/dev",
"build": "./node_modules/.bin/babel src/ -d lib/",
"pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.0.8} ./node_modules/.bin/mongodb-runner start",
"test": "cross-env NODE_ENV=test TESTING=1 ./node_modules/.bin/babel-node $(if [ \"$CODE_COVERAGE\" = \"1\" ]; then echo './node_modules/babel-istanbul/lib/cli.js cover -x **/spec/**'; fi;) ./node_modules/jasmine/bin/jasmine.js",
"posttest": "mongodb-runner stop",
"start": "./bin/parse-server",
"test": "cross-env NODE_ENV=test TESTING=1 ./node_modules/.bin/babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js",
"posttest": "./node_modules/.bin/mongodb-runner stop",
"coverage": "cross-env COVERAGE_OPTION='./node_modules/babel-istanbul/lib/cli.js cover -x **/spec/**' npm test",
"start": "node ./bin/parse-server",
"prepublish": "npm run build"
},
"engines": {
Expand Down
25 changes: 25 additions & 0 deletions spec/AdapterLoader.spec.js
Original file line number Diff line number Diff line change
@@ -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", ()=>{

Expand Down Expand Up @@ -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();
})
});
45 changes: 45 additions & 0 deletions spec/ParseAPI.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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();
});
});
});

});
92 changes: 85 additions & 7 deletions spec/ParseRole.spec.js
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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');
});
});

});

9 changes: 9 additions & 0 deletions spec/RestCreate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
Expand Down
56 changes: 43 additions & 13 deletions spec/Schema.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 8463535

Please sign in to comment.