diff --git a/packages/cozy-clisk/src/launcher/saveFiles.js b/packages/cozy-clisk/src/launcher/saveFiles.js index bd4bf0d89..4555cb7f2 100644 --- a/packages/cozy-clisk/src/launcher/saveFiles.js +++ b/packages/cozy-clisk/src/launcher/saveFiles.js @@ -21,6 +21,7 @@ import { dataUriToArrayBuffer } from '../libs/utils' * @property {import('cozy-client/types/types').IOCozyFile} [existingFile] - already existing file corresponding to the entry * @property {boolean} [shouldReplace] - Internal result of the shouldReplaceFile function on the entry * @property {boolean} [forceReplaceFile] - should the konnector force the replace of the current file + * @property {import('cozy-client/types/types').IOCozyFile} [fileDocument] - Resulting cozy file */ /** @@ -137,9 +138,8 @@ const saveFiles = async (client, entries, folderPath, options) => { // do not create subPath folder or call saveFile for existing files or files that don't need to be replaced for (const entry of entries) { - const existingFile = options.existingFilesIndex.get( - calculateFileKey(entry, options.fileIdAttributes) - ) + const fileKey = calculateFileKey(entry, options.fileIdAttributes) + const existingFile = options.existingFilesIndex.get(fileKey) let shouldReplace = false if (existingFile) { shouldReplace = shouldReplaceFile(existingFile, entry, saveOptions) @@ -161,6 +161,13 @@ const saveFiles = async (client, entries, folderPath, options) => { let savedFiles = 0 for (const entry of toSaveEntries) { + const fileKey = calculateFileKey(entry, options.fileIdAttributes) + if (options.existingFilesIndex.get(fileKey) && !entry.forceReplaceFile) { + // do not save multiple entries related to the same file. (Can be the case with saveBills + // with multiple bills associated to the same file) + continue + } + const start = Date.now() ;['filename'].forEach(key => addValOrFnResult(entry, key, options)) @@ -174,6 +181,7 @@ const saveFiles = async (client, entries, folderPath, options) => { delete savedEntry._cozy_file_to_create } savedEntries.push(savedEntry) + options.existingFilesIndex.set(fileKey, savedEntry.fileDocument) const end = Date.now() saveOptions.log( 'debug', diff --git a/packages/cozy-clisk/src/launcher/saveFiles.spec.js b/packages/cozy-clisk/src/launcher/saveFiles.spec.js index abc662bf4..787ffcd6c 100644 --- a/packages/cozy-clisk/src/launcher/saveFiles.spec.js +++ b/packages/cozy-clisk/src/launcher/saveFiles.spec.js @@ -576,4 +576,51 @@ describe('saveFiles', function () { } ]) }) + it('should save only one file even with multiple entries related to the same file', async () => { + const client = { + save: jest.fn().mockImplementation(doc => ({ + data: doc + })), + query: jest.fn().mockResolvedValue({ included: [], data: null }), + collection: () => ({ + statByPath: jest.fn().mockImplementation(path => { + return { data: { _id: path } } + }), + addReferencesTo: jest.fn() + }) + } + const documents = [ + { + filestream: 'filestream content', + filename: 'file name.txt' + }, + { + filestream: 'filestream content 2', + filename: 'file name.txt' + } + ] + await saveFiles(client, documents, '/test/folder/path', { + manifest: { + slug: 'testslug' + }, + sourceAccount: 'testsourceaccount', + sourceAccountIdentifier: 'testsourceaccountidentifier', + fileIdAttributes: ['filename'], + existingFilesIndex: new Map(), + log: jest.fn() + }) + expect(client.save).toHaveBeenCalledTimes(1) + expect(client.save).toHaveBeenNthCalledWith(1, { + _type: 'io.cozy.files', + data: 'filestream content', + dirId: '/test/folder/path', + metadata: { + fileIdAttributes: 'file name.txt' + }, + name: 'file name.txt', + sourceAccount: 'testsourceaccount', + sourceAccountIdentifier: 'testsourceaccountidentifier', + type: 'file' + }) + }) })