Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: align file trigger syntax with class trigger #7966

Merged
merged 15 commits into from
May 29, 2022
Merged
1 change: 1 addition & 0 deletions DEPRECATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| 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) | deprecated | - |
| DEPPS5 | Remove legacy file triggers in preference to `Parse.Cloud.beforeSave(Parse.File, (req) => {})` | [#7966](https://github.com/parse-community/parse-server/pull/7966) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
dblythy marked this conversation as resolved.
Show resolved Hide resolved

[i_deprecation]: ## "The version and date of the deprecation."
[i_removal]: ## "The version and date of the planned removal."
Expand Down
19 changes: 10 additions & 9 deletions spec/CloudCode.Validator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,8 @@ describe('cloud validator', () => {
});

it('basic beforeSaveFile skipWithMasterKey', async done => {
Parse.Cloud.beforeSaveFile(
Parse.Cloud.beforeSave(
Parse.File,
() => {
throw 'beforeSaveFile should have resolved using master key.';
},
Expand Down Expand Up @@ -1431,7 +1432,7 @@ describe('cloud validator', () => {
});

it('validate beforeSaveFile', async done => {
Parse.Cloud.beforeSaveFile(() => {}, validatorSuccess);
Parse.Cloud.beforeSave(Parse.File, () => {}, validatorSuccess);

const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
const result = await file.save({ useMasterKey: true });
Expand All @@ -1440,7 +1441,7 @@ describe('cloud validator', () => {
});

it('validate beforeSaveFile fail', async done => {
Parse.Cloud.beforeSaveFile(() => {}, validatorFail);
Parse.Cloud.beforeSave(Parse.File, () => {}, validatorFail);
try {
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save({ useMasterKey: true });
Expand All @@ -1452,7 +1453,7 @@ describe('cloud validator', () => {
});

it('validate afterSaveFile', async done => {
Parse.Cloud.afterSaveFile(() => {}, validatorSuccess);
Parse.Cloud.afterSave(Parse.File, () => {}, validatorSuccess);

const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
const result = await file.save({ useMasterKey: true });
Expand All @@ -1461,7 +1462,7 @@ describe('cloud validator', () => {
});

it('validate afterSaveFile fail', async done => {
Parse.Cloud.beforeSaveFile(() => {}, validatorFail);
Parse.Cloud.beforeSave(Parse.File, () => {}, validatorFail);
try {
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save({ useMasterKey: true });
Expand All @@ -1473,7 +1474,7 @@ describe('cloud validator', () => {
});

it('validate beforeDeleteFile', async done => {
Parse.Cloud.beforeDeleteFile(() => {}, validatorSuccess);
Parse.Cloud.beforeDelete(Parse.File, () => {}, validatorSuccess);

const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save();
Expand All @@ -1482,7 +1483,7 @@ describe('cloud validator', () => {
});

it('validate beforeDeleteFile fail', async done => {
Parse.Cloud.beforeDeleteFile(() => {}, validatorFail);
Parse.Cloud.beforeDelete(Parse.File, () => {}, validatorFail);
try {
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save();
Expand All @@ -1495,7 +1496,7 @@ describe('cloud validator', () => {
});

it('validate afterDeleteFile', async done => {
Parse.Cloud.afterDeleteFile(() => {}, validatorSuccess);
Parse.Cloud.afterDelete(Parse.File, () => {}, validatorSuccess);

const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save();
Expand All @@ -1504,7 +1505,7 @@ describe('cloud validator', () => {
});

it('validate afterDeleteFile fail', async done => {
Parse.Cloud.afterDeleteFile(() => {}, validatorFail);
Parse.Cloud.afterDelete(Parse.File, () => {}, validatorFail);
try {
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
await file.save();
Expand Down
95 changes: 72 additions & 23 deletions spec/CloudCode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3379,7 +3379,7 @@ describe('saveFile hooks', () => {
it('beforeSaveFile 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.beforeSaveFile(() => {
Parse.Cloud.beforeSave(Parse.File, () => {
const newFile = new Parse.File('some-file.txt');
newFile._url = 'http://www.somewhere.com/parse/files/some-app-id/some-file.txt';
return newFile;
Expand All @@ -3394,7 +3394,7 @@ describe('saveFile hooks', () => {

it('beforeSaveFile should throw error', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSaveFile(() => {
Parse.Cloud.beforeSave(Parse.File, () => {
throw new Parse.Error(400, 'some-error-message');
});
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
Expand All @@ -3408,8 +3408,8 @@ describe('saveFile hooks', () => {
it('beforeSaveFile should change values of uploaded file by editing fileObject directly', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSaveFile(async req => {
expect(req.triggerName).toEqual('beforeSaveFile');
Parse.Cloud.beforeSave(Parse.File, async req => {
expect(req.triggerName).toEqual('beforeSave');
expect(req.master).toBe(true);
req.file.addMetadata('foo', 'bar');
req.file.addTag('tagA', 'some-tag');
Expand Down Expand Up @@ -3437,8 +3437,8 @@ describe('saveFile hooks', () => {
it('beforeSaveFile should change values by returning new fileObject', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSaveFile(async req => {
expect(req.triggerName).toEqual('beforeSaveFile');
Parse.Cloud.beforeSave(Parse.File, async req => {
expect(req.triggerName).toEqual('beforeSave');
expect(req.fileSize).toBe(3);
const newFile = new Parse.File('donald_duck.pdf', [4, 5, 6], 'application/pdf');
newFile.setMetadata({ foo: 'bar' });
Expand Down Expand Up @@ -3471,8 +3471,8 @@ describe('saveFile hooks', () => {
it('beforeSaveFile should contain metadata and tags saved from client', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const createFileSpy = spyOn(mockAdapter, 'createFile').and.callThrough();
Parse.Cloud.beforeSaveFile(async req => {
expect(req.triggerName).toEqual('beforeSaveFile');
Parse.Cloud.beforeSave(Parse.File, async req => {
expect(req.triggerName).toEqual('beforeSave');
expect(req.fileSize).toBe(3);
expect(req.file).toBeInstanceOf(Parse.File);
expect(req.file.name()).toBe('popeye.txt');
Expand Down Expand Up @@ -3500,7 +3500,7 @@ describe('saveFile hooks', () => {
await reconfigureServer({ filesAdapter: mockAdapter });
const config = Config.get('test');
config.filesController.options.preserveFileName = true;
Parse.Cloud.beforeSaveFile(async ({ file }) => {
Parse.Cloud.beforeSave(Parse.File, async ({ file }) => {
expect(file.name()).toBe('popeye.txt');
const fileData = await file.getData();
const newFile = new Parse.File('2020-04-01.txt', { base64: fileData });
Expand All @@ -3514,13 +3514,13 @@ describe('saveFile hooks', () => {
it('afterSaveFile 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.beforeSaveFile(req => {
Parse.Cloud.beforeSave(Parse.File, req => {
expect(req.fileSize).toBe(3);
const newFile = new Parse.File('some-file.txt');
newFile._url = 'http://www.somewhere.com/parse/files/some-app-id/some-file.txt';
return newFile;
});
Parse.Cloud.afterSaveFile(req => {
Parse.Cloud.afterSave(Parse.File, req => {
expect(req.fileSize).toBe(null);
});
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
Expand All @@ -3533,7 +3533,7 @@ describe('saveFile hooks', () => {

it('afterSaveFile should throw error', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.afterSaveFile(async () => {
Parse.Cloud.afterSave(Parse.File, async () => {
throw new Parse.Error(400, 'some-error-message');
});
const filename = 'donald_duck.pdf';
Expand All @@ -3547,11 +3547,11 @@ describe('saveFile hooks', () => {

it('afterSaveFile should call with fileObject', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSaveFile(async req => {
Parse.Cloud.beforeSave(Parse.File, async req => {
req.file.setTags({ tagA: 'some-tag' });
req.file.setMetadata({ foo: 'bar' });
});
Parse.Cloud.afterSaveFile(async req => {
Parse.Cloud.afterSave(Parse.File, async req => {
expect(req.master).toBe(true);
expect(req.file._tags).toEqual({ tagA: 'some-tag' });
expect(req.file._metadata).toEqual({ foo: 'bar' });
Expand All @@ -3563,13 +3563,13 @@ describe('saveFile hooks', () => {

it('afterSaveFile should change fileSize when file data changes', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSaveFile(async req => {
Parse.Cloud.beforeSave(Parse.File, async req => {
expect(req.fileSize).toBe(3);
expect(req.master).toBe(true);
const newFile = new Parse.File('donald_duck.pdf', [4, 5, 6, 7, 8, 9], 'application/pdf');
return newFile;
});
Parse.Cloud.afterSaveFile(async req => {
Parse.Cloud.afterSave(Parse.File, async req => {
expect(req.fileSize).toBe(6);
expect(req.master).toBe(true);
done();
Expand All @@ -3580,7 +3580,7 @@ describe('saveFile hooks', () => {

it('beforeDeleteFile should call with fileObject', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDeleteFile(req => {
Parse.Cloud.beforeDelete(Parse.File, 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');
Expand All @@ -3592,7 +3592,7 @@ describe('saveFile hooks', () => {

it('beforeDeleteFile should throw error', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDeleteFile(() => {
Parse.Cloud.beforeDelete(Parse.File, () => {
throw new Error('some error message');
});
const file = new Parse.File('popeye.txt');
Expand All @@ -3606,12 +3606,12 @@ describe('saveFile hooks', () => {

it('afterDeleteFile should call with fileObject', async done => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeDeleteFile(req => {
Parse.Cloud.beforeDelete(Parse.File, 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');
});
Parse.Cloud.afterDeleteFile(req => {
Parse.Cloud.afterDelete(Parse.File, 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');
Expand All @@ -3623,7 +3623,7 @@ describe('saveFile hooks', () => {

it('beforeSaveFile should not change file if nothing is returned', async () => {
await reconfigureServer({ filesAdapter: mockAdapter });
Parse.Cloud.beforeSaveFile(() => {
Parse.Cloud.beforeSave(Parse.File, () => {
return;
});
const file = new Parse.File('popeye.txt', [1, 2, 3], 'text/plain');
Expand All @@ -3632,7 +3632,7 @@ describe('saveFile hooks', () => {
});

it('throw custom error from beforeSaveFile', async done => {
Parse.Cloud.beforeSaveFile(() => {
Parse.Cloud.beforeSave(Parse.File, () => {
throw new Parse.Error(Parse.Error.SCRIPT_FAILED, 'It should fail');
});
try {
Expand All @@ -3646,7 +3646,7 @@ describe('saveFile hooks', () => {
});

it('throw empty error from beforeSaveFile', async done => {
Parse.Cloud.beforeSaveFile(() => {
Parse.Cloud.beforeSave(Parse.File, () => {
throw null;
});
try {
Expand All @@ -3658,6 +3658,55 @@ 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, (req) => {})`
);
}
});
});

describe('sendEmail', () => {
Expand Down
13 changes: 4 additions & 9 deletions src/Routers/FilesRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export class FilesRouter {
try {
// run beforeSaveFile trigger
const triggerResult = await triggers.maybeRunFileTrigger(
triggers.Types.beforeSaveFile,
triggers.Types.beforeSave,
fileObject,
config,
req.auth
Expand Down Expand Up @@ -194,12 +194,7 @@ export class FilesRouter {
};
}
// run afterSaveFile trigger
await triggers.maybeRunFileTrigger(
triggers.Types.afterSaveFile,
fileObject,
config,
req.auth
);
await triggers.maybeRunFileTrigger(triggers.Types.afterSave, fileObject, config, req.auth);
res.status(201);
res.set('Location', saveResult.url);
res.json(saveResult);
Expand All @@ -222,7 +217,7 @@ export class FilesRouter {
file._url = filesController.adapter.getFileLocation(req.config, filename);
const fileObject = { file, fileSize: null };
await triggers.maybeRunFileTrigger(
triggers.Types.beforeDeleteFile,
triggers.Types.beforeDelete,
fileObject,
req.config,
req.auth
Expand All @@ -231,7 +226,7 @@ export class FilesRouter {
await filesController.deleteFile(req.config, filename);
// run afterDeleteFile trigger
await triggers.maybeRunFileTrigger(
triggers.Types.afterDeleteFile,
triggers.Types.afterDelete,
fileObject,
req.config,
req.auth
Expand Down
Loading