diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index 56359c937e..59b728a944 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -13,6 +13,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h | DEPPS7 | Remove file trigger syntax `Parse.Cloud.beforeSaveFile((request) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS8 | Login with expired 3rd party authentication token defaults to `false` | [#7079](https://github.com/parse-community/parse-server/pull/7079) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS9 | Rename LiveQuery `fields` option to `keys` | [#8389](https://github.com/parse-community/parse-server/issues/8389) | 6.0.0 (2023) | 7.0.0 (2024) | deprecated | - | +| DEPPS10 | Config option `encodeParseObjectInCloudFunction` defaults to `true` | [#8634](https://github.com/parse-community/parse-server/issues/8634) | 6.2.0 (2023) | 7.0.0 (2024) | deprecated | - | [i_deprecation]: ## "The version and date of the deprecation." [i_removal]: ## "The version and date of the planned removal." diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index a8795a4e84..a2e623551a 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1353,7 +1353,27 @@ describe('Cloud Code', () => { }); }); + it('should not encode Parse Objects', async () => { + const user = new Parse.User(); + user.setUsername('username'); + user.setPassword('password'); + user.set('deleted', false); + await user.signUp(); + Parse.Cloud.define( + 'deleteAccount', + async req => { + expect(req.params.object instanceof Parse.Object).not.toBeTrue(); + return 'Object deleted'; + }, + { + requireMaster: true, + } + ); + await Parse.Cloud.run('deleteAccount', { object: user.toPointer() }, { useMasterKey: true }); + }); + it('allow cloud to encode Parse Objects', async () => { + await reconfigureServer({ encodeParseObjectInCloudFunction: true }); const user = new Parse.User(); user.setUsername('username'); user.setPassword('password'); diff --git a/src/Deprecator/Deprecations.js b/src/Deprecator/Deprecations.js index 0afd98ff0c..2f698ad33e 100644 --- a/src/Deprecator/Deprecations.js +++ b/src/Deprecator/Deprecations.js @@ -18,4 +18,5 @@ module.exports = [ { optionKey: 'allowClientClassCreation', changeNewDefault: 'false' }, { optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' }, + { optionKey: 'encodeParseObjectInCloudFunction', changeNewDefault: 'true' }, ]; diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index b067412d26..6477836eed 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -210,6 +210,13 @@ module.exports.ParseServerOptions = { action: parsers.booleanParser, default: false, }, + encodeParseObjectInCloudFunction: { + env: 'PARSE_SERVER_ENCODE_PARSE_OBJECT_IN_CLOUD_FUNCTION', + help: + 'If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

\u2139\uFE0F The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`.', + action: parsers.booleanParser, + default: false, + }, encryptionKey: { env: 'PARSE_SERVER_ENCRYPTION_KEY', help: 'Key for encrypting your files', diff --git a/src/Options/docs.js b/src/Options/docs.js index 2e1390345d..fdb62bb590 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -40,6 +40,7 @@ * @property {Number} emailVerifyTokenValidityDuration Set the validity duration of the email verification token in seconds after which the token expires. The token is used in the link that is set in the email. After the token expires, the link becomes invalid and a new link has to be sent. If the option is not set or set to `undefined`, then the token never expires.

For example, to expire the token after 2 hours, set a value of 7200 seconds (= 60 seconds * 60 minutes * 2 hours).

Default is `undefined`.
Requires option `verifyUserEmails: true`. * @property {Boolean} enableAnonymousUsers Enable (or disable) anonymous users, defaults to true * @property {Boolean} enableExpressErrorHandler Enables the default express error handler for all errors + * @property {Boolean} encodeParseObjectInCloudFunction If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

ℹ️ The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`. * @property {String} encryptionKey Key for encrypting your files * @property {Boolean} enforcePrivateUsers Set to true if new users should be created without public read and write access. * @property {Boolean} expireInactiveSessions Sets whether we should expire the inactive sessions, defaults to true. If false, all new sessions are created with no expiration date. diff --git a/src/Options/index.js b/src/Options/index.js index 2008301c7d..a8414c658c 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -202,6 +202,9 @@ export interface ParseServerOptions { cacheAdapter: ?Adapter; /* Adapter module for email sending */ emailAdapter: ?Adapter; + /* If set to `true`, a `Parse.Object` that is in the payload when calling a Cloud Function will be converted to an instance of `Parse.Object`. If `false`, the object will not be converted and instead be a plain JavaScript object, which contains the raw data of a `Parse.Object` but is not an actual instance of `Parse.Object`. Default is `false`.

ℹ️ The expected behavior would be that the object is converted to an instance of `Parse.Object`, so you would normally set this option to `true`. The default is `false` because this is a temporary option that has been introduced to avoid a breaking change when fixing a bug where JavaScript objects are not converted to actual instances of `Parse.Object`. + :DEFAULT: false */ + encodeParseObjectInCloudFunction: ?boolean; /* Public URL to your parse server with http:// or https://. :ENV: PARSE_PUBLIC_SERVER_URL */ publicServerURL: ?string; diff --git a/src/Routers/FunctionsRouter.js b/src/Routers/FunctionsRouter.js index da69d54e0c..bb4b959ebe 100644 --- a/src/Routers/FunctionsRouter.js +++ b/src/Routers/FunctionsRouter.js @@ -9,7 +9,7 @@ import { jobStatusHandler } from '../StatusHandler'; import _ from 'lodash'; import { logger } from '../logger'; -function parseObject(obj) { +function parseObject(obj, config) { if (Array.isArray(obj)) { return obj.map(item => { return parseObject(item); @@ -18,21 +18,21 @@ function parseObject(obj) { return Object.assign(new Date(obj.iso), obj); } else if (obj && obj.__type == 'File') { return Parse.File.fromJSON(obj); - } else if (obj && obj.__type == 'Pointer') { + } else if (obj && obj.__type == 'Pointer' && config.encodeParseObjectInCloudFunction) { return Parse.Object.fromJSON({ __type: 'Pointer', className: obj.className, objectId: obj.objectId, }); } else if (obj && typeof obj === 'object') { - return parseParams(obj); + return parseParams(obj, config); } else { return obj; } } -function parseParams(params) { - return _.mapValues(params, parseObject); +function parseParams(params, config) { + return _.mapValues(params, item => parseObject(item, config)); } export class FunctionsRouter extends PromiseRouter { @@ -66,7 +66,7 @@ export class FunctionsRouter extends PromiseRouter { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'Invalid job.'); } let params = Object.assign({}, req.body, req.query); - params = parseParams(params); + params = parseParams(params, req.config); const request = { params: params, log: req.config.loggerController, @@ -126,7 +126,7 @@ export class FunctionsRouter extends PromiseRouter { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, `Invalid function: "${functionName}"`); } let params = Object.assign({}, req.body, req.query); - params = parseParams(params); + params = parseParams(params, req.config); const request = { params: params, master: req.auth && req.auth.isMaster,