From f88e9278bc7dcce7cb1a8c243e963b2db52c20a2 Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Sat, 18 Apr 2020 21:04:10 +0200 Subject: [PATCH 1/6] added context to object save in JS SDK --- _includes/js/objects.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/_includes/js/objects.md b/_includes/js/objects.md index 95a8cc058..9cddd3eb1 100644 --- a/_includes/js/objects.md +++ b/_includes/js/objects.md @@ -199,6 +199,29 @@ teamMember.save(null, { cascadeSave: false }); ``` +### Cloud Code context + +You may pass a `context` that is accessible in Cloud Code `beforeSave` and `afterSave` triggers for that `Parse.Object`. This is useful if you want to condition certain operations in Cloud Code triggers on ephemeral information that should not be saved with the `Parse.Object` in the database. The context is ephemeral in the sense that it vanishes after the Cloud Code triggers for that particular `Parse.Object` have executed. For example: + +```javascript +var TeamMember = Parse.Object.extend("TeamMember"); +var teamMember = new TeamMember(); +teamMember.set("team", "A"); + +var context = { notifyTeam: false }; +await teamMember.save(null, { context: context }); +``` + +The context is then accessible in Cloud Code: + +```javascript +Parse.Cloud.afterSave("TeamMember", async (req) => { + var notifyTeam = req.context.notifyTeam; + if (notifyTeam) { + // Notify team about new member. + } +}); +``` ## Retrieving Objects From d21b8d19d9cb5d870ce3ace2d3a6620de67cc261 Mon Sep 17 00:00:00 2001 From: Manuel Date: Sat, 18 Apr 2020 21:46:25 +0200 Subject: [PATCH 2/6] Update _includes/js/objects.md Co-Authored-By: Tom Fox <13188249+TomWFox@users.noreply.github.com> --- _includes/js/objects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/js/objects.md b/_includes/js/objects.md index 9cddd3eb1..1ff0469f7 100644 --- a/_includes/js/objects.md +++ b/_includes/js/objects.md @@ -201,7 +201,7 @@ teamMember.save(null, { cascadeSave: false }); ### Cloud Code context -You may pass a `context` that is accessible in Cloud Code `beforeSave` and `afterSave` triggers for that `Parse.Object`. This is useful if you want to condition certain operations in Cloud Code triggers on ephemeral information that should not be saved with the `Parse.Object` in the database. The context is ephemeral in the sense that it vanishes after the Cloud Code triggers for that particular `Parse.Object` have executed. For example: +You may pass a `context` dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers for that `Parse.Object`. This is useful if you want to condition certain operations in Cloud Code triggers on ephemeral information that should not be saved with the `Parse.Object` in the database. The context is ephemeral in the sense that it vanishes after the Cloud Code triggers for that particular `Parse.Object` have executed. For example: ```javascript var TeamMember = Parse.Object.extend("TeamMember"); From 3b159bfe9f7bfc29738672912539eea055305c18 Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Sat, 18 Apr 2020 22:48:09 +0200 Subject: [PATCH 3/6] added context info to cloud code --- _includes/cloudcode/cloud-code.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/_includes/cloudcode/cloud-code.md b/_includes/cloudcode/cloud-code.md index 28befcc3c..89662a836 100644 --- a/_includes/cloudcode/cloud-code.md +++ b/_includes/cloudcode/cloud-code.md @@ -243,7 +243,10 @@ You can use an `afterSave` handler to perform lengthy operations after sending a ## Using Request Context -State can be passed from a `beforeSave` handler to an `afterSave` handler in the Request Context. The following example sends emails to users who are being added to a [Parse.Role's users relation](https://parseplatform.org/Parse-SDK-JS/api/2.1.0/Parse.Role.html#getUsers) asynchronously, so the client receives a response before the emails complete sending: +When saving a `Parse.Object` you may pass a `context` dictionary that is accessible in the Cloud Code Save Triggers. More info in the [JavaScript Guide]({{ site.baseUrl }}/js/guide/#cloud-code-context). + +The context is also passed from a `beforeSave` handler to an `afterSave` handler. The following example sends emails to users who are being added to a [Parse.Role's users relation](https://parseplatform.org/Parse-SDK-JS/api/2.1.0/Parse.Role.html#getUsers) asynchronously, so the client receives a response before the emails complete sending: + ```javascript const beforeSave = function beforeSave(request) { From 223bc3a85fdba243c592c4b9fad1129f71cffffb Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Sat, 18 Apr 2020 22:51:58 +0200 Subject: [PATCH 4/6] restructuring cloud code doc - added headings per trigger group - moved context of save triggers into own section --- _includes/cloudcode/cloud-code.md | 88 +++++++++++++++++-------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/_includes/cloudcode/cloud-code.md b/_includes/cloudcode/cloud-code.md index 89662a836..cff1b4ec6 100644 --- a/_includes/cloudcode/cloud-code.md +++ b/_includes/cloudcode/cloud-code.md @@ -167,9 +167,11 @@ We don't support at the moment job scheduling and highly recommend to use a 3rd Viewing jobs is supported on parse-dashboard starting version 1.0.19, but you can also query the _JobStatus class with a masterKey call to fetch your recent jobs. -# beforeSave Triggers +# Save Triggers -## Implementing validation +## beforeSave + +### Implementing validation Another reason to run code in the cloud is to enforce a particular data format. For example, you might have both an Android and an iOS app, and you want to validate data for each of those. Rather than writing code once for each client environment, you can write it just once with Cloud Code. @@ -192,7 +194,7 @@ If the function throws, the `Review` object will not be saved, and the client wi One useful tip is that even if your mobile app has many different versions, the same version of Cloud Code applies to all of them. Thus, if you launch an application that doesn't correctly check the validity of input data, you can still fix this problem by adding a validation with `beforeSave`. -## Modifying Objects on Save +### Modifying Objects on Save In some cases, you don't want to throw out invalid data. You just want to tweak it a bit before saving it. `beforeSave` can handle this case, too. Any adjustment you make to request.object will be saved. @@ -208,7 +210,7 @@ Parse.Cloud.beforeSave("Review", (request) => { }); ``` -## Predefined Classes +### Predefined Classes If you want to use `beforeSave` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: ```javascript @@ -217,7 +219,7 @@ Parse.Cloud.beforeSave(Parse.User, async (request) => { }) ``` -# afterSave Triggers +## afterSave In some cases, you may want to perform some action, such as a push, after an object has been saved. You can do this by registering a handler with the `afterSave` method. For example, suppose you want to keep track of the number of comments on a blog post. You can do that by writing a function like this: @@ -235,19 +237,28 @@ Parse.Cloud.afterSave("Comment", (request) => { }); ``` -## Async Behavior +### Async Behavior In the example above, the client will receive a successful response before the promise in the handler completes, regardless of how the promise resolves. For instance, the client will receive a successful response even if the handler throws an exception. Any errors that occurred while running the handler can be found in the Cloud Code log. You can use an `afterSave` handler to perform lengthy operations after sending a response back to the client. In order to respond to the client before the `afterSave` handler completes, your handler may not return a promise and your `afterSave` handler may not use async/await. -## Using Request Context +### Predefined Classes + +If you want to use `afterSave` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: + +```javascript +Parse.Cloud.afterSave(Parse.User, async (request) => { + // code here +}) +``` + +## Context When saving a `Parse.Object` you may pass a `context` dictionary that is accessible in the Cloud Code Save Triggers. More info in the [JavaScript Guide]({{ site.baseUrl }}/js/guide/#cloud-code-context). The context is also passed from a `beforeSave` handler to an `afterSave` handler. The following example sends emails to users who are being added to a [Parse.Role's users relation](https://parseplatform.org/Parse-SDK-JS/api/2.1.0/Parse.Role.html#getUsers) asynchronously, so the client receives a response before the emails complete sending: - ```javascript const beforeSave = function beforeSave(request) { const { object: role } = request; @@ -271,18 +282,9 @@ const afterSave = function afterSave(request) { }; ``` +# Delete Triggers -## Predefined Classes - -If you want to use `afterSave` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: - -```javascript -Parse.Cloud.afterSave(Parse.User, async (request) => { - // code here -}) -``` - -# beforeDelete Triggers +## beforeDelete You can run custom Cloud Code before an object is deleted. You can do this with the `beforeDelete` method. For instance, this can be used to implement a restricted delete policy that is more sophisticated than what can be expressed through [ACLs]({{ site.apis.js }}/classes/Parse.ACL.html). For example, suppose you have a photo album app, where many photos are associated with each album, and you want to prevent the user from deleting an album if it still has a photo in it. You can do that by writing a function like this: @@ -303,7 +305,7 @@ Parse.Cloud.beforeDelete("Album", (request) => { If the function throws, the `Album` object will not be deleted, and the client will get an error. Otherwise,the object will be deleted normally. -## Predefined Classes +### Predefined Classes If you want to use `beforeDelete` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: ```javascript @@ -312,7 +314,7 @@ Parse.Cloud.beforeDelete(Parse.User, async (request) => { }) ``` -# afterDelete Triggers +## afterDelete In some cases, you may want to perform some action, such as a push, after an object has been deleted. You can do this by registering a handler with the `afterDelete` method. For example, suppose that after deleting a blog post, you also want to delete all associated comments. You can do that by writing a function like this: @@ -332,7 +334,7 @@ The `afterDelete` handler can access the object that was deleted through `reques The client will receive a successful response to the delete request after the handler terminates, regardless of how the `afterDelete` terminates. For instance, the client will receive a successful response even if the handler throws an exception. Any errors that occurred while running the handler can be found in the Cloud Code log. -## Predefined Classes +### Predefined Classes If you want to use `afterDelete` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: ```javascript @@ -341,11 +343,13 @@ Parse.Cloud.afterDelete(Parse.User, async (request) => { }) ``` -# beforeSaveFile Triggers +# File Triggers + +## beforeSaveFile With the `beforeSaveFile` method you can run custom Cloud Code before any file is saved. Returning a new `Parse.File` will save the new file instead of the one sent by the client. -## Examples +### Examples ```javascript // Changing the file name @@ -370,7 +374,7 @@ Parse.Cloud.beforeSaveFile((request) => { }); ``` -## Metadata and Tags +### Metadata and Tags Adding Metadata and Tags to your files allows you to add additional bits of data to the files that are stored within your storage solution (i.e AWS S3). The `beforeSaveFile` hook is a great place to set the metadata and/or tags on your files. @@ -385,7 +389,7 @@ Parse.Cloud.beforeSaveFile((request) => { }); ``` -# afterSaveFile Triggers +## afterSaveFile The `afterSaveFile` method is a great way to keep track of all of the files stored in your app. For example: @@ -401,7 +405,7 @@ Parse.Cloud.afterSaveFile(async (request) => { }); ``` -# beforeDeleteFile Triggers +## beforeDeleteFile You can run custom Cloud Code before any file gets deleted. For example, lets say you want to add logic that only allows files to be deleted by the user who created it. You could use a combination of the `afterSaveFile` and the `beforeDeleteFile` methods as follows: @@ -425,7 +429,7 @@ Parse.Cloud.beforeDeleteFile(async (request) => { }); ``` -# afterDeleteFile Triggers +## afterDeleteFile In the above `beforeDeleteFile` example the `FileObject` collection is used to keep track of saved files in your app. The `afterDeleteFile` trigger is a good place to clean up these objects once a file has been successfully deleted. @@ -439,13 +443,15 @@ Parse.Cloud.afterDeleteFile(async (request) => { }); ``` -# beforeFind Triggers +# Find Triggers + +## beforeFind *Available only on parse-server cloud code starting 2.2.20* In some cases you may want to transform an incoming query, adding an additional limit or increasing the default limit, adding extra includes or restrict the results to a subset of keys. You can do so with the `beforeFind` trigger. -## Examples +### Examples ```javascript // Properties available @@ -502,7 +508,7 @@ Parse.Cloud.beforeFind('MyObject2', (req) => { ``` -## Predefined Classes +### Predefined Classes If you want to use `beforeFind` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: @@ -512,7 +518,7 @@ Parse.Cloud.beforeFind(Parse.User, async (request) => { }) ``` -# afterFind Triggers +## afterFind *Available only on parse-server cloud code starting 2.2.25* @@ -524,7 +530,7 @@ Parse.Cloud.afterFind('MyCustomClass', async (request) => { }) ``` -## Predefined Classes +### Predefined Classes If you want to use `afterFind` for a predefined class in the Parse JavaScript SDK (e.g. [Parse.User]({{ site.apis.js }}classes/Parse.User.html)), you should not pass a String for the first argument. Instead, you should pass the class itself, for example: @@ -534,7 +540,9 @@ Parse.Cloud.afterFind(Parse.User, async (request) => { }) ``` -# beforeLogin Triggers +# Session Triggers + +## beforeLogin *Available only on parse-server cloud code starting 3.3.0* @@ -549,21 +557,21 @@ Parse.Cloud.beforeLogin(async request => { }); ``` -## Some considerations to be aware of +### Some considerations to be aware of - It waits for any promises to resolve - The user is not available on the request object - the user has not yet been provided a session until after beforeLogin is successfully completed - Like `afterSave` on `Parse.User`, it will not save mutations to the user unless explicitly saved -### The trigger will run... +#### The trigger will run... - On username & password logins - On `authProvider` logins -### The trigger won't run... +#### The trigger won't run... - On sign up - If the login credentials are incorrect -# afterLogout Triggers +## afterLogout *Available only on parse-server cloud code starting 3.10.0* @@ -578,10 +586,10 @@ Parse.Cloud.afterLogout(async request => { }); ``` -## Some considerations to be aware of +### Some considerations to be aware of - Like with `afterDelete` triggers, the `_Session` object that is contained in the request has already been deleted. -### The trigger will run... +#### The trigger will run... - when the user logs out and a `_Session` object was deleted ### The trigger won't run... From 453d2fd5128c183d183b7ceaf4170b8b0833f5fb Mon Sep 17 00:00:00 2001 From: Manuel Trezza Date: Sun, 19 Apr 2020 16:46:53 +0200 Subject: [PATCH 5/6] Added required parse server version (tbd) - Insert version before merging --- _includes/js/objects.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_includes/js/objects.md b/_includes/js/objects.md index 1ff0469f7..f12c6601a 100644 --- a/_includes/js/objects.md +++ b/_includes/js/objects.md @@ -201,6 +201,8 @@ teamMember.save(null, { cascadeSave: false }); ### Cloud Code context +*Requires Parse Server [tdb]+* + You may pass a `context` dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers for that `Parse.Object`. This is useful if you want to condition certain operations in Cloud Code triggers on ephemeral information that should not be saved with the `Parse.Object` in the database. The context is ephemeral in the sense that it vanishes after the Cloud Code triggers for that particular `Parse.Object` have executed. For example: ```javascript From 3c240015f30baa9903d7e75ead13d0ea311ec445 Mon Sep 17 00:00:00 2001 From: Tom Fox <13188249+TomWFox@users.noreply.github.com> Date: Mon, 27 Jul 2020 12:39:11 +0100 Subject: [PATCH 6/6] add parse server version --- _includes/js/objects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/js/objects.md b/_includes/js/objects.md index f12c6601a..a9aafbd2b 100644 --- a/_includes/js/objects.md +++ b/_includes/js/objects.md @@ -201,7 +201,7 @@ teamMember.save(null, { cascadeSave: false }); ### Cloud Code context -*Requires Parse Server [tdb]+* +*Requires Parse Server 4.3.0+* You may pass a `context` dictionary that is accessible in Cloud Code `beforeSave` and `afterSave` triggers for that `Parse.Object`. This is useful if you want to condition certain operations in Cloud Code triggers on ephemeral information that should not be saved with the `Parse.Object` in the database. The context is ephemeral in the sense that it vanishes after the Cloud Code triggers for that particular `Parse.Object` have executed. For example: