Skip to content

Commit 843f289

Browse files
committed
Merge remote-tracking branch 'upstream/master' into test-configurations
2 parents c9dfac2 + 5ed037f commit 843f289

File tree

12 files changed

+260
-71
lines changed

12 files changed

+260
-71
lines changed

.github/parse-server-logo.png

11.3 KB
Loading

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## Parse Server Changelog
22

3+
### 2.1.1 (2/18/2016)
4+
5+
* Experimental: Schemas API support for DELETE operations
6+
* Fix: Session token issue fetching Users
7+
* Fix: Facebook auth validation
8+
* Fix: Invalid error when deleting missing session
9+
310
### 2.1.0 (2/17/2016)
411

512
* Feature: Support for additional OAuth providers

README.md

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
<img src="http://parse.com/assets/svgs/parse-infinity.svg" alt="Parse logo" height="70"/>
2-
3-
## Parse Server
1+
![Parse Server logo](.github/parse-server-logo.png?raw=true)
42

53
[![Build Status](https://img.shields.io/travis/ParsePlatform/parse-server/master.svg?style=flat)](https://travis-ci.org/ParsePlatform/parse-server)
64
[![Coverage Status](https://img.shields.io/codecov/c/github/ParsePlatform/parse-server/master.svg)](https://codecov.io/github/ParsePlatform/parse-server?branch=master)
@@ -12,25 +10,50 @@ Parse Server works with the Express web application framework. It can be added t
1210

1311
Read the announcement blog post here: http://blog.parse.com/announcements/introducing-parse-server-and-the-database-migration-tool/
1412

15-
## Documentation
13+
## Getting Started
1614

17-
Documentation for Parse Server is available in the [wiki](https://github.com/ParsePlatform/parse-server/wiki) for this repository. The [Parse Server guide](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide) is a good place to get started.
15+
[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/parseplatform/parse-server-example)
16+
[![Deploy to Azure](http://azuredeploy.net/deploybutton.png)](https://azuredeploy.net/?repository=https://github.com/parseplatform/parse-server-example)
17+
<a title="Deploy to AWS" href="https://console.aws.amazon.com/elasticbeanstalk/home?region=us-west-2#/newApplication?applicationName=ParseServer&solutionStackName=Node.js&tierName=WebServer&sourceBundleUrl=https://s3.amazonaws.com/elasticbeanstalk-samples-us-east-1/eb-parse-server-sample/parse-server-example.zip" target="_blank"><img src="http://d0.awsstatic.com/product-marketing/Elastic%20Beanstalk/deploy-to-aws.png" height="40"></a>
1818

19-
If you're interested in developing for Parse Server, the [Development guide](https://github.com/ParsePlatform/parse-server/wiki/Development-Guide) will help you get set up.
19+
You can create an instance of ParseServer, and mount it on a new or existing Express website:
20+
21+
```js
22+
var express = require('express');
23+
var ParseServer = require('parse-server').ParseServer;
24+
var app = express();
25+
26+
// Specify the connection string for your mongodb database
27+
// and the location to your Parse cloud code
28+
var api = new ParseServer({
29+
databaseURI: 'mongodb://localhost:27017/dev',
30+
cloud: '/home/myApp/cloud/main.js', // Provide an absolute path
31+
appId: 'myAppId',
32+
masterKey: '', //Add your master key here. Keep it secret!
33+
fileKey: 'optionalFileKey',
34+
serverURL: 'http://localhost:1337/parse' // Don't forget to change to https if needed
35+
});
2036

21-
### Example Project
37+
// Serve the Parse API on the /parse URL prefix
38+
app.use('/parse', api);
39+
40+
app.listen(1337, function() {
41+
console.log('parse-server-example running on port 1337.');
42+
});
43+
```
2244

23-
Check out the [parse-server-example project](https://github.com/ParsePlatform/parse-server-example) repository for an example of a Node.js application that uses the parse-server module on Express.
45+
## Documentation
2446

25-
### Migration Guide
47+
Documentation for Parse Server is available in the [wiki](https://github.com/ParsePlatform/parse-server/wiki) for this repository. The [Parse Server guide](https://github.com/ParsePlatform/parse-server/wiki/Parse-Server-Guide) is a good place to get started.
2648

27-
Migrate your existing Parse apps to your own Parse Server. The hosted version of Parse will be fully retired on January 28th, 2017. If you are planning to migrate an app, you need to begin work as soon as possible. Learn more in the [Migration guide](https://github.com/ParsePlatform/parse-server/wiki/Migrating-an-Existing-Parse-App).
49+
If you're interested in developing for Parse Server, the [Development guide](https://github.com/ParsePlatform/parse-server/wiki/Development-Guide) will help you get set up.
2850

51+
### Migration Guide
2952

53+
The hosted version of Parse will be fully retired on January 28th, 2017. If you are planning to migrate an app, you need to begin work as soon as possible. Learn more in the [Migration guide](https://github.com/ParsePlatform/parse-server/wiki/Migrating-an-Existing-Parse-App).
3054

3155
---
3256

33-
3457
#### Basic options:
3558

3659
* databaseURI (required) - The connection string for your database, i.e. `mongodb://user:[email protected]/dbname`
@@ -112,45 +135,8 @@ For more informations about custom auth please see the examples:
112135
* databaseAdapter (unfinished) - The backing store can be changed by creating an adapter class (see `DatabaseAdapter.js`)
113136
* loggerAdapter - The default behavior/transport (File) can be changed by creating an adapter class (see [`LoggerAdapter.js`](https://github.com/ParsePlatform/parse-server/blob/master/src/Adapters/Logger/LoggerAdapter.js))
114137
* enableAnonymousUsers - Defaults to true. Set to false to disable anonymous users.
115-
---
116-
117-
### Usage
118-
119-
You can create an instance of ParseServer, and mount it on a new or existing Express website:
120-
121-
```js
122-
var express = require('express');
123-
var ParseServer = require('parse-server').ParseServer;
124-
125-
var app = express();
126-
127-
var port = process.env.PORT || 1337;
128-
129-
// Specify the connection string for your mongodb database
130-
// and the location to your Parse cloud code
131-
var api = new ParseServer({
132-
databaseURI: 'mongodb://localhost:27017/dev',
133-
cloud: '/home/myApp/cloud/main.js', // Provide an absolute path
134-
appId: 'myAppId',
135-
masterKey: '', //Add your master key here. Keep it secret!
136-
fileKey: 'optionalFileKey',
137-
serverURL: 'http://localhost:' + port + '/parse' // Don't forget to change to https if needed
138-
});
139-
140-
// Serve the Parse API on the /parse URL prefix
141-
app.use('/parse', api);
142-
143-
// Hello world
144-
app.get('/', function(req, res) {
145-
res.status(200).send('Express is running here.');
146-
});
147-
148-
app.listen(port, function() {
149-
console.log('parse-server-example running on port ' + port + '.');
150-
});
151-
152-
```
153138

139+
---
154140

155141
#### Standalone usage
156142

@@ -173,8 +159,7 @@ PARSE_SERVER_FACEBOOK_APP_IDS // string of comma separated list
173159
```
174160

175161

176-
177-
Alernatively, you can use the `PARSE_SERVER_OPTIONS` environment variable set to the JSON of your configuration (see Usage).
162+
Alternatively, you can use the `PARSE_SERVER_OPTIONS` environment variable set to the JSON of your configuration (see Usage).
178163

179164
To start the server, just run `npm start`.
180165

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-server",
3-
"version": "2.1.0",
3+
"version": "2.1.1",
44
"description": "An express module providing a Parse-compatible API server",
55
"main": "lib/index.js",
66
"repository": {

spec/ParseAPI.spec.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ describe('miscellaneous', function() {
587587
done();
588588
});
589589
});
590-
590+
591591
it('test cloud function query parameters', (done) => {
592592
Parse.Cloud.define('echoParams', (req, res) => {
593593
res.success(req.params);
@@ -621,8 +621,8 @@ describe('miscellaneous', function() {
621621
// Register a function with validation
622622
Parse.Cloud.define('functionWithParameterValidation', (req, res) => {
623623
res.success('works');
624-
}, (params) => {
625-
return params.success === 100;
624+
}, (request) => {
625+
return request.params.success === 100;
626626
});
627627

628628
Parse.Cloud.run('functionWithParameterValidation', {"success":100}).then((s) => {
@@ -638,8 +638,8 @@ describe('miscellaneous', function() {
638638
// Register a function with validation
639639
Parse.Cloud.define('functionWithParameterValidationFailure', (req, res) => {
640640
res.success('noway');
641-
}, (params) => {
642-
return params.success === 100;
641+
}, (request) => {
642+
return request.params.success === 100;
643643
});
644644

645645
Parse.Cloud.run('functionWithParameterValidationFailure', {"success":500}).then((s) => {
@@ -721,4 +721,15 @@ describe('miscellaneous', function() {
721721
});
722722
});
723723

724+
it('fails on invalid function', done => {
725+
Parse.Cloud.run('somethingThatDoesDefinitelyNotExist').then((s) => {
726+
fail('This should have never suceeded');
727+
done();
728+
}, (e) => {
729+
expect(e.code).toEqual(Parse.Error.SCRIPT_FAILED);
730+
expect(e.message).toEqual('Invalid function.');
731+
done();
732+
});
733+
});
734+
724735
});

spec/schemas.spec.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
var Parse = require('parse/node').Parse;
22
var request = require('request');
33
var dd = require('deep-diff');
4+
var Config = require('../src/Config');
5+
6+
var config = new Config('test');
47

58
var hasAllPODobject = () => {
69
var obj = new Parse.Object('HasAllPOD');
@@ -633,4 +636,102 @@ describe('schemas', () => {
633636
});
634637
});
635638
});
639+
640+
it('requires the master key to delete schemas', done => {
641+
request.del({
642+
url: 'http://localhost:8378/1/schemas/DoesntMatter',
643+
headers: noAuthHeaders,
644+
json: true,
645+
}, (error, response, body) => {
646+
expect(response.statusCode).toEqual(403);
647+
expect(body.error).toEqual('unauthorized');
648+
done();
649+
});
650+
});
651+
652+
it('refuses to delete non-empty collection', done => {
653+
var obj = hasAllPODobject();
654+
obj.save()
655+
.then(() => {
656+
request.del({
657+
url: 'http://localhost:8378/1/schemas/HasAllPOD',
658+
headers: masterKeyHeaders,
659+
json: true,
660+
}, (error, response, body) => {
661+
expect(response.statusCode).toEqual(400);
662+
expect(body.code).toEqual(255);
663+
expect(body.error).toEqual('class HasAllPOD not empty, contains 1 objects, cannot drop schema');
664+
done();
665+
});
666+
});
667+
});
668+
669+
it('fails when deleting collections with invalid class names', done => {
670+
request.del({
671+
url: 'http://localhost:8378/1/schemas/_GlobalConfig',
672+
headers: masterKeyHeaders,
673+
json: true,
674+
}, (error, response, body) => {
675+
expect(response.statusCode).toEqual(400);
676+
expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
677+
expect(body.error).toEqual('Invalid classname: _GlobalConfig, classnames can only have alphanumeric characters and _, and must start with an alpha character ');
678+
done();
679+
})
680+
});
681+
682+
it('does not fail when deleting nonexistant collections', done => {
683+
request.del({
684+
url: 'http://localhost:8378/1/schemas/Missing',
685+
headers: masterKeyHeaders,
686+
json: true,
687+
}, (error, response, body) => {
688+
expect(response.statusCode).toEqual(200);
689+
expect(body).toEqual({});
690+
done();
691+
});
692+
});
693+
694+
it('deletes collections including join tables', done => {
695+
var obj = new Parse.Object('MyClass');
696+
obj.set('data', 'data');
697+
obj.save()
698+
.then(() => {
699+
var obj2 = new Parse.Object('MyOtherClass');
700+
var relation = obj2.relation('aRelation');
701+
relation.add(obj);
702+
return obj2.save();
703+
})
704+
.then(obj2 => obj2.destroy())
705+
.then(() => {
706+
request.del({
707+
url: 'http://localhost:8378/1/schemas/MyOtherClass',
708+
headers: masterKeyHeaders,
709+
json: true,
710+
}, (error, response, body) => {
711+
expect(response.statusCode).toEqual(200);
712+
expect(response.body).toEqual({});
713+
config.database.db.collection('test__Join:aRelation:MyOtherClass', { strict: true }, (err, coll) => {
714+
//Expect Join table to be gone
715+
expect(err).not.toEqual(null);
716+
config.database.db.collection('test_MyOtherClass', { strict: true }, (err, coll) => {
717+
// Expect data table to be gone
718+
expect(err).not.toEqual(null);
719+
request.get({
720+
url: 'http://localhost:8378/1/schemas/MyOtherClass',
721+
headers: masterKeyHeaders,
722+
json: true,
723+
}, (error, response, body) => {
724+
//Expect _SCHEMA entry to be gone.
725+
expect(response.statusCode).toEqual(400);
726+
expect(body.code).toEqual(Parse.Error.INVALID_CLASS_NAME);
727+
expect(body.error).toEqual('class MyOtherClass does not exist');
728+
done();
729+
});
730+
});
731+
});
732+
});
733+
}, error => {
734+
fail(error);
735+
});
736+
});
636737
});

src/Adapters/Files/S3Adapter.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import * as AWS from 'aws-sdk';
66
import { FilesAdapter } from './FilesAdapter';
77

88
const DEFAULT_S3_REGION = "us-east-1";
9-
const DEFAULT_S3_BUCKET = "parse-files";
109

1110
export class S3Adapter extends FilesAdapter {
1211
// Creates an S3 session.
@@ -15,8 +14,8 @@ export class S3Adapter extends FilesAdapter {
1514
constructor(
1615
accessKey,
1716
secretKey,
17+
bucket,
1818
{ region = DEFAULT_S3_REGION,
19-
bucket = DEFAULT_S3_BUCKET,
2019
bucketPrefix = '',
2120
directAccess = false } = {}
2221
) {

src/ExportAdapter.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ ExportAdapter.prototype.destroy = function(className, query, options = {}) {
306306

307307
return coll.remove(mongoWhere);
308308
}).then((resp) => {
309-
if (resp.result.n === 0) {
309+
//Check _Session to avoid changing password failed without any session.
310+
if (resp.result.n === 0 && className !== "_Session") {
310311
return Promise.reject(
311312
new Parse.Error(Parse.Error.OBJECT_NOT_FOUND,
312313
'Object not found.'));

src/Schema.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ Schema.prototype.deleteField = function(fieldName, className, database, prefix)
521521
});
522522
}
523523

524-
if (schema.data[className][fieldName].startsWith('relation')) {
524+
if (schema.data[className][fieldName].startsWith('relation<')) {
525525
//For relations, drop the _Join table
526526
return database.dropCollection(prefix + '_Join:' + fieldName + ':' + className)
527527
//Save the _SCHEMA object
@@ -714,6 +714,7 @@ function getObjectType(obj) {
714714
module.exports = {
715715
load: load,
716716
classNameIsValid: classNameIsValid,
717+
invalidClassNameMessage: invalidClassNameMessage,
717718
mongoSchemaFromFieldsAndClassName: mongoSchemaFromFieldsAndClassName,
718719
schemaAPITypeToMongoFieldType: schemaAPITypeToMongoFieldType,
719720
buildMergedSchemaObject: buildMergedSchemaObject,

src/functions.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,22 @@ var router = new PromiseRouter();
1010
function handleCloudFunction(req) {
1111
if (Parse.Cloud.Functions[req.params.functionName]) {
1212

13-
const params = Object.assign({}, req.body, req.query);
14-
13+
var request = {
14+
params: Object.assign({}, req.body, req.query),
15+
master: req.auth && req.auth.isMaster,
16+
user: req.auth && req.auth.user,
17+
installationId: req.info.installationId
18+
};
19+
1520
if (Parse.Cloud.Validators[req.params.functionName]) {
16-
var result = Parse.Cloud.Validators[req.params.functionName](params);
21+
var result = Parse.Cloud.Validators[req.params.functionName](request);
1722
if (!result) {
1823
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'Validation failed.');
1924
}
2025
}
2126

2227
return new Promise(function (resolve, reject) {
2328
var response = createResponseObject(resolve, reject);
24-
var request = {
25-
params: params,
26-
master: req.auth && req.auth.isMaster,
27-
user: req.auth && req.auth.user,
28-
installationId: req.info.installationId
29-
};
3029
Parse.Cloud.Functions[req.params.functionName](request, response);
3130
});
3231
} else {

src/middlewares.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function handleParseHeaders(req, res, next) {
2626
restAPIKey: req.get('X-Parse-REST-API-Key')
2727
};
2828

29-
if (req.body && req.body._noBody) {
29+
if (req.body) {
3030
// Unity SDK sends a _noBody key which needs to be removed.
3131
// Unclear at this point if action needs to be taken.
3232
delete req.body._noBody;

0 commit comments

Comments
 (0)