diff --git a/app/api/files/files.ts b/app/api/files/files.ts index 1c91d0c9ce..dad29a898d 100644 --- a/app/api/files/files.ts +++ b/app/api/files/files.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-statements */ import entities from 'api/entities'; import { applicationEventsBus } from 'api/eventsbus'; import { mimeTypeFromUrl } from 'api/files/extensionHelper'; @@ -25,11 +26,19 @@ const deduceMimeType = (_file: FileType) => { return file; }; +export class UpdateFileError extends Error { + constructor() { + super('Can not update a File that does not exist'); + } +} + export const files = { async save(_file: FileType, index = true) { const file = deduceMimeType(_file); const existingFile = file._id ? await filesModel.getById(file._id) : undefined; + if (file._id && !existingFile) throw new UpdateFileError(); + const savedFile = await filesModel.save(await validateFile(file)); if (index) { await search.indexEntities({ sharedId: savedFile.entity }, '+fullText'); diff --git a/app/api/files/processDocument.ts b/app/api/files/processDocument.ts index f09a9a15cd..8aaba3f2b8 100644 --- a/app/api/files/processDocument.ts +++ b/app/api/files/processDocument.ts @@ -1,8 +1,9 @@ +/* eslint-disable max-statements */ import { convertToPDFService } from 'api/services/convertToPDF/convertToPdfService'; import settings from 'api/settings'; import { FileType } from 'shared/types/fileType'; -import { files } from './files'; +import { files, UpdateFileError } from './files'; import { PDF } from './PDF'; export const processPDF = async ( @@ -10,6 +11,7 @@ export const processPDF = async ( file: FileType & { destination?: string }, detectLanguage = true ) => { + let thumbnail; const pdf = new PDF(file); const upload = await files.save({ ...file, @@ -24,7 +26,13 @@ export const processPDF = async ( conversion.language = file.language; } - const thumbnail = await pdf.createThumbnail(upload._id.toString()); + const saved = await files.save({ + ...upload, + ...conversion, + status: 'ready', + }); + + thumbnail = await pdf.createThumbnail(upload._id.toString()); await files.save({ entity: entitySharedId, @@ -34,18 +42,13 @@ export const processPDF = async ( mimetype: 'image/jpeg', }); - const saved = await files.save({ - ...upload, - ...conversion, - status: 'ready', - }); - return saved; } catch (e) { await files.save({ ...upload, status: 'failed', }); + throw e; } }; diff --git a/app/api/files/specs/files.spec.ts b/app/api/files/specs/files.spec.ts new file mode 100644 index 0000000000..6235a79fc5 --- /dev/null +++ b/app/api/files/specs/files.spec.ts @@ -0,0 +1,27 @@ +import testingDB from 'api/utils/testing_db'; +import { testingEnvironment } from 'api/utils/testingEnvironment'; +import { files, UpdateFileError } from '../files'; + +describe('Files', () => { + beforeEach(async () => { + await testingEnvironment.setUp({}); + }); + + afterAll(async () => testingEnvironment.tearDown()); + + it('should not update a File if no longer exist', async () => { + const promise = files.save({ + _id: testingDB.id(), + filename: 'any_file_name', + originalname: 'any_original_name', + entity: '123', + language: 'en', + }); + + await expect(promise).rejects.toEqual(new UpdateFileError()); + + const [result] = await files.get({}); + + expect(result).toBeUndefined(); + }); +}); diff --git a/app/api/files/specs/processDocument.spec.ts b/app/api/files/specs/processDocument.spec.ts index b6576db1cb..9397ad2655 100644 --- a/app/api/files/specs/processDocument.spec.ts +++ b/app/api/files/specs/processDocument.spec.ts @@ -1,3 +1,4 @@ +import testingDB from 'api/utils/testing_db'; import { convertToPDFService, MimeTypeNotSupportedForConversion, @@ -5,7 +6,7 @@ import { import { testingEnvironment } from 'api/utils/testingEnvironment'; // eslint-disable-next-line node/no-restricted-import import { writeFile } from 'fs/promises'; -import { files } from '../files'; +import { files, UpdateFileError } from '../files'; import { attachmentsPath, setupTestUploadedPaths } from '../filesystem'; import { processDocument } from '../processDocument'; @@ -76,4 +77,20 @@ describe('processDocument', () => { expect(file).toBeUndefined(); }); }); + + it('should not persist file or thumbnail if there is an UpdateFileError', async () => { + const _id = testingDB.id(); + const promise = processDocument('any_entity_shared_id', { + _id, + filename: 'any_file_name', + originalname: 'any_original_name', + }); + + await expect(promise).rejects.toEqual(new UpdateFileError()); + const [file] = await files.get({ _id }); + const [thumbnail] = await files.get({ entity: _id, type: 'thumbnail' }); + + expect(file).toBeUndefined(); + expect(thumbnail).toBeUndefined(); + }); });