Migrate to new cloud code interfaces
removes job status object, moves messasge method on req object Adds 3.0.0 migration guide Fixes nits about 3.0.0 documentation Adds update guide to README
This commit is contained in:
226
3.0.0.md
Normal file
226
3.0.0.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Upgrading Parse Server to version 3.0.0
|
||||
|
||||
parse-server 3.0.0 comes also with the JS SDK version 2.0 which requires a migration. Follow the migration guide [here](https://github.com/parse-community/Parse-SDK-JS/blob/master/2.0.0.md).
|
||||
|
||||
With the 3.0.0, parse-server has completely revamped it's cloud code interface. Gone are the backbone style calls, welcome promises and async/await.
|
||||
|
||||
In order to leverage those new nodejs features, you'll need to run at least node 8.10. We've dropped the support of node 6 a few months ago, so if you haven't made the change yet, now would be a really good time to take the plunge.
|
||||
|
||||
## Migrating Cloud Code Hooks
|
||||
|
||||
### Synchronous validations:
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.beforeSave('MyClassName', function(request, response) {
|
||||
if (!passesValidation(req.object)) {
|
||||
response.error('Ooops something went wrong');
|
||||
} else {
|
||||
response.success();
|
||||
}
|
||||
});
|
||||
|
||||
// after
|
||||
Parse.Cloud.beforeSave('MyClassName', (request) => {
|
||||
if (!passesValidation(req.object)) {
|
||||
throw 'Ooops something went wrong';
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
All methods are wrapped in promises, so you can freely `throw` `Error`, `Parse.Error` or `string` to mark an error.
|
||||
|
||||
### Asynchronous validations:
|
||||
|
||||
For asynchronous code, you can use promises or async / await.
|
||||
|
||||
Consider the following beforeSave call that would replace the contents of a fileURL with a proper copy of the image as a Parse.File.
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.beforeSave('Post', function(request, response) {
|
||||
Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL'),
|
||||
success: function(contents) {
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
request.object.set('file', file);
|
||||
response.success();
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
As we can see the current way, with backbone style callbacks is quite tough to read and maintain.
|
||||
It's also not really trivial to handle errors, as you need to pass the response.error to each error handlers.
|
||||
|
||||
Now it can be modernized with promises:
|
||||
|
||||
```js
|
||||
// after (with promises)
|
||||
Parse.Cloud.beforeSave('MyClassName', (request) => {
|
||||
return Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL')
|
||||
}).then((contents) => {
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
request.object.set('file', file);
|
||||
return file.save();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
And you can even make it better with async/await.
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.beforeSave('MyClassName', async (request) => {
|
||||
const contents = await Parse.Cloud.httpRequest({
|
||||
url: request.object.get('fileURL')
|
||||
});
|
||||
|
||||
const file = new Parse.File('image.png', { base64: contents.buffer.toString('base64') });
|
||||
request.object.set('file', file);
|
||||
await file.save();
|
||||
});
|
||||
```
|
||||
|
||||
## Aborting hooks and functions
|
||||
|
||||
In order to abort a `beforeSave` or any hook, you now need to throw an error:
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.beforeSave('MyClassName', async (request) => {
|
||||
// valid, will result in a Parse.Error(SCRIPT_FAILED, 'Something went wrong')
|
||||
throw 'Something went wrong'
|
||||
// also valid, will fail with Parse.Error(SCRIPT_FAILED, 'Something else went wrong')
|
||||
throw new Error('Something else went wrong')
|
||||
// using a Parse.Error is also valid
|
||||
throw new Parse.Error(1001, 'My error')
|
||||
});
|
||||
```
|
||||
|
||||
## Migrating Functions
|
||||
|
||||
Cloud Functions can be migrated the same way as cloud code hooks.
|
||||
In functions, the response object is not passed anymore, as it is in cloud code hooks
|
||||
|
||||
Continuing with the image downloader example:
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.define('downloadImage', function(request, response) {
|
||||
Parse.Cloud.httpRequest({
|
||||
url: request.params.url,
|
||||
success: function(contents) {
|
||||
const file = new Parse.File(request.params.name, { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
response.success(file);
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
},
|
||||
error: response.error
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
You would call this method with:
|
||||
|
||||
```js
|
||||
Parse.Cloud.run({
|
||||
url: '....',
|
||||
name: 'my-file'
|
||||
});
|
||||
```
|
||||
|
||||
To migrate this function you would follow the same practices as the ones before, and we'll jump right away to the async/await implementation:
|
||||
|
||||
```js
|
||||
// after with async/await
|
||||
Parse.Cloud.beforeSave('MyClassName', async (request) => {
|
||||
const {
|
||||
url, name
|
||||
} = request.params;
|
||||
const response = await Parse.Cloud.httpRequest({ url });
|
||||
|
||||
const file = new Parse.File(name, { base64: response.buffer.toString('base64') });
|
||||
await file.save();
|
||||
return file;
|
||||
});
|
||||
```
|
||||
|
||||
## Migrating jobs
|
||||
|
||||
As with hooks and functions, jobs don't have a status object anymore.
|
||||
The message method has been moved to the request object.
|
||||
|
||||
```js
|
||||
// before
|
||||
Parse.Cloud.job('downloadImageJob', function(request, status) {
|
||||
var query = new Parse.Query('ImagesToDownload');
|
||||
query.find({
|
||||
success: function(images) {
|
||||
var done = 0;
|
||||
for (var i = 0; i<images.length; i++) {
|
||||
var image = images[i];
|
||||
status.message('Doing '+image.get('url'));
|
||||
Parse.Cloud.httpRequest({
|
||||
url: image.get('url'),
|
||||
success: function(contents) {
|
||||
status.message('Got '+image.get('url'));
|
||||
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
|
||||
file.save({
|
||||
success: function() {
|
||||
status.message('Saved '+image.get('url'));
|
||||
done++;
|
||||
if (done == images.length) {
|
||||
status.success();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
response.message('Error '+image.get('url'));
|
||||
done++;
|
||||
if (done == images.length) {
|
||||
status.error();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
error: status.error
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
Parse.Cloud.job('downloadImageJob', async function(request) {
|
||||
const query = new Parse.Query('ImagesToDownload');
|
||||
const images = await query.find();
|
||||
const promises = images.map(async (image) => {
|
||||
request.message('Doing ' + image.get('url'));
|
||||
const contents = await Parse.Cloud.httpRequest({
|
||||
url: image.get('url')
|
||||
});
|
||||
request.message('Got ' + image.get('url'));
|
||||
const file = new Parse.File(image.get('name'), { base64: contents.buffer.toString('base64') });
|
||||
await file.save();
|
||||
request.message('Saved ' + image.get('url'));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
As you can see the new implementation is more concise, easier to read and maintain.
|
||||
|
||||
If you encounter a problem or discover an issue with this guide, or with any Parse Community project, feel free to [reach out on github](https://github.com/parse-community/parse-server/issues/new/choose)
|
||||
|
||||
@@ -35,6 +35,7 @@ Parse Server works with the Express web application framework. It can be added t
|
||||
- [Ride the Bleeding Edge](#want-to-ride-the-bleeding-edge)
|
||||
- [Contributing](#contributing)
|
||||
- [Backers](#backers)
|
||||
- [Upgrading to 3.0.0](#upgrading-to-3.0.0)
|
||||
- [Sponsors](#sponsors)
|
||||
|
||||
# Getting Started
|
||||
@@ -380,6 +381,14 @@ Parse Server allows developers to choose from several options when hosting files
|
||||
|
||||
`GridStoreAdapter` is used by default and requires no setup, but if you're interested in using S3 or Google Cloud Storage, additional configuration information is available in the [Parse Server guide](http://docs.parseplatform.org/parse-server/guide/#configuring-file-adapters).
|
||||
|
||||
# Upgrading to 3.0.0
|
||||
|
||||
Starting 3.0.0, parse-server uses the JS SDK version 2.0.
|
||||
In short, parse SDK v2.0 removes the backbone style callbacks as well as the Parse.Promise object in favor of native promises.
|
||||
All the Cloud Code interfaces also have been updated to reflect those changes, and all backbone style response objects are removed and replaced by Promise style resolution.
|
||||
|
||||
We have written up a [migration guide](3.0.0.md), hoping this will help you transition to the next major release.
|
||||
|
||||
# Support
|
||||
|
||||
For implementation related questions or technical support, please refer to the [Stack Overflow](http://stackoverflow.com/questions/tagged/parse.com) and [Server Fault](https://serverfault.com/tags/parse) communities.
|
||||
|
||||
@@ -25,8 +25,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('can create functions', done => {
|
||||
Parse.Cloud.define('hello', (req, res) => {
|
||||
res.success('Hello world!');
|
||||
Parse.Cloud.define('hello', () => {
|
||||
return 'Hello world!';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('hello', {}).then(result => {
|
||||
@@ -44,8 +44,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('basic beforeSave rejection', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveFail', function(req, res) {
|
||||
res.error('You shall not pass!');
|
||||
Parse.Cloud.beforeSave('BeforeSaveFail', function() {
|
||||
throw new Error('You shall not pass!');
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveFail');
|
||||
@@ -59,25 +59,25 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('returns an error', (done) => {
|
||||
Parse.Cloud.define('cloudCodeWithError', (req, res) => {
|
||||
Parse.Cloud.define('cloudCodeWithError', () => {
|
||||
/* eslint-disable no-undef */
|
||||
foo.bar();
|
||||
/* eslint-enable no-undef */
|
||||
res.success('I better throw an error.');
|
||||
return 'I better throw an error.';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('cloudCodeWithError')
|
||||
.then(
|
||||
() => done.fail('should not succeed'),
|
||||
e => {
|
||||
expect(e).toEqual(new Parse.Error(1, undefined));
|
||||
expect(e).toEqual(new Parse.Error(141, 'foo is not defined'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('beforeSave rejection with custom error code', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveFailWithErrorCode', function (req, res) {
|
||||
res.error(999, 'Nope');
|
||||
Parse.Cloud.beforeSave('BeforeSaveFailWithErrorCode', function () {
|
||||
throw new Parse.Error(999, 'Nope');
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveFailWithErrorCode');
|
||||
@@ -93,12 +93,12 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('basic beforeSave rejection via promise', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveFailWithPromise', function (req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveFailWithPromise', function () {
|
||||
const query = new Parse.Query('Yolo');
|
||||
query.find().then(() => {
|
||||
res.error('Nope');
|
||||
return query.find().then(() => {
|
||||
throw 'Nope';
|
||||
}, () => {
|
||||
res.success();
|
||||
return Promise.response();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -115,9 +115,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeSave changed object success', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
|
||||
req.object.set('foo', 'baz');
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveChanged');
|
||||
@@ -138,9 +137,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeSave returns value on create and update', (done) => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
|
||||
req.object.set('foo', 'baz');
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveChanged');
|
||||
@@ -327,9 +325,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeSave happens on update', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
|
||||
req.object.set('foo', 'baz');
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveChanged');
|
||||
@@ -350,8 +347,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeDelete failure', function(done) {
|
||||
Parse.Cloud.beforeDelete('BeforeDeleteFail', function(req, res) {
|
||||
res.error('Nope');
|
||||
Parse.Cloud.beforeDelete('BeforeDeleteFail', function() {
|
||||
throw 'Nope';
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeDeleteFail');
|
||||
@@ -383,12 +380,10 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('basic beforeDelete rejection via promise', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeDeleteFailWithPromise', function (req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeDeleteFailWithPromise', function () {
|
||||
const query = new Parse.Query('Yolo');
|
||||
query.find().then(() => {
|
||||
res.error('Nope');
|
||||
}, () => {
|
||||
res.success();
|
||||
return query.find().then(() => {
|
||||
throw 'Nope';
|
||||
});
|
||||
});
|
||||
|
||||
@@ -431,8 +426,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test cloud function return types', function(done) {
|
||||
Parse.Cloud.define('foo', function(req, res) {
|
||||
res.success({
|
||||
Parse.Cloud.define('foo', function() {
|
||||
return {
|
||||
object: {
|
||||
__type: 'Object',
|
||||
className: 'Foo',
|
||||
@@ -452,7 +447,7 @@ describe('Cloud Code', () => {
|
||||
x: 2
|
||||
}],
|
||||
a: 2
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
Parse.Cloud.run('foo').then((result) => {
|
||||
@@ -476,7 +471,7 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test cloud function request params types', function(done) {
|
||||
Parse.Cloud.define('params', function(req, res) {
|
||||
Parse.Cloud.define('params', function(req) {
|
||||
expect(req.params.date instanceof Date).toBe(true);
|
||||
expect(req.params.date.getTime()).toBe(1463907600000);
|
||||
expect(req.params.dateList[0] instanceof Date).toBe(true);
|
||||
@@ -497,7 +492,7 @@ describe('Cloud Code', () => {
|
||||
expect(Array.isArray(req.params.arrayOfArray)).toBe(true);
|
||||
expect(Array.isArray(req.params.arrayOfArray[0])).toBe(true);
|
||||
expect(Array.isArray(req.params.arrayOfArray[1])).toBe(true);
|
||||
return res.success({});
|
||||
return {};
|
||||
});
|
||||
|
||||
const params = {
|
||||
@@ -550,12 +545,12 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test cloud function should echo keys', function(done) {
|
||||
Parse.Cloud.define('echoKeys', function(req, res){
|
||||
return res.success({
|
||||
Parse.Cloud.define('echoKeys', function() {
|
||||
return {
|
||||
applicationId: Parse.applicationId,
|
||||
masterKey: Parse.masterKey,
|
||||
javascriptKey: Parse.javascriptKey
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
Parse.Cloud.run('echoKeys').then((result) => {
|
||||
@@ -567,15 +562,14 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('should properly create an object in before save', done => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
|
||||
req.object.set('foo', 'baz');
|
||||
res.success();
|
||||
});
|
||||
|
||||
Parse.Cloud.define('createBeforeSaveChangedObject', function(req, res){
|
||||
Parse.Cloud.define('createBeforeSaveChangedObject', function() {
|
||||
const obj = new Parse.Object('BeforeSaveChanged');
|
||||
obj.save().then(() => {
|
||||
res.success(obj);
|
||||
return obj.save().then(() => {
|
||||
return obj;
|
||||
})
|
||||
})
|
||||
|
||||
@@ -588,7 +582,7 @@ describe('Cloud Code', () => {
|
||||
it('dirtyKeys are set on update', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.beforeSave('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req) => {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
expect(object.get('fooAgain')).toEqual('barAgain');
|
||||
@@ -601,10 +595,9 @@ describe('Cloud Code', () => {
|
||||
expect(object.dirty('foo')).toBeTruthy();
|
||||
expect(object.get('foo')).toEqual('baz');
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -625,8 +618,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeSave unchanged success', function(done) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged', function(req, res) {
|
||||
res.success();
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged', function() {
|
||||
return;
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveUnchanged');
|
||||
@@ -640,8 +633,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test beforeDelete success', function(done) {
|
||||
Parse.Cloud.beforeDelete('BeforeDeleteTest', function(req, res) {
|
||||
res.success();
|
||||
Parse.Cloud.beforeDelete('BeforeDeleteTest', function() {
|
||||
return;
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeDeleteTest');
|
||||
@@ -658,11 +651,11 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('test save triggers get user', async (done) => {
|
||||
Parse.Cloud.beforeSave('SaveTriggerUser', function(req, res) {
|
||||
Parse.Cloud.beforeSave('SaveTriggerUser', function(req) {
|
||||
if (req.user && req.user.id) {
|
||||
res.success();
|
||||
return;
|
||||
} else {
|
||||
res.error('No user present on request object for beforeSave.');
|
||||
throw new Error('No user present on request object for beforeSave.');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -687,9 +680,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('beforeSave change propagates through the save response', (done) => {
|
||||
Parse.Cloud.beforeSave('ChangingObject', function(request, response) {
|
||||
Parse.Cloud.beforeSave('ChangingObject', function(request) {
|
||||
request.object.set('foo', 'baz');
|
||||
response.success();
|
||||
});
|
||||
const obj = new Parse.Object('ChangingObject');
|
||||
obj.save({ foo: 'bar' }).then((objAgain) => {
|
||||
@@ -702,10 +694,9 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('beforeSave change propagates through the afterSave #1931', (done) => {
|
||||
Parse.Cloud.beforeSave('ChangingObject', function(request, response) {
|
||||
Parse.Cloud.beforeSave('ChangingObject', function(request) {
|
||||
request.object.unset('file');
|
||||
request.object.unset('date');
|
||||
response.success();
|
||||
});
|
||||
|
||||
Parse.Cloud.afterSave('ChangingObject', function(request) {
|
||||
@@ -728,8 +719,8 @@ describe('Cloud Code', () => {
|
||||
|
||||
it('test cloud function parameter validation success', (done) => {
|
||||
// Register a function with validation
|
||||
Parse.Cloud.define('functionWithParameterValidation', (req, res) => {
|
||||
res.success('works');
|
||||
Parse.Cloud.define('functionWithParameterValidation', () => {
|
||||
return 'works';
|
||||
}, (request) => {
|
||||
return request.params.success === 100;
|
||||
});
|
||||
@@ -743,8 +734,8 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('doesnt receive stale user in cloud code functions after user has been updated with master key (regression test for #1836)', done => {
|
||||
Parse.Cloud.define('testQuery', function(request, response) {
|
||||
response.success(request.user.get('data'));
|
||||
Parse.Cloud.define('testQuery', function(request) {
|
||||
return request.user.get('data');
|
||||
});
|
||||
|
||||
Parse.User.signUp('user', 'pass')
|
||||
@@ -772,8 +763,8 @@ describe('Cloud Code', () => {
|
||||
const cacheAdapter = new InMemoryCacheAdapter({ ttl: 100000000 });
|
||||
reconfigureServer({ cacheAdapter })
|
||||
.then(() => {
|
||||
Parse.Cloud.define('checkStaleUser', (request, response) => {
|
||||
response.success(request.user.get('data'));
|
||||
Parse.Cloud.define('checkStaleUser', (request) => {
|
||||
return request.user.get('data');
|
||||
});
|
||||
|
||||
user = new Parse.User();
|
||||
@@ -836,9 +827,7 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('trivial beforeSave should not affect fetched pointers (regression test for #1238)', done => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged', (req, res) => {
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged', () => {});
|
||||
|
||||
const TestObject = Parse.Object.extend("TestObject");
|
||||
const NoBeforeSaveObject = Parse.Object.extend("NoBeforeSave");
|
||||
@@ -868,13 +857,10 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('beforeSave should not affect fetched pointers', done => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged', (req, res) => {
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.beforeSave('BeforeSaveUnchanged',() => {});
|
||||
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', function(req) {
|
||||
req.object.set('foo', 'baz');
|
||||
res.success();
|
||||
});
|
||||
|
||||
const TestObject = Parse.Object.extend("TestObject");
|
||||
@@ -910,15 +896,14 @@ describe('Cloud Code', () => {
|
||||
const NoBeforeSaveObject = Parse.Object.extend('NoBeforeSave');
|
||||
const BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
||||
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req) => {
|
||||
const object = req.object;
|
||||
object.set('before', 'save');
|
||||
res.success();
|
||||
});
|
||||
|
||||
Parse.Cloud.define('removeme', (req, res) => {
|
||||
const testObject = new TestObject();
|
||||
testObject.save()
|
||||
return testObject.save()
|
||||
.then(testObject => {
|
||||
const object = new NoBeforeSaveObject({remove: testObject});
|
||||
return object.save();
|
||||
@@ -927,14 +912,12 @@ describe('Cloud Code', () => {
|
||||
object.unset('remove');
|
||||
return object.save();
|
||||
})
|
||||
.then(object => {
|
||||
res.success(object);
|
||||
}).catch(res.error);
|
||||
.catch(res.error);
|
||||
});
|
||||
|
||||
Parse.Cloud.define('removeme2', (req, res) => {
|
||||
const testObject = new TestObject();
|
||||
testObject.save()
|
||||
return testObject.save()
|
||||
.then(testObject => {
|
||||
const object = new BeforeSaveObject({remove: testObject});
|
||||
return object.save();
|
||||
@@ -943,9 +926,7 @@ describe('Cloud Code', () => {
|
||||
object.unset('remove');
|
||||
return object.save();
|
||||
})
|
||||
.then(object => {
|
||||
res.success(object);
|
||||
}).catch(res.error);
|
||||
.catch(res.error);
|
||||
});
|
||||
|
||||
Parse.Cloud.run('removeme')
|
||||
@@ -972,11 +953,10 @@ describe('Cloud Code', () => {
|
||||
const TestObject = Parse.Object.extend('TestObject');
|
||||
const BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
||||
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req) => {
|
||||
const object = req.object;
|
||||
object.set('before', 'save');
|
||||
object.unset('remove');
|
||||
res.success();
|
||||
});
|
||||
|
||||
let object;
|
||||
@@ -1001,14 +981,13 @@ describe('Cloud Code', () => {
|
||||
const TestObject = Parse.Object.extend('TestObject');
|
||||
const BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
|
||||
let testObj;
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req, res) => {
|
||||
Parse.Cloud.beforeSave('BeforeSaveChanged', (req) => {
|
||||
const object = req.object;
|
||||
object.set('before', 'save');
|
||||
testObj = new TestObject();
|
||||
testObj.save().then(() => {
|
||||
return testObj.save().then(() => {
|
||||
object.relation('testsRelation').add(testObj);
|
||||
res.success();
|
||||
}, res.error);
|
||||
});
|
||||
});
|
||||
|
||||
const object = new BeforeSaveObject();
|
||||
@@ -1027,23 +1006,19 @@ describe('Cloud Code', () => {
|
||||
* does not result in that key being omitted from the response.
|
||||
*/
|
||||
it('before save increment does not return undefined', (done) => {
|
||||
Parse.Cloud.define("cloudIncrementClassFunction", function (req, res) {
|
||||
Parse.Cloud.define("cloudIncrementClassFunction", function (req) {
|
||||
const CloudIncrementClass = Parse.Object.extend("CloudIncrementClass");
|
||||
const obj = new CloudIncrementClass();
|
||||
obj.id = req.params.objectId;
|
||||
obj.save().then(
|
||||
function (savedObj) {
|
||||
res.success(savedObj);
|
||||
});
|
||||
return obj.save();
|
||||
});
|
||||
|
||||
Parse.Cloud.beforeSave("CloudIncrementClass", function (req, res) {
|
||||
Parse.Cloud.beforeSave("CloudIncrementClass", function (req) {
|
||||
const obj = req.object;
|
||||
if(!req.master) {
|
||||
obj.increment('points', -10);
|
||||
obj.increment('num', -9);
|
||||
}
|
||||
res.success();
|
||||
});
|
||||
|
||||
const CloudIncrementClass = Parse.Object.extend('CloudIncrementClass');
|
||||
@@ -1077,9 +1052,7 @@ describe('Cloud Code', () => {
|
||||
describe('cloud jobs', () => {
|
||||
it('should define a job', (done) => {
|
||||
expect(() => {
|
||||
Parse.Cloud.job('myJob', (req, res) => {
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.job('myJob', () => {});
|
||||
}).not.toThrow();
|
||||
|
||||
rp.post({
|
||||
@@ -1098,9 +1071,7 @@ describe('Cloud Code', () => {
|
||||
|
||||
it('should not run without master key', (done) => {
|
||||
expect(() => {
|
||||
Parse.Cloud.job('myJob', (req, res) => {
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.job('myJob', () => {});
|
||||
}).not.toThrow();
|
||||
|
||||
rp.post({
|
||||
@@ -1124,10 +1095,8 @@ describe('Cloud Code', () => {
|
||||
expect(req.functionName).toBeUndefined();
|
||||
expect(req.jobName).toBe('myJob');
|
||||
expect(typeof req.jobId).toBe('string');
|
||||
expect(typeof res.success).toBe('function');
|
||||
expect(typeof res.error).toBe('function');
|
||||
expect(typeof res.message).toBe('function');
|
||||
res.success();
|
||||
expect(typeof req.message).toBe('function');
|
||||
expect(typeof res).toBe('undefined');
|
||||
done();
|
||||
});
|
||||
}).not.toThrow();
|
||||
@@ -1151,10 +1120,8 @@ describe('Cloud Code', () => {
|
||||
expect(req.functionName).toBeUndefined();
|
||||
expect(req.jobName).toBe('myJob');
|
||||
expect(typeof req.jobId).toBe('string');
|
||||
expect(typeof res.success).toBe('function');
|
||||
expect(typeof res.error).toBe('function');
|
||||
expect(typeof res.message).toBe('function');
|
||||
res.success();
|
||||
expect(typeof req.message).toBe('function');
|
||||
expect(typeof res).toBe('undefined');
|
||||
done();
|
||||
});
|
||||
}).not.toThrow();
|
||||
@@ -1169,16 +1136,16 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('should set the message / success on the job', (done) => {
|
||||
Parse.Cloud.job('myJob', (req, res) => {
|
||||
res.message('hello');
|
||||
res.message().then(() => {
|
||||
Parse.Cloud.job('myJob', (req) => {
|
||||
req.message('hello');
|
||||
const promise = req.message().then(() => {
|
||||
return getJobStatus(req.jobId);
|
||||
}).then((jobStatus) => {
|
||||
expect(jobStatus.get('message')).toEqual('hello');
|
||||
expect(jobStatus.get('status')).toEqual('running');
|
||||
return res.success().then(() => {
|
||||
return getJobStatus(req.jobId);
|
||||
});
|
||||
});
|
||||
promise.then(() => {
|
||||
return getJobStatus(req.jobId);
|
||||
}).then((jobStatus) => {
|
||||
expect(jobStatus.get('message')).toEqual('hello');
|
||||
expect(jobStatus.get('status')).toEqual('succeeded');
|
||||
@@ -1188,6 +1155,7 @@ describe('Cloud Code', () => {
|
||||
jfail(err);
|
||||
done();
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
rp.post({
|
||||
@@ -1204,8 +1172,9 @@ describe('Cloud Code', () => {
|
||||
});
|
||||
|
||||
it('should set the failure on the job', (done) => {
|
||||
Parse.Cloud.job('myJob', (req, res) => {
|
||||
res.error('Something went wrong').then(() => {
|
||||
Parse.Cloud.job('myJob', (req) => {
|
||||
const promise = Promise.reject('Something went wrong');
|
||||
new Promise((resolve) => setTimeout(resolve, 200)).then(() => {
|
||||
return getJobStatus(req.jobId);
|
||||
}).then((jobStatus) => {
|
||||
expect(jobStatus.get('message')).toEqual('Something went wrong');
|
||||
@@ -1215,6 +1184,7 @@ describe('Cloud Code', () => {
|
||||
jfail(err);
|
||||
done();
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
rp.post({
|
||||
@@ -1239,9 +1209,9 @@ describe('Cloud Code', () => {
|
||||
|
||||
describe('cloud functions', () => {
|
||||
it('Should have request ip', (done) => {
|
||||
Parse.Cloud.define('myFunction', (req, res) => {
|
||||
Parse.Cloud.define('myFunction', (req) => {
|
||||
expect(req.ip).toBeDefined();
|
||||
res.success("success");
|
||||
return "success";
|
||||
});
|
||||
|
||||
Parse.Cloud.run('myFunction', {}).then(() => done());
|
||||
@@ -1250,9 +1220,8 @@ describe('cloud functions', () => {
|
||||
|
||||
describe('beforeSave hooks', () => {
|
||||
it('should have request headers', (done) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (req, res) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (req) => {
|
||||
expect(req.headers).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1261,9 +1230,8 @@ describe('beforeSave hooks', () => {
|
||||
});
|
||||
|
||||
it('should have request ip', (done) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (req, res) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (req) => {
|
||||
expect(req.ip).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1285,9 +1253,8 @@ describe('afterSave hooks', () => {
|
||||
});
|
||||
|
||||
it('should have request ip', (done) => {
|
||||
Parse.Cloud.afterSave('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterSave('MyObject', (req) => {
|
||||
expect(req.ip).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1298,9 +1265,8 @@ describe('afterSave hooks', () => {
|
||||
|
||||
describe('beforeDelete hooks', () => {
|
||||
it('should have request headers', (done) => {
|
||||
Parse.Cloud.beforeDelete('MyObject', (req, res) => {
|
||||
Parse.Cloud.beforeDelete('MyObject', (req) => {
|
||||
expect(req.headers).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1311,9 +1277,8 @@ describe('beforeDelete hooks', () => {
|
||||
});
|
||||
|
||||
it('should have request ip', (done) => {
|
||||
Parse.Cloud.beforeDelete('MyObject', (req, res) => {
|
||||
Parse.Cloud.beforeDelete('MyObject', (req) => {
|
||||
expect(req.ip).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1554,11 +1519,11 @@ describe('beforeFind hooks', () => {
|
||||
|
||||
describe('afterFind hooks', () => {
|
||||
it('should add afterFind trigger using get',(done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req) => {
|
||||
for(let i = 0 ; i < req.objects.length ; i++){
|
||||
req.objects[i].set("secretField","###");
|
||||
}
|
||||
res.success(req.objects);
|
||||
return req.objects;
|
||||
});
|
||||
const obj = new Parse.Object('MyObject');
|
||||
obj.set('secretField', 'SSID');
|
||||
@@ -1578,11 +1543,11 @@ describe('afterFind hooks', () => {
|
||||
});
|
||||
|
||||
it('should add afterFind trigger using find',(done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req) => {
|
||||
for(let i = 0 ; i < req.objects.length ; i++){
|
||||
req.objects[i].set("secretField","###");
|
||||
}
|
||||
res.success(req.objects);
|
||||
return req.objects;
|
||||
});
|
||||
const obj = new Parse.Object('MyObject');
|
||||
obj.set('secretField', 'SSID');
|
||||
@@ -1603,14 +1568,14 @@ describe('afterFind hooks', () => {
|
||||
});
|
||||
|
||||
it('should filter out results',(done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req) => {
|
||||
const filteredResults = [];
|
||||
for(let i = 0 ; i < req.objects.length ; i++){
|
||||
if(req.objects[i].get("secretField") === "SSID1") {
|
||||
filteredResults.push(req.objects[i]);
|
||||
}
|
||||
}
|
||||
res.success(filteredResults);
|
||||
return filteredResults;
|
||||
});
|
||||
const obj0 = new Parse.Object('MyObject');
|
||||
obj0.set('secretField', 'SSID1');
|
||||
@@ -1633,8 +1598,8 @@ describe('afterFind hooks', () => {
|
||||
});
|
||||
|
||||
it('should handle failures',(done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
res.error(Parse.Error.SCRIPT_FAILED, "It should fail");
|
||||
Parse.Cloud.afterFind('MyObject', () => {
|
||||
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, "It should fail");
|
||||
});
|
||||
const obj = new Parse.Object('MyObject');
|
||||
obj.set('secretField', 'SSID');
|
||||
@@ -1749,9 +1714,8 @@ describe('afterFind hooks', () => {
|
||||
});
|
||||
|
||||
it('should have request headers', (done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req) => {
|
||||
expect(req.headers).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1770,9 +1734,8 @@ describe('afterFind hooks', () => {
|
||||
});
|
||||
|
||||
it('should have request ip', (done) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req, res) => {
|
||||
Parse.Cloud.afterFind('MyObject', (req) => {
|
||||
expect(req.ip).toBeDefined();
|
||||
res.success();
|
||||
});
|
||||
|
||||
const MyObject = Parse.Object.extend('MyObject');
|
||||
@@ -1787,7 +1750,7 @@ describe('afterFind hooks', () => {
|
||||
query.find(),
|
||||
]);
|
||||
})
|
||||
.then(() => done());
|
||||
.then(() => done()).catch(done.fail);
|
||||
});
|
||||
|
||||
it('should validate triggers correctly', () => {
|
||||
|
||||
@@ -28,10 +28,10 @@ describe("Cloud Code Logger", () => {
|
||||
const config = Config.get('test');
|
||||
const spy = spyOn(config.loggerController, 'log').and.callThrough();
|
||||
|
||||
Parse.Cloud.define("loggerTest", (req, res) => {
|
||||
Parse.Cloud.define("loggerTest", (req) => {
|
||||
req.log.info('logTest', 'info log', { info: 'some log' });
|
||||
req.log.error('logTest', 'error log', { error: 'there was an error' });
|
||||
res.success({});
|
||||
return {};
|
||||
});
|
||||
|
||||
return Parse.Cloud.run('loggerTest').then(() => {
|
||||
@@ -57,8 +57,8 @@ describe("Cloud Code Logger", () => {
|
||||
it('trigger should obfuscate password', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.beforeSave(Parse.User, (req, res) => {
|
||||
res.success(req.object);
|
||||
Parse.Cloud.beforeSave(Parse.User, (req) => {
|
||||
return req.object;
|
||||
});
|
||||
|
||||
Parse.User.signUp('tester123', 'abc')
|
||||
@@ -75,10 +75,10 @@ describe("Cloud Code Logger", () => {
|
||||
it("should expose log to trigger", (done) => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.beforeSave("MyObject", (req, res) => {
|
||||
Parse.Cloud.beforeSave("MyObject", (req) => {
|
||||
req.log.info('beforeSave MyObject', 'info log', { info: 'some log' });
|
||||
req.log.error('beforeSave MyObject', 'error log', { error: 'there was an error' });
|
||||
res.success({});
|
||||
return {};
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('MyObject');
|
||||
@@ -114,8 +114,8 @@ describe("Cloud Code Logger", () => {
|
||||
it('should truncate input and result of long lines', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
const longString = fs.readFileSync(loremFile, 'utf8');
|
||||
Parse.Cloud.define('aFunction', (req, res) => {
|
||||
res.success(req.params);
|
||||
Parse.Cloud.define('aFunction', (req) => {
|
||||
return req.params;
|
||||
});
|
||||
|
||||
Parse.Cloud.run('aFunction', { longString })
|
||||
@@ -147,8 +147,8 @@ describe("Cloud Code Logger", () => {
|
||||
|
||||
it('should log a denied beforeSave', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
Parse.Cloud.beforeSave("MyObject", (req, res) => {
|
||||
res.error('uh oh!');
|
||||
Parse.Cloud.beforeSave("MyObject", () => {
|
||||
throw 'uh oh!';
|
||||
});
|
||||
|
||||
new Parse.Object('MyObject')
|
||||
@@ -169,8 +169,8 @@ describe("Cloud Code Logger", () => {
|
||||
it('should log cloud function success', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.define('aFunction', (req, res) => {
|
||||
res.success('it worked!');
|
||||
Parse.Cloud.define('aFunction', () => {
|
||||
return 'it worked!';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('aFunction', { foo: 'bar' })
|
||||
@@ -187,8 +187,8 @@ describe("Cloud Code Logger", () => {
|
||||
it('should log cloud function failure', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.define('aFunction', (req, res) => {
|
||||
res.error('it failed!');
|
||||
Parse.Cloud.define('aFunction', () => {
|
||||
throw 'it failed!';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('aFunction', { foo: 'bar' })
|
||||
@@ -206,10 +206,10 @@ describe("Cloud Code Logger", () => {
|
||||
xit('should log a changed beforeSave indicating a change', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.beforeSave("MyObject", (req, res) => {
|
||||
Parse.Cloud.beforeSave("MyObject", (req) => {
|
||||
const myObj = req.object;
|
||||
myObj.set('aChange', true);
|
||||
res.success(myObj);
|
||||
return myObj;
|
||||
});
|
||||
|
||||
new Parse.Object('MyObject')
|
||||
@@ -231,8 +231,8 @@ describe("Cloud Code Logger", () => {
|
||||
it('cloud function should obfuscate password', done => {
|
||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
||||
|
||||
Parse.Cloud.define('testFunction', (req, res) => {
|
||||
res.success(1002,'verify code success');
|
||||
Parse.Cloud.define('testFunction', () => {
|
||||
return 'verify code success';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('testFunction', {username:'hawk',password:'123456'})
|
||||
|
||||
@@ -343,9 +343,8 @@ describe('miscellaneous', function() {
|
||||
const acl = new Parse.ACL({
|
||||
'*': { read: true, write: false }
|
||||
});
|
||||
Parse.Cloud.beforeSave('BeforeSaveAddACL', function(req, res) {
|
||||
Parse.Cloud.beforeSave('BeforeSaveAddACL', function(req) {
|
||||
req.object.setACL(acl);
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('BeforeSaveAddACL');
|
||||
@@ -369,7 +368,7 @@ describe('miscellaneous', function() {
|
||||
it('object is set on create and update', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.beforeSave('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req) => {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
expect(object.get('fooAgain')).toEqual('barAgain');
|
||||
@@ -387,10 +386,9 @@ describe('miscellaneous', function() {
|
||||
expect(object.createdAt).not.toBeUndefined();
|
||||
expect(object.updatedAt).not.toBeUndefined();
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -412,11 +410,11 @@ describe('miscellaneous', function() {
|
||||
it('works when object is passed to success', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.beforeSave('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req) => {
|
||||
const object = req.object;
|
||||
object.set('foo', 'bar');
|
||||
triggerTime++;
|
||||
res.success(object);
|
||||
return object;
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -434,7 +432,7 @@ describe('miscellaneous', function() {
|
||||
it('original object is set on update', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.beforeSave('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req) => {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
expect(object.get('fooAgain')).toEqual('barAgain');
|
||||
@@ -462,10 +460,9 @@ describe('miscellaneous', function() {
|
||||
expect(originalObject.updatedAt).not.toBeUndefined();
|
||||
expect(originalObject.get('foo')).toEqual('bar');
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -488,16 +485,14 @@ describe('miscellaneous', function() {
|
||||
it('pointer mutation properly saves object', done => {
|
||||
const className = 'GameScore';
|
||||
|
||||
Parse.Cloud.beforeSave(className, (req, res) => {
|
||||
Parse.Cloud.beforeSave(className, (req) => {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
|
||||
const child = object.get('child');
|
||||
expect(child instanceof Parse.Object).toBeTruthy();
|
||||
child.set('a', 'b');
|
||||
child.save().then(() => {
|
||||
res.success();
|
||||
});
|
||||
return child.save();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object(className);
|
||||
@@ -528,18 +523,17 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
|
||||
it('pointer reassign is working properly (#1288)', (done) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeSave('GameScore', (req) => {
|
||||
|
||||
const obj = req.object;
|
||||
if (obj.get('point')) {
|
||||
return res.success();
|
||||
return;
|
||||
}
|
||||
const TestObject1 = Parse.Object.extend('TestObject1');
|
||||
const newObj = new TestObject1({'key1': 1});
|
||||
|
||||
return newObj.save().then((newObj) => {
|
||||
obj.set('point' , newObj);
|
||||
res.success();
|
||||
});
|
||||
});
|
||||
let pointId;
|
||||
@@ -560,7 +554,7 @@ describe('miscellaneous', function() {
|
||||
it('test afterSave get full object on create and update', function(done) {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.afterSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
expect(object.id).not.toBeUndefined();
|
||||
@@ -574,10 +568,9 @@ describe('miscellaneous', function() {
|
||||
// Update
|
||||
expect(object.get('foo')).toEqual('baz');
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -601,7 +594,7 @@ describe('miscellaneous', function() {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
|
||||
Parse.Cloud.afterSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
expect(object.get('fooAgain')).toEqual('barAgain');
|
||||
@@ -625,10 +618,9 @@ describe('miscellaneous', function() {
|
||||
expect(originalObject.updatedAt).not.toBeUndefined();
|
||||
expect(originalObject.get('foo')).toEqual('bar');
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -651,7 +643,7 @@ describe('miscellaneous', function() {
|
||||
it('test afterSave get full original object even req auth can not query it', (done) => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.afterSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
const originalObject = req.original;
|
||||
if (triggerTime == 0) {
|
||||
@@ -667,10 +659,9 @@ describe('miscellaneous', function() {
|
||||
expect(originalObject.updatedAt).not.toBeUndefined();
|
||||
expect(originalObject.get('foo')).toEqual('bar');
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -698,7 +689,7 @@ describe('miscellaneous', function() {
|
||||
it('afterSave flattens custom operations', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.afterSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
expect(object instanceof Parse.Object).toBeTruthy();
|
||||
const originalObject = req.original;
|
||||
@@ -711,10 +702,9 @@ describe('miscellaneous', function() {
|
||||
// Check the originalObject
|
||||
expect(originalObject.get('yolo')).toEqual(1);
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -735,7 +725,7 @@ describe('miscellaneous', function() {
|
||||
it('beforeSave receives ACL', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.beforeSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.beforeSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
if (triggerTime == 0) {
|
||||
const acl = object.getACL();
|
||||
@@ -746,10 +736,9 @@ describe('miscellaneous', function() {
|
||||
expect(acl.getPublicReadAccess()).toBeFalsy();
|
||||
expect(acl.getPublicWriteAccess()).toBeTruthy();
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -774,7 +763,7 @@ describe('miscellaneous', function() {
|
||||
it('afterSave receives ACL', done => {
|
||||
let triggerTime = 0;
|
||||
// Register a mock beforeSave hook
|
||||
Parse.Cloud.afterSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
const object = req.object;
|
||||
if (triggerTime == 0) {
|
||||
const acl = object.getACL();
|
||||
@@ -785,10 +774,9 @@ describe('miscellaneous', function() {
|
||||
expect(acl.getPublicReadAccess()).toBeFalsy();
|
||||
expect(acl.getPublicWriteAccess()).toBeTruthy();
|
||||
} else {
|
||||
res.error();
|
||||
throw new Error();
|
||||
}
|
||||
triggerTime++;
|
||||
res.success();
|
||||
});
|
||||
|
||||
const obj = new Parse.Object('GameScore');
|
||||
@@ -860,8 +848,8 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test cloud function error handling', (done) => {
|
||||
// Register a function which will fail
|
||||
Parse.Cloud.define('willFail', (req, res) => {
|
||||
res.error('noway');
|
||||
Parse.Cloud.define('willFail', () => {
|
||||
throw new Error('noway');
|
||||
});
|
||||
Parse.Cloud.run('willFail').then(() => {
|
||||
fail('Should not have succeeded.');
|
||||
@@ -875,8 +863,8 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test cloud function error handling with custom error code', (done) => {
|
||||
// Register a function which will fail
|
||||
Parse.Cloud.define('willFail', (req, res) => {
|
||||
res.error(999, 'noway');
|
||||
Parse.Cloud.define('willFail', () => {
|
||||
throw new Parse.Error(999, 'noway');
|
||||
});
|
||||
Parse.Cloud.run('willFail').then(() => {
|
||||
fail('Should not have succeeded.');
|
||||
@@ -890,8 +878,8 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test cloud function error handling with standard error code', (done) => {
|
||||
// Register a function which will fail
|
||||
Parse.Cloud.define('willFail', (req, res) => {
|
||||
res.error('noway');
|
||||
Parse.Cloud.define('willFail', () => {
|
||||
throw new Error('noway');
|
||||
});
|
||||
Parse.Cloud.run('willFail').then(() => {
|
||||
fail('Should not have succeeded.');
|
||||
@@ -905,11 +893,10 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test beforeSave/afterSave get installationId', function(done) {
|
||||
let triggerTime = 0;
|
||||
Parse.Cloud.beforeSave('GameScore', function(req, res) {
|
||||
Parse.Cloud.beforeSave('GameScore', function(req) {
|
||||
triggerTime++;
|
||||
expect(triggerTime).toEqual(1);
|
||||
expect(req.installationId).toEqual('yolo');
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.afterSave('GameScore', function(req) {
|
||||
triggerTime++;
|
||||
@@ -936,11 +923,10 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test beforeDelete/afterDelete get installationId', function(done) {
|
||||
let triggerTime = 0;
|
||||
Parse.Cloud.beforeDelete('GameScore', function(req, res) {
|
||||
Parse.Cloud.beforeDelete('GameScore', function(req) {
|
||||
triggerTime++;
|
||||
expect(triggerTime).toEqual(1);
|
||||
expect(req.installationId).toEqual('yolo');
|
||||
res.success();
|
||||
});
|
||||
Parse.Cloud.afterDelete('GameScore', function(req) {
|
||||
triggerTime++;
|
||||
@@ -973,9 +959,8 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test beforeDelete with locked down ACL', async () => {
|
||||
let called = false;
|
||||
Parse.Cloud.beforeDelete('GameScore', (req, res) => {
|
||||
Parse.Cloud.beforeDelete('GameScore', () => {
|
||||
called = true;
|
||||
res.success();
|
||||
});
|
||||
const object = new Parse.Object('GameScore');
|
||||
object.setACL(new Parse.ACL());
|
||||
@@ -991,8 +976,8 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
|
||||
it('test cloud function query parameters', (done) => {
|
||||
Parse.Cloud.define('echoParams', (req, res) => {
|
||||
res.success(req.params);
|
||||
Parse.Cloud.define('echoParams', (req) => {
|
||||
return req.params;
|
||||
});
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -1020,8 +1005,8 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('test cloud function parameter validation', (done) => {
|
||||
// Register a function with validation
|
||||
Parse.Cloud.define('functionWithParameterValidationFailure', (req, res) => {
|
||||
res.success('noway');
|
||||
Parse.Cloud.define('functionWithParameterValidationFailure', () => {
|
||||
return 'noway';
|
||||
}, (request) => {
|
||||
return request.params.success === 100;
|
||||
});
|
||||
@@ -1037,9 +1022,9 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
|
||||
it('can handle null params in cloud functions (regression test for #1742)', done => {
|
||||
Parse.Cloud.define('func', (request, response) => {
|
||||
Parse.Cloud.define('func', (request) => {
|
||||
expect(request.params.nullParam).toEqual(null);
|
||||
response.success('yay');
|
||||
return 'yay';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('func', {nullParam: null})
|
||||
@@ -1053,10 +1038,10 @@ describe('miscellaneous', function() {
|
||||
|
||||
it('can handle date params in cloud functions (#2214)', done => {
|
||||
const date = new Date();
|
||||
Parse.Cloud.define('dateFunc', (request, response) => {
|
||||
Parse.Cloud.define('dateFunc', (request) => {
|
||||
expect(request.params.date.__type).toEqual('Date');
|
||||
expect(request.params.date.iso).toEqual(date.toISOString());
|
||||
response.success('yay');
|
||||
return 'yay';
|
||||
});
|
||||
|
||||
Parse.Cloud.run('dateFunc', {date: date})
|
||||
@@ -1514,12 +1499,10 @@ describe('miscellaneous', function() {
|
||||
});
|
||||
|
||||
it('should not update schema beforeSave #2672', (done) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (request, response) => {
|
||||
Parse.Cloud.beforeSave('MyObject', (request) => {
|
||||
if (request.object.get('secret')) {
|
||||
response.error('cannot set secret here');
|
||||
return;
|
||||
throw 'cannot set secret here';
|
||||
}
|
||||
response.success();
|
||||
});
|
||||
|
||||
const object = new Parse.Object('MyObject');
|
||||
|
||||
@@ -664,10 +664,10 @@ describe('Parse.Relation testing', () => {
|
||||
});
|
||||
|
||||
it('can query roles in Cloud Code (regession test #1489)', done => {
|
||||
Parse.Cloud.define('isAdmin', (request, response) => {
|
||||
Parse.Cloud.define('isAdmin', (request) => {
|
||||
const query = new Parse.Query(Parse.Role);
|
||||
query.equalTo('name', 'admin');
|
||||
query.first({ useMasterKey: true })
|
||||
return query.first({ useMasterKey: true })
|
||||
.then(role => {
|
||||
const relation = new Parse.Relation(role, 'users');
|
||||
const admins = relation.query();
|
||||
@@ -675,7 +675,6 @@ describe('Parse.Relation testing', () => {
|
||||
admins.first({ useMasterKey: true })
|
||||
.then(user => {
|
||||
if (user) {
|
||||
response.success(user);
|
||||
done();
|
||||
} else {
|
||||
fail('Should have found admin user, found nothing instead');
|
||||
|
||||
@@ -1615,7 +1615,7 @@ describe('Parse.User testing', () => {
|
||||
|
||||
it('should have authData in beforeSave and afterSave', async (done) => {
|
||||
|
||||
Parse.Cloud.beforeSave('_User', (request, response) => {
|
||||
Parse.Cloud.beforeSave('_User', (request) => {
|
||||
const authData = request.object.get('authData');
|
||||
expect(authData).not.toBeUndefined();
|
||||
if (authData) {
|
||||
@@ -1624,10 +1624,9 @@ describe('Parse.User testing', () => {
|
||||
} else {
|
||||
fail('authData should be set');
|
||||
}
|
||||
response.success();
|
||||
});
|
||||
|
||||
Parse.Cloud.afterSave('_User', (request, response) => {
|
||||
Parse.Cloud.afterSave('_User', (request) => {
|
||||
const authData = request.object.get('authData');
|
||||
expect(authData).not.toBeUndefined();
|
||||
if (authData) {
|
||||
@@ -1636,7 +1635,6 @@ describe('Parse.User testing', () => {
|
||||
} else {
|
||||
fail('authData should be set');
|
||||
}
|
||||
response.success();
|
||||
});
|
||||
|
||||
const provider = getMockFacebookProvider();
|
||||
@@ -2341,9 +2339,8 @@ describe('Parse.User testing', () => {
|
||||
});
|
||||
|
||||
it('should cleanup null authData keys ParseUser update (regression test for #1198, #2252)', (done) => {
|
||||
Parse.Cloud.beforeSave('_User', (req, res) => {
|
||||
Parse.Cloud.beforeSave('_User', (req) => {
|
||||
req.object.set('foo', 'bar');
|
||||
res.success();
|
||||
});
|
||||
|
||||
let originalSessionToken;
|
||||
@@ -2540,9 +2537,9 @@ describe('Parse.User testing', () => {
|
||||
});
|
||||
|
||||
it('changes to a user should update the cache', (done) => {
|
||||
Parse.Cloud.define('testUpdatedUser', (req, res) => {
|
||||
Parse.Cloud.define('testUpdatedUser', (req) => {
|
||||
expect(req.user.get('han')).toEqual('solo');
|
||||
res.success({});
|
||||
return {};
|
||||
});
|
||||
const user = new Parse.User();
|
||||
user.setUsername('harrison');
|
||||
|
||||
@@ -558,7 +558,7 @@ describe('PushController', () => {
|
||||
expect(spy.calls.count()).toBe(4);
|
||||
const allCalls = spy.calls.all();
|
||||
allCalls.forEach((call) => {
|
||||
expect(call.args.length).toBe(2);
|
||||
expect(call.args.length).toBe(1);
|
||||
const object = call.args[0].object;
|
||||
expect(object instanceof Parse.Object).toBe(true);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Parse.Cloud.define('cloudCodeInFile', (req, res) => {
|
||||
res.success('It is possible to define cloud code in a file.');
|
||||
Parse.Cloud.define('cloudCodeInFile', () => {
|
||||
return 'It is possible to define cloud code in a file.';
|
||||
});
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Parse.Cloud.define('cloudCodeInFile', (req, res) => {
|
||||
res.success('It is possible to define cloud code in a file.');
|
||||
Parse.Cloud.define('cloudCodeInFile', () => {
|
||||
return 'It is possible to define cloud code in a file.';
|
||||
});
|
||||
|
||||
@@ -101,9 +101,8 @@ describe('rest create', () => {
|
||||
it('handles object and subdocument', done => {
|
||||
const obj = { subdoc: {foo: 'bar', wu: 'tan'} };
|
||||
|
||||
Parse.Cloud.beforeSave('MyClass', function(req, res) {
|
||||
Parse.Cloud.beforeSave('MyClass', function() {
|
||||
// this beforeSave trigger should do nothing but can mess with the object
|
||||
res.success();
|
||||
});
|
||||
|
||||
rest.create(config, auth.nobody(config), 'MyClass', obj)
|
||||
|
||||
@@ -1656,11 +1656,10 @@ describe('schemas', () => {
|
||||
|
||||
it('unset field in beforeSave should not stop object creation', (done) => {
|
||||
const hook = {
|
||||
method: function(req, res) {
|
||||
method: function(req) {
|
||||
if (req.object.get('undesiredField')) {
|
||||
req.object.unset('undesiredField');
|
||||
}
|
||||
return res.success();
|
||||
}
|
||||
};
|
||||
spyOn(hook, 'method').and.callThrough();
|
||||
|
||||
@@ -166,7 +166,7 @@ export class HooksController {
|
||||
}
|
||||
|
||||
function wrapToHTTPRequest(hook, key) {
|
||||
return (req, res) => {
|
||||
return (req) => {
|
||||
const jsonBody = {};
|
||||
for (var i in req) {
|
||||
jsonBody[i] = req[i];
|
||||
@@ -195,37 +195,38 @@ function wrapToHTTPRequest(hook, key) {
|
||||
logger.warn('Making outgoing webhook request without webhookKey being set!');
|
||||
}
|
||||
|
||||
request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
|
||||
var result;
|
||||
if (body) {
|
||||
if (typeof body === "string") {
|
||||
try {
|
||||
body = JSON.parse(body);
|
||||
} catch (e) {
|
||||
err = {
|
||||
error: "Malformed response",
|
||||
code: -1,
|
||||
partialResponse: body.substring(0, 100)
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
|
||||
var result;
|
||||
if (body) {
|
||||
if (typeof body === "string") {
|
||||
try {
|
||||
body = JSON.parse(body);
|
||||
} catch (e) {
|
||||
err = {
|
||||
error: "Malformed response",
|
||||
code: -1,
|
||||
partialResponse: body.substring(0, 100)
|
||||
};
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
result = body.success;
|
||||
err = body.error;
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
result = body.success;
|
||||
err = body.error;
|
||||
if (err) {
|
||||
return reject(err);
|
||||
} else if (hook.triggerName === 'beforeSave') {
|
||||
if (typeof result === 'object') {
|
||||
delete result.createdAt;
|
||||
delete result.updatedAt;
|
||||
}
|
||||
return resolve({object: result});
|
||||
} else {
|
||||
return resolve(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return res.error(err);
|
||||
} else if (hook.triggerName === 'beforeSave') {
|
||||
if (typeof result === 'object') {
|
||||
delete result.createdAt;
|
||||
delete result.updatedAt;
|
||||
}
|
||||
return res.success({object: result});
|
||||
} else {
|
||||
return res.success(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,18 +56,21 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
jobName
|
||||
};
|
||||
const status = {
|
||||
success: jobHandler.setSucceeded.bind(jobHandler),
|
||||
error: jobHandler.setFailed.bind(jobHandler),
|
||||
jobName,
|
||||
message: jobHandler.setMessage.bind(jobHandler)
|
||||
}
|
||||
};
|
||||
|
||||
return jobHandler.setRunning(jobName, params).then((jobStatus) => {
|
||||
request.jobId = jobStatus.objectId
|
||||
// run the function async
|
||||
process.nextTick(() => {
|
||||
jobFunction(request, status);
|
||||
Promise.resolve().then(() => {
|
||||
return jobFunction(request);
|
||||
}).then((result) => {
|
||||
jobHandler.setSucceeded(result);
|
||||
}, (error) => {
|
||||
jobHandler.setFailed(error);
|
||||
});
|
||||
});
|
||||
return {
|
||||
headers: {
|
||||
@@ -87,13 +90,19 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function(code, message) {
|
||||
if (!message) {
|
||||
if (code instanceof Parse.Error) {
|
||||
return reject(code)
|
||||
}
|
||||
message = code;
|
||||
code = Parse.Error.SCRIPT_FAILED;
|
||||
error: function(message) {
|
||||
// parse error, process away
|
||||
if (message instanceof Parse.Error) {
|
||||
return reject(message);
|
||||
}
|
||||
|
||||
const code = Parse.Error.SCRIPT_FAILED;
|
||||
// If it's an error, mark it as a script failed
|
||||
if (typeof message === 'string') {
|
||||
return reject(new Parse.Error(code, message));
|
||||
}
|
||||
if (message instanceof Error) {
|
||||
message = message.message;
|
||||
}
|
||||
reject(new Parse.Error(code, message));
|
||||
},
|
||||
@@ -106,69 +115,66 @@ export class FunctionsRouter extends PromiseRouter {
|
||||
const applicationId = req.config.applicationId;
|
||||
const theFunction = triggers.getFunction(functionName, applicationId);
|
||||
const theValidator = triggers.getValidator(req.params.functionName, applicationId);
|
||||
if (theFunction) {
|
||||
let params = Object.assign({}, req.body, req.query);
|
||||
params = parseParams(params);
|
||||
var request = {
|
||||
params: params,
|
||||
master: req.auth && req.auth.isMaster,
|
||||
user: req.auth && req.auth.user,
|
||||
installationId: req.info.installationId,
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
functionName
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === "function") {
|
||||
var result = theValidator(request);
|
||||
if (!result) {
|
||||
throw new Parse.Error(Parse.Error.VALIDATION_ERROR, 'Validation failed.');
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const userString = (req.auth && req.auth.user) ? req.auth.user.id : undefined;
|
||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||
var response = FunctionsRouter.createResponseObject((result) => {
|
||||
try {
|
||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
||||
logger.info(
|
||||
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput }\n Result: ${cleanResult }`,
|
||||
{
|
||||
functionName,
|
||||
params,
|
||||
user: userString,
|
||||
}
|
||||
);
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, (error) => {
|
||||
try {
|
||||
logger.error(
|
||||
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + JSON.stringify(error),
|
||||
{
|
||||
functionName,
|
||||
error,
|
||||
params,
|
||||
user: userString
|
||||
}
|
||||
);
|
||||
reject(error);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
// Force the keys before the function calls.
|
||||
Parse.applicationId = req.config.applicationId;
|
||||
Parse.javascriptKey = req.config.javascriptKey;
|
||||
Parse.masterKey = req.config.masterKey;
|
||||
theFunction(request, response);
|
||||
});
|
||||
} else {
|
||||
if (!theFunction) {
|
||||
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, `Invalid function: "${functionName}"`);
|
||||
}
|
||||
let params = Object.assign({}, req.body, req.query);
|
||||
params = parseParams(params);
|
||||
const request = {
|
||||
params: params,
|
||||
master: req.auth && req.auth.isMaster,
|
||||
user: req.auth && req.auth.user,
|
||||
installationId: req.info.installationId,
|
||||
log: req.config.loggerController,
|
||||
headers: req.config.headers,
|
||||
ip: req.config.ip,
|
||||
functionName
|
||||
};
|
||||
|
||||
if (theValidator && typeof theValidator === "function") {
|
||||
var result = theValidator(request);
|
||||
if (!result) {
|
||||
throw new Parse.Error(Parse.Error.VALIDATION_ERROR, 'Validation failed.');
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
const userString = (req.auth && req.auth.user) ? req.auth.user.id : undefined;
|
||||
const cleanInput = logger.truncateLogMessage(JSON.stringify(params));
|
||||
const { success, error, message } = FunctionsRouter.createResponseObject((result) => {
|
||||
try {
|
||||
const cleanResult = logger.truncateLogMessage(JSON.stringify(result.response.result));
|
||||
logger.info(
|
||||
`Ran cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput }\n Result: ${cleanResult }`,
|
||||
{
|
||||
functionName,
|
||||
params,
|
||||
user: userString,
|
||||
}
|
||||
);
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, (error) => {
|
||||
try {
|
||||
logger.error(
|
||||
`Failed running cloud function ${functionName} for user ${userString} with:\n Input: ${cleanInput}\n Error: ` + JSON.stringify(error),
|
||||
{
|
||||
functionName,
|
||||
error,
|
||||
params,
|
||||
user: userString
|
||||
}
|
||||
);
|
||||
reject(error);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
return Promise.resolve().then(() => {
|
||||
return theFunction(request, { message });
|
||||
}).then(success, error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,16 +222,11 @@ export function getResponseObject(request, resolve, reject) {
|
||||
}
|
||||
return resolve(response);
|
||||
},
|
||||
error: function(code, message) {
|
||||
if (!message) {
|
||||
if (code instanceof Parse.Error) {
|
||||
return reject(code)
|
||||
}
|
||||
message = code;
|
||||
code = Parse.Error.SCRIPT_FAILED;
|
||||
error: function(error) {
|
||||
if (typeof error === 'string') {
|
||||
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, error));
|
||||
}
|
||||
var scriptError = new Parse.Error(code, message);
|
||||
return reject(scriptError);
|
||||
return reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,7 +271,7 @@ export function maybeRunAfterFindTrigger(triggerType, auth, className, objects,
|
||||
return resolve();
|
||||
}
|
||||
const request = getRequestObject(triggerType, auth, null, null, config);
|
||||
const response = getResponseObject(request,
|
||||
const { success, error } = getResponseObject(request,
|
||||
object => {
|
||||
resolve(object);
|
||||
},
|
||||
@@ -289,16 +284,18 @@ export function maybeRunAfterFindTrigger(triggerType, auth, className, objects,
|
||||
object.className = className;
|
||||
return Parse.Object.fromJSON(object);
|
||||
});
|
||||
const triggerPromise = trigger(request, response);
|
||||
if (triggerPromise && typeof triggerPromise.then === "function") {
|
||||
return triggerPromise.then(promiseResults => {
|
||||
if(promiseResults) {
|
||||
resolve(promiseResults);
|
||||
}else{
|
||||
return reject(new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise"));
|
||||
}
|
||||
});
|
||||
}
|
||||
return Promise.resolve().then(() => {
|
||||
const response = trigger(request);
|
||||
if (response && typeof response.then === 'function') {
|
||||
return response.then((results) => {
|
||||
if (!results) {
|
||||
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, "AfterFind expect results to be returned in the promise");
|
||||
}
|
||||
return results;
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}).then(success, error);
|
||||
}).then((results) => {
|
||||
logTriggerAfterHook(triggerType, className, JSON.stringify(results), auth);
|
||||
return results;
|
||||
@@ -401,7 +398,7 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
|
||||
var trigger = getTrigger(parseObject.className, triggerType, config.applicationId);
|
||||
if (!trigger) return resolve();
|
||||
var request = getRequestObject(triggerType, auth, parseObject, originalParseObject, config);
|
||||
var response = getResponseObject(request, (object) => {
|
||||
var { success, error } = getResponseObject(request, (object) => {
|
||||
logTriggerSuccessBeforeHook(
|
||||
triggerType, parseObject.className, parseObject.toJSON(), object, auth);
|
||||
resolve(object);
|
||||
@@ -410,27 +407,19 @@ export function maybeRunTrigger(triggerType, auth, parseObject, originalParseObj
|
||||
triggerType, parseObject.className, parseObject.toJSON(), auth, error);
|
||||
reject(error);
|
||||
});
|
||||
// Force the current Parse app before the trigger
|
||||
Parse.applicationId = config.applicationId;
|
||||
Parse.javascriptKey = config.javascriptKey || '';
|
||||
Parse.masterKey = config.masterKey;
|
||||
|
||||
// AfterSave and afterDelete triggers can return a promise, which if they
|
||||
// do, needs to be resolved before this promise is resolved,
|
||||
// so trigger execution is synced with RestWrite.execute() call.
|
||||
// If triggers do not return a promise, they can run async code parallel
|
||||
// to the RestWrite.execute() call.
|
||||
var triggerPromise = trigger(request, response);
|
||||
if(triggerType === Types.afterSave || triggerType === Types.afterDelete)
|
||||
{
|
||||
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
|
||||
if(triggerPromise && typeof triggerPromise.then === "function") {
|
||||
return triggerPromise.then(resolve, resolve);
|
||||
return Promise.resolve().then(() => {
|
||||
const promise = trigger(request);
|
||||
if(triggerType === Types.afterSave || triggerType === Types.afterDelete) {
|
||||
logTriggerAfterHook(triggerType, parseObject.className, parseObject.toJSON(), auth);
|
||||
}
|
||||
else {
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
return promise;
|
||||
}).then(success, error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user