From 4e6a375b5184ae0f7aa256a921eca4021c609435 Mon Sep 17 00:00:00 2001 From: Onur <154966188+onurhanife@users.noreply.github.com> Date: Thu, 15 Feb 2024 00:54:30 +0300 Subject: [PATCH] feat: Deprecation DEPPS7: Remove deprecated Cloud Code file trigger syntax (#8855) BREAKING CHANGE: Cloud Code file trigger syntax has been aligned with object trigger syntax, for example `Parse.Cloud.beforeDeleteFile'` has been changed to `Parse.Cloud.beforeDelete(Parse.File, (request) => {})'` --- DEPRECATIONS.md | 2 +- spec/CloudCode.spec.js | 81 +++++----------------- src/Options/Definitions.js | 6 +- src/Options/docs.js | 6 +- src/Options/index.js | 6 +- src/cloud-code/Parse.Cloud.js | 127 +--------------------------------- 6 files changed, 27 insertions(+), 201 deletions(-) diff --git a/DEPRECATIONS.md b/DEPRECATIONS.md index b825e50b2f..7153f6f532 100644 --- a/DEPRECATIONS.md +++ b/DEPRECATIONS.md @@ -10,7 +10,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h | DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - | | DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | -| 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 | - | +| 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) | removed | - | | 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) | 8.0.0 (2025) | deprecated | - | diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index a1c8b48bfd..239a58d39f 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -3635,7 +3635,7 @@ describe('afterLogin hook', () => { }); describe('saveFile hooks', () => { - it('beforeSaveFile should return file that is already saved and not save anything to files adapter', async () => { + it('beforeSave(Parse.File) should return file that is already saved and not save anything to files adapter', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, () => { @@ -3651,7 +3651,7 @@ describe('saveFile hooks', () => { expect(createFileSpy).not.toHaveBeenCalled(); }); - it('beforeSaveFile should throw error', async () => { + it('beforeSave(Parse.File) should throw error', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, () => { throw new Parse.Error(400, 'some-error-message'); @@ -3664,7 +3664,7 @@ describe('saveFile hooks', () => { } }); - it('beforeSaveFile should change values of uploaded file by editing fileObject directly', async () => { + it('beforeSave(Parse.File) should change values of uploaded file by editing fileObject directly', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3693,7 +3693,7 @@ describe('saveFile hooks', () => { ); }); - it('beforeSaveFile should change values by returning new fileObject', async () => { + it('beforeSave(Parse.File) should change values by returning new fileObject', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3727,7 +3727,7 @@ describe('saveFile hooks', () => { expect(file._name.indexOf(expectedFileName)).toBe(file._name.length - expectedFileName.length); }); - it('beforeSaveFile should contain metadata and tags saved from client', async () => { + it('beforeSave(Parse.File) should contain metadata and tags saved from client', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, async req => { @@ -3755,7 +3755,7 @@ describe('saveFile hooks', () => { ); }); - it('beforeSaveFile should return same file data with new file name', async () => { + it('beforeSave(Parse.File) should return same file data with new file name', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const config = Config.get('test'); config.filesController.options.preserveFileName = true; @@ -3770,7 +3770,7 @@ describe('saveFile hooks', () => { expect(result.name()).toBe('2020-04-01.txt'); }); - it('afterSaveFile should set fileSize to null if beforeSave returns an already saved file', async () => { + it('afterSave(Parse.File) should set fileSize to null if beforeSave returns an already saved file', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough(); Parse.Cloud.beforeSave(Parse.File, req => { @@ -3790,7 +3790,7 @@ describe('saveFile hooks', () => { expect(createFileSpy).not.toHaveBeenCalled(); }); - it('afterSaveFile should throw error', async () => { + it('afterSave(Parse.File) should throw error', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.afterSave(Parse.File, async () => { throw new Parse.Error(400, 'some-error-message'); @@ -3804,7 +3804,7 @@ describe('saveFile hooks', () => { } }); - it('afterSaveFile should call with fileObject', async done => { + it('afterSave(Parse.File) should call with fileObject', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, async req => { req.file.setTags({ tagA: 'some-tag' }); @@ -3820,7 +3820,7 @@ describe('saveFile hooks', () => { await file.save({ useMasterKey: true }); }); - it('afterSaveFile should change fileSize when file data changes', async done => { + it('afterSave(Parse.File) should change fileSize when file data changes', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, async req => { expect(req.fileSize).toBe(3); @@ -3837,7 +3837,7 @@ describe('saveFile hooks', () => { await file.save({ useMasterKey: true }); }); - it('beforeDeleteFile should call with fileObject', async () => { + it('beforeDelete(Parse.File) should call with fileObject', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, req => { expect(req.file).toBeInstanceOf(Parse.File); @@ -3849,7 +3849,7 @@ describe('saveFile hooks', () => { await file.destroy({ useMasterKey: true }); }); - it('beforeDeleteFile should throw error', async done => { + it('beforeDelete(Parse.File) should throw error', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, () => { throw new Error('some error message'); @@ -3863,7 +3863,7 @@ describe('saveFile hooks', () => { } }); - it('afterDeleteFile should call with fileObject', async done => { + it('afterDelete(Parse.File) should call with fileObject', async done => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeDelete(Parse.File, req => { expect(req.file).toBeInstanceOf(Parse.File); @@ -3880,7 +3880,7 @@ describe('saveFile hooks', () => { await file.destroy({ useMasterKey: true }); }); - it('beforeSaveFile should not change file if nothing is returned', async () => { + it('beforeSave(Parse.File) should not change file if nothing is returned', async () => { await reconfigureServer({ filesAdapter: mockAdapter }); Parse.Cloud.beforeSave(Parse.File, () => { return; @@ -3890,7 +3890,7 @@ describe('saveFile hooks', () => { expect(result).toBe(file); }); - it('throw custom error from beforeSaveFile', async done => { + it('throw custom error from beforeSave(Parse.File) ', async done => { Parse.Cloud.beforeSave(Parse.File, () => { throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'It should fail'); }); @@ -3904,7 +3904,7 @@ describe('saveFile hooks', () => { } }); - it('throw empty error from beforeSaveFile', async done => { + it('throw empty error from beforeSave(Parse.File)', async done => { Parse.Cloud.beforeSave(Parse.File, () => { throw null; }); @@ -3917,55 +3917,6 @@ describe('saveFile hooks', () => { done(); } }); - - it('legacy hooks', async () => { - await reconfigureServer({ filesAdapter: mockAdapter }); - const logger = require('../lib/logger').logger; - const logSpy = spyOn(logger, 'warn').and.callFake(() => {}); - const triggers = { - beforeSaveFile(req) { - req.file.setTags({ tagA: 'some-tag' }); - req.file.setMetadata({ foo: 'bar' }); - expect(req.triggerName).toEqual('beforeSave'); - expect(req.master).toBe(true); - }, - afterSaveFile(req) { - expect(req.master).toBe(true); - expect(req.file._tags).toEqual({ tagA: 'some-tag' }); - expect(req.file._metadata).toEqual({ foo: 'bar' }); - }, - beforeDeleteFile(req) { - expect(req.file).toBeInstanceOf(Parse.File); - expect(req.file._name).toEqual('popeye.txt'); - expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt'); - expect(req.fileSize).toBe(null); - }, - afterDeleteFile(req) { - expect(req.file).toBeInstanceOf(Parse.File); - expect(req.file._name).toEqual('popeye.txt'); - expect(req.file._url).toEqual('http://www.somewhere.com/popeye.txt'); - }, - }; - - for (const key in triggers) { - spyOn(triggers, key).and.callThrough(); - Parse.Cloud[key](triggers[key]); - } - - const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain'); - await file.save({ useMasterKey: true }); - await new Parse.File('popeye.txt', [1, 2, 3], 'text/plain').destroy({ useMasterKey: true }); - await new Promise(resolve => setTimeout(resolve, 100)); - for (const key in triggers) { - expect(triggers[key]).toHaveBeenCalled(); - expect(logSpy).toHaveBeenCalledWith( - `DeprecationWarning: Parse.Cloud.${key} is deprecated and will be removed in a future version. Use Parse.Cloud.${key.replace( - 'File', - '' - )}(Parse.File, (request) => {})` - ); - } - }); }); describe('sendEmail', () => { diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js index 35da35bb5f..b9dd882dbb 100644 --- a/src/Options/Definitions.js +++ b/src/Options/Definitions.js @@ -1063,19 +1063,19 @@ module.exports.LogLevels = { triggerAfter: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_AFTER', help: - 'Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`.', + 'Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`.', default: 'info', }, triggerBeforeError: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_BEFORE_ERROR', help: - 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `.', + 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`.', default: 'error', }, triggerBeforeSuccess: { env: 'PARSE_SERVER_LOG_LEVELS_TRIGGER_BEFORE_SUCCESS', help: - 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`.', + 'Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`.', default: 'info', }, }; diff --git a/src/Options/docs.js b/src/Options/docs.js index 643123c253..3dbb9b34d0 100644 --- a/src/Options/docs.js +++ b/src/Options/docs.js @@ -247,7 +247,7 @@ * @interface LogLevels * @property {String} cloudFunctionError Log level used by the Cloud Code Functions on error. Default is `error`. * @property {String} cloudFunctionSuccess Log level used by the Cloud Code Functions on success. Default is `info`. - * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`. - * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `. - * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`. + * @property {String} triggerAfter Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. + * @property {String} triggerBeforeError Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. + * @property {String} triggerBeforeSuccess Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. */ diff --git a/src/Options/index.js b/src/Options/index.js index cfda946a05..0c6e82e4c6 100644 --- a/src/Options/index.js +++ b/src/Options/index.js @@ -607,15 +607,15 @@ export interface AuthAdapter { } export interface LogLevels { - /* Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterSaveFile`, `afterDeleteFile`, `afterFind`, `afterLogout`. Default is `info`. + /* Log level used by the Cloud Code Triggers `afterSave`, `afterDelete`, `afterFind`, `afterLogout`. Default is `info`. :DEFAULT: info */ triggerAfter: ?string; - /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on success. Default is `info`. + /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on success. Default is `info`. :DEFAULT: info */ triggerBeforeSuccess: ?string; - /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeSaveFile`, `beforeDeleteFile`, `beforeFind`, `beforeLogin` on error. Default is `error `. + /* Log level used by the Cloud Code Triggers `beforeSave`, `beforeDelete`, `beforeFind`, `beforeLogin` on error. Default is `error`. :DEFAULT: error */ triggerBeforeError: ?string; diff --git a/src/cloud-code/Parse.Cloud.js b/src/cloud-code/Parse.Cloud.js index 01bf65f42c..e37cc9b225 100644 --- a/src/cloud-code/Parse.Cloud.js +++ b/src/cloud-code/Parse.Cloud.js @@ -1,6 +1,5 @@ import { Parse } from 'parse/node'; import * as triggers from '../triggers'; -import Deprecator from '../Deprecator/Deprecator'; import { addRateLimit } from '../middlewares'; const Config = require('../Config'); @@ -502,130 +501,6 @@ ParseCloud.afterFind = function (parseClass, handler, validationHandler) { ); }; -/** - * Registers a before save file function. - * - * **Available in Cloud Code only.** - * - * ``` - * Parse.Cloud.beforeSaveFile(async (request) => { - * // code here - * }, (request) => { - * // validation code here - * }); - * - * Parse.Cloud.beforeSaveFile(async (request) => { - * // code here - * }, { ...validationObject }); - *``` - * - * @method beforeSaveFile - * @deprecated - * @name Parse.Cloud.beforeSaveFile - * @param {Function} func The function to run before saving a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. - * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. - */ -ParseCloud.beforeSaveFile = function (handler, validationHandler) { - Deprecator.logRuntimeDeprecation({ - usage: 'Parse.Cloud.beforeSaveFile', - solution: 'Use Parse.Cloud.beforeSave(Parse.File, (request) => {})', - }); - ParseCloud.beforeSave(Parse.File, handler, validationHandler); -}; - -/** - * Registers an after save file function. - * - * **Available in Cloud Code only.** - * - * ``` - * Parse.Cloud.afterSaveFile(async (request) => { - * // code here - * }, (request) => { - * // validation code here - * }); - * - * Parse.Cloud.afterSaveFile(async (request) => { - * // code here - * }, { ...validationObject }); - *``` - * - * @method afterSaveFile - * @deprecated - * @name Parse.Cloud.afterSaveFile - * @param {Function} func The function to run after saving a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. - * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. - */ -ParseCloud.afterSaveFile = function (handler, validationHandler) { - Deprecator.logRuntimeDeprecation({ - usage: 'Parse.Cloud.afterSaveFile', - solution: 'Use Parse.Cloud.afterSave(Parse.File, (request) => {})', - }); - ParseCloud.afterSave(Parse.File, handler, validationHandler); -}; - -/** - * Registers a before delete file function. - * - * **Available in Cloud Code only.** - * - * ``` - * Parse.Cloud.beforeDeleteFile(async (request) => { - * // code here - * }, (request) => { - * // validation code here - * }); - * - * Parse.Cloud.beforeDeleteFile(async (request) => { - * // code here - * }, { ...validationObject }); - *``` - * - * @method beforeDeleteFile - * @deprecated - * @name Parse.Cloud.beforeDeleteFile - * @param {Function} func The function to run before deleting a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. - * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. - */ -ParseCloud.beforeDeleteFile = function (handler, validationHandler) { - Deprecator.logRuntimeDeprecation({ - usage: 'Parse.Cloud.beforeDeleteFile', - solution: 'Use Parse.Cloud.beforeDelete(Parse.File, (request) => {})', - }); - ParseCloud.beforeDelete(Parse.File, handler, validationHandler); -}; - -/** - * Registers an after delete file function. - * - * **Available in Cloud Code only.** - * - * ``` - * Parse.Cloud.afterDeleteFile(async (request) => { - * // code here - * }, (request) => { - * // validation code here - * }); - * - * Parse.Cloud.afterDeleteFile(async (request) => { - * // code here - * }, { ...validationObject }); - *``` - * - * @method afterDeleteFile - * @deprecated - * @name Parse.Cloud.afterDeleteFile - * @param {Function} func The function to after before deleting a file. This function can be async and should take just one parameter, {@link Parse.Cloud.FileTriggerRequest}. - * @param {(Object|Function)} validator An optional function to help validating cloud code. This function can be an async function and should take one parameter a {@link Parse.Cloud.FileTriggerRequest}, or a {@link Parse.Cloud.ValidatorObject}. - */ -ParseCloud.afterDeleteFile = function (handler, validationHandler) { - Deprecator.logRuntimeDeprecation({ - usage: 'Parse.Cloud.afterDeleteFile', - solution: 'Use Parse.Cloud.afterDelete(Parse.File, (request) => {})', - }); - ParseCloud.afterDelete(Parse.File, handler, validationHandler); -}; - /** * Registers a before live query server connect function. * @@ -803,7 +678,7 @@ module.exports = ParseCloud; * @property {Integer} contentLength The value from Content-Length header * @property {String} ip The IP address of the client making the request. * @property {Object} headers The original HTTP headers for the request. - * @property {String} triggerName The name of the trigger (`beforeSaveFile`, `afterSaveFile`) + * @property {String} triggerName The name of the trigger (`beforeSave`, `afterSave`) * @property {Object} log The current logger inside Parse Server. */