diff --git a/api-tests/core/upload/admin/folder-file.test.api.js b/api-tests/core/upload/admin/folder-file.test.api.js index 2b3e82d43b5..b299a88a1e5 100644 --- a/api-tests/core/upload/admin/folder-file.test.api.js +++ b/api-tests/core/upload/admin/folder-file.test.api.js @@ -220,6 +220,34 @@ describe('Bulk actions for folders & files', () => { const existingfoldersIds = resFolder.body.data.map((f) => f.id); expect(existingfoldersIds).toEqual(expect.not.arrayContaining([folder.id])); }); + + test('Can delete folders without deleting others with similar path', async () => { + // Ensure the folder algo does not only delete by folders that start with the same path (startswith /1 matches /10 too) + + // Delete all previous folders, so first file path is /1 + await rq + .get('/upload/folders') + .then((res) => res.body.data.map((f) => f.id)) + .then((folderIds) => rq.post('/upload/actions/bulk-delete', { body: { folderIds } })); + + // Create folders + const folder1 = await createFolder('folderToDelete', null); + for (let i = 0; i < 20; i++) { + await createFolder(`folderToKeep-${i}`, null); + } + // Delete folder1 + await rq.post('/upload/actions/bulk-delete', { + body: { folderIds: [folder1.id] }, + }); + + const folderIds = await rq + .get('/upload/folders') + .then((res) => res.body.data.map((f) => f.id)); + + // Should include all folders except the one we deleted + expect(folderIds.length).toBe(20); + expect(folderIds).toEqual(expect.not.arrayContaining([folder1.id])); + }); }); describe('move', () => { diff --git a/packages/core/upload/server/services/folder.js b/packages/core/upload/server/services/folder.js index d8b5769a156..a046ed2b427 100644 --- a/packages/core/upload/server/services/folder.js +++ b/packages/core/upload/server/services/folder.js @@ -56,16 +56,22 @@ const deleteByIds = async (ids = []) => { // delete files const filesToDelete = await strapi.db.query(FILE_MODEL_UID).findMany({ where: { - $or: pathsToDelete.map((path) => ({ folderPath: { $startsWith: path } })), + $or: pathsToDelete.flatMap((path) => [ + { folderPath: { $eq: path } }, + { folderPath: { $startsWith: `${path}/` } }, + ]), }, }); await Promise.all(filesToDelete.map((file) => getService('upload').remove(file))); - // delete folders + // delete folders and subfolders const { count: totalFolderNumber } = await strapi.db.query(FOLDER_MODEL_UID).deleteMany({ where: { - $or: pathsToDelete.map((path) => ({ path: { $startsWith: path } })), + $or: pathsToDelete.flatMap((path) => [ + { path: { $eq: path } }, + { path: { $startsWith: `${path}/` } }, + ]), }, });