From 587b62ea7be5ef72e05de4e7cf6be002c4e55a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre=20No=C3=ABl?= Date: Wed, 6 Apr 2022 11:36:13 +0200 Subject: [PATCH] replace path by location + add location to files --- .../server/content-types/file/schema.js | 5 + .../server/content-types/folder/schema.js | 2 +- .../upload/server/controllers/admin-folder.js | 4 +- .../server/services/__tests__/file.test.js | 27 ++ .../server/services/__tests__/folder.test.js | 22 +- .../server/services/__tests__/upload.test.js | 14 + packages/core/upload/server/services/file.js | 15 + .../core/upload/server/services/folder.js | 10 +- packages/core/upload/server/services/index.js | 2 + .../core/upload/server/services/upload.js | 6 + .../tests/admin/file-folder.test.e2e.js | 387 ++++++++++++++++++ .../upload/tests/admin/file-image.test.e2e.js | 109 +++++ .../core/upload/tests/admin/file.test.e2e.js | 387 ++---------------- .../upload/tests/admin/folder.test.e2e.js | 21 +- .../upload/tests/admin/settings.test.e2e.js | 81 ++++ .../tests/content-api/upload.test.e2e.js | 85 +--- 16 files changed, 728 insertions(+), 449 deletions(-) create mode 100644 packages/core/upload/server/services/__tests__/file.test.js create mode 100644 packages/core/upload/server/services/file.js create mode 100644 packages/core/upload/tests/admin/file-folder.test.e2e.js create mode 100644 packages/core/upload/tests/admin/file-image.test.e2e.js create mode 100644 packages/core/upload/tests/admin/settings.test.e2e.js diff --git a/packages/core/upload/server/content-types/file/schema.js b/packages/core/upload/server/content-types/file/schema.js index c51a0a8a40..1fe660cf79 100644 --- a/packages/core/upload/server/content-types/file/schema.js +++ b/packages/core/upload/server/content-types/file/schema.js @@ -95,5 +95,10 @@ module.exports = { target: 'plugin::upload.folder', inversedBy: 'files', }, + location: { + type: 'string', + min: 1, + required: true, + }, }, }; diff --git a/packages/core/upload/server/content-types/folder/schema.js b/packages/core/upload/server/content-types/folder/schema.js index 4d2feff37a..dfb6806268 100644 --- a/packages/core/upload/server/content-types/folder/schema.js +++ b/packages/core/upload/server/content-types/folder/schema.js @@ -45,7 +45,7 @@ module.exports = { target: 'plugin::upload.file', mappedBy: 'folder', }, - path: { + location: { type: 'string', min: 1, required: true, diff --git a/packages/core/upload/server/controllers/admin-folder.js b/packages/core/upload/server/controllers/admin-folder.js index 46a3582c9d..22ff1019b9 100644 --- a/packages/core/upload/server/controllers/admin-folder.js +++ b/packages/core/upload/server/controllers/admin-folder.js @@ -39,10 +39,10 @@ module.exports = { await validateCreateFolder(body); - const { setPathAndUID } = getService('folder'); + const { setLocationAndUID } = getService('folder'); // TODO: wrap with a transaction - const enrichFolder = pipeAsync(setPathAndUID, setCreatorFields({ user })); + const enrichFolder = pipeAsync(setLocationAndUID, setCreatorFields({ user })); const enrichedFolder = await enrichFolder(body); const folder = await strapi.entityService.create(folderModel, { diff --git a/packages/core/upload/server/services/__tests__/file.test.js b/packages/core/upload/server/services/__tests__/file.test.js new file mode 100644 index 0000000000..9a46b578c6 --- /dev/null +++ b/packages/core/upload/server/services/__tests__/file.test.js @@ -0,0 +1,27 @@ +'use strict'; + +const { getLocation } = require('../file'); + +const folderLocation = '/9bc2352b-e29b-4ba3-810f-7b91033222de'; + +describe('file', () => { + describe('getLocation', () => { + beforeAll(() => { + global.strapi = { + entityService: { + findOne: jest.fn(() => ({ location: folderLocation })), + }, + }; + }); + + test.each([ + [[1, 'myFile.txt'], folderLocation], + [[undefined, 'myFile.txt'], '/'], + [[null, 'myFile.txt'], '/'], + ])('inputs %s should give %s', async (args, expectedResult) => { + const result = await getLocation(...args); + + expect(result).toBe(expectedResult); + }); + }); +}); diff --git a/packages/core/upload/server/services/__tests__/folder.test.js b/packages/core/upload/server/services/__tests__/folder.test.js index f6876170e9..8a8bf8f7ae 100644 --- a/packages/core/upload/server/services/__tests__/folder.test.js +++ b/packages/core/upload/server/services/__tests__/folder.test.js @@ -1,38 +1,38 @@ 'use strict'; -const { setPathAndUID } = require('../folder'); +const { setLocationAndUID } = require('../folder'); const folderUID = '9bc2352b-e29b-4ba3-810f-7b91033222de'; const uuidRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; -const rootPathRegex = /^\/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; -const folderPathRegex = new RegExp( +const rootLocationRegex = /^\/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; +const folderLocationRegex = new RegExp( '^/' + folderUID + '/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$', 'i' ); describe('folder', () => { - describe('setPathAndUID', () => { + describe('setLocationAndUID', () => { beforeAll(() => { global.strapi = { entityService: { - findOne: jest.fn(() => ({ uid: `/${folderUID}` })), + findOne: jest.fn(() => ({ location: `/${folderUID}` })), }, }; }); test.each([ - [{ parent: 1 }, folderPathRegex], - [{}, rootPathRegex], - [{ parent: null }, rootPathRegex], - ])('inputs %s', async (folder, expectedPath) => { + [{ parent: 1 }, folderLocationRegex], + [{}, rootLocationRegex], + [{ parent: null }, rootLocationRegex], + ])('inputs %s', async (folder, expectedLocation) => { const clonedFolder = { ...folder }; - const result = await setPathAndUID(clonedFolder); + const result = await setLocationAndUID(clonedFolder); expect(result).toBe(clonedFolder); expect(result).toMatchObject({ ...folder, uid: expect.stringMatching(uuidRegex), - path: expect.stringMatching(expectedPath), + location: expect.stringMatching(expectedLocation), }); }); }); diff --git a/packages/core/upload/server/services/__tests__/upload.test.js b/packages/core/upload/server/services/__tests__/upload.test.js index 9e7cd3e7a3..fdcbcb33ad 100644 --- a/packages/core/upload/server/services/__tests__/upload.test.js +++ b/packages/core/upload/server/services/__tests__/upload.test.js @@ -3,6 +3,20 @@ const uploadService = require('../upload')({}); describe('Upload service', () => { + beforeAll(() => { + global.strapi = { + plugins: { + upload: { + services: { + file: { + getLocation: () => '/a-location', + }, + }, + }, + }, + }; + }); + describe('formatFileInfo', () => { test('Generates hash', async () => { const fileData = { diff --git a/packages/core/upload/server/services/file.js b/packages/core/upload/server/services/file.js new file mode 100644 index 0000000000..e1bb5bdbbf --- /dev/null +++ b/packages/core/upload/server/services/file.js @@ -0,0 +1,15 @@ +'use strict'; + +const folderModel = 'plugin::upload.folder'; + +const getLocation = async folderId => { + if (!folderId) return '/'; + + const parentFolder = await strapi.entityService.findOne(folderModel, folderId); + + return parentFolder.location; +}; + +module.exports = { + getLocation, +}; diff --git a/packages/core/upload/server/services/folder.js b/packages/core/upload/server/services/folder.js index 2c178dfa4a..3b7536a666 100644 --- a/packages/core/upload/server/services/folder.js +++ b/packages/core/upload/server/services/folder.js @@ -23,17 +23,17 @@ const joinBy = (joint, ...args) => { const generateUID = () => uuid(); -const setPathAndUID = async folder => { +const setLocationAndUID = async folder => { const uid = generateUID(); - let parentPath = '/'; + let parentLocation = '/'; if (folder.parent) { const parentFolder = await strapi.entityService.findOne(folderModel, folder.parent); - parentPath = parentFolder.path; + parentLocation = parentFolder.location; } return Object.assign(folder, { uid, - path: joinBy('/', parentPath, uid), + location: joinBy('/', parentLocation, uid), }); }; @@ -61,5 +61,5 @@ const exists = async (params = {}) => { module.exports = { exists, deleteByIds, - setPathAndUID, + setLocationAndUID, }; diff --git a/packages/core/upload/server/services/index.js b/packages/core/upload/server/services/index.js index b648c62df7..8ab6d72f48 100644 --- a/packages/core/upload/server/services/index.js +++ b/packages/core/upload/server/services/index.js @@ -4,10 +4,12 @@ const provider = require('./provider'); const upload = require('./upload'); const imageManipulation = require('./image-manipulation'); const folder = require('./folder'); +const file = require('./file'); module.exports = { provider, upload, folder, + file, 'image-manipulation': imageManipulation, }; diff --git a/packages/core/upload/server/services/upload.js b/packages/core/upload/server/services/upload.js index fecd2d4c3e..3cf6588163 100644 --- a/packages/core/upload/server/services/upload.js +++ b/packages/core/upload/server/services/upload.js @@ -64,6 +64,8 @@ module.exports = ({ strapi }) => ({ }, async formatFileInfo({ filename, type, size }, fileInfo = {}, metas = {}) { + const fileService = getService('file'); + const ext = path.extname(filename); const basename = path.basename(fileInfo.name || filename, ext); const usedName = fileInfo.name || filename; @@ -73,6 +75,7 @@ module.exports = ({ strapi }) => ({ alternativeText: fileInfo.alternativeText, caption: fileInfo.caption, folder: fileInfo.folder, + location: await fileService.getLocation(fileInfo.folder), hash: generateFileName(basename), ext, mime: type, @@ -205,12 +208,15 @@ module.exports = ({ strapi }) => ({ throw new NotFoundError(); } + const fileService = getService('file'); + const newName = _.isNil(name) ? dbFile.name : name; const newInfos = { name: newName, alternativeText: _.isNil(alternativeText) ? dbFile.alternativeText : alternativeText, caption: _.isNil(caption) ? dbFile.caption : caption, folder: _.isUndefined(folder) ? dbFile.folder : folder, + location: _.isUndefined(folder) ? dbFile.path : await fileService.getLocation(folder), }; return this.update(id, newInfos, { user }); diff --git a/packages/core/upload/tests/admin/file-folder.test.e2e.js b/packages/core/upload/tests/admin/file-folder.test.e2e.js new file mode 100644 index 0000000000..c05f63fad5 --- /dev/null +++ b/packages/core/upload/tests/admin/file-folder.test.e2e.js @@ -0,0 +1,387 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const { createTestBuilder } = require('../../../../../test/helpers/builder'); +const { createStrapiInstance } = require('../../../../../test/helpers/strapi'); +const { createAuthRequest } = require('../../../../../test/helpers/request'); + +let strapi; +let rq; +let data = { + folders: [], + files: [], +}; + +describe('File', () => { + const builder = createTestBuilder(); + + beforeAll(async () => { + strapi = await createStrapiInstance(); + rq = await createAuthRequest({ strapi }); + + // create 2 folders + for (let i = 1; i <= 2; i += 1) { + const folderRes = await rq({ + method: 'POST', + url: '/upload/folders', + body: { name: `my folder ${i}` }, + }); + data.folders.push(folderRes.body.data); + } + }); + + afterAll(async () => { + await rq({ + method: 'POST', + url: '/upload/folders/batch-delete', + body: { + ids: data.folders.map(f => f.id), + }, + }); + + await strapi.destroy(); + await builder.cleanup(); + }); + + describe('create', () => { + test('Can create a file at root level', async () => { + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + }, + }); + + expect(res.statusCode).toBe(200); + expect(Array.isArray(res.body)).toBe(true); + expect(res.body.length).toBe(1); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body[0].id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.jpg', + ext: '.jpg', + mime: 'image/jpeg', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: null, + location: '/', + }); + + data.files.push(file); + }); + + test('Can create a file inside a folder', async () => { + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + fileInfo: JSON.stringify({ + folder: data.folders[0].id, + }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(Array.isArray(res.body)).toBe(true); + expect(res.body.length).toBe(1); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body[0].id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.jpg', + ext: '.jpg', + mime: 'image/jpeg', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: { id: data.folders[0].id }, + location: data.folders[0].location, + }); + + data.files.push(file); + }); + + test("Cannot create a file inside a folder that doesn't exist", async () => { + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + fileInfo: JSON.stringify({ + folder: '1234', // id that doesn't exist + }), + }, + }); + + expect(res.status).toBe(400); + expect(res.body.error.message).toBe("the folder doesn't exist"); + }); + }); + + describe('Update info', () => { + describe('Move a file from a folder to another folder', () => { + test('when replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), + fileInfo: JSON.stringify({ folder: data.folders[1].id }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[1].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.pdf', + ext: '.jpg', + mime: 'application/pdf', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: { id: data.folders[1].id }, + location: data.folders[1].location, + }); + data.files[1] = file; + }); + + test('without replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + fileInfo: JSON.stringify({ folder: data.folders[0].id }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[1].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.pdf', + ext: '.jpg', + mime: 'application/pdf', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: { id: data.folders[0].id }, + location: data.folders[0].location, + }); + data.files[1] = file; + }); + }); + describe('Move a file from root level to a folder', () => { + test('when replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[0].id}`, + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), + fileInfo: JSON.stringify({ folder: data.folders[0].id }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[0].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.pdf', + ext: '.jpg', + mime: 'application/pdf', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: { id: data.folders[0].id }, + location: data.folders[0].location, + }); + data.files[0] = file; + }); + + test('without replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + fileInfo: JSON.stringify({ folder: data.folders[1].id }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[1].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.pdf', + ext: '.jpg', + mime: 'application/pdf', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: { id: data.folders[1].id }, + location: data.folders[1].location, + }); + data.files[1] = file; + }); + }); + + describe('Move a file from folder to the root level', () => { + test('when replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[0].id}`, + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + fileInfo: JSON.stringify({ folder: null }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[0].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.jpg', + ext: '.jpg', + mime: 'image/jpeg', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: null, + location: '/', + }); + data.files[0] = file; + }); + + test('without replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + fileInfo: JSON.stringify({ folder: null }), + }, + }); + + expect(res.statusCode).toBe(200); + expect(res.body).toMatchObject({ id: data.files[1].id }); + + const { body: file } = await rq({ + method: 'GET', + url: `/upload/files/${res.body.id}`, + }); + + expect(file).toMatchObject({ + id: expect.anything(), + name: 'rec.pdf', + ext: '.jpg', + mime: 'application/pdf', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + folder: null, + location: '/', + }); + data.files[1] = file; + }); + }); + + describe("Cannot create a file inside a folder that doesn't exist", () => { + test('when replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + fileInfo: JSON.stringify({ + folder: '1234', // id that doesn't exist + }), + }, + }); + + expect(res.status).toBe(400); + expect(res.body.error.message).toBe("the folder doesn't exist"); + }); + + test('whithout replacing the file', async () => { + const res = await rq({ + method: 'POST', + url: `/upload?id=${data.files[1].id}`, + formData: { + fileInfo: JSON.stringify({ + folder: '1234', // id that doesn't exist + }), + }, + }); + + expect(res.status).toBe(400); + expect(res.body.error.message).toBe("the folder doesn't exist"); + }); + }); + }); +}); diff --git a/packages/core/upload/tests/admin/file-image.test.e2e.js b/packages/core/upload/tests/admin/file-image.test.e2e.js new file mode 100644 index 0000000000..ce02fd8c8d --- /dev/null +++ b/packages/core/upload/tests/admin/file-image.test.e2e.js @@ -0,0 +1,109 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +// Helpers. +const { createTestBuilder } = require('../../../../../test/helpers/builder'); +const { createStrapiInstance } = require('../../../../../test/helpers/strapi'); +const { createAuthRequest } = require('../../../../../test/helpers/request'); + +const builder = createTestBuilder(); +let strapi; +let rq; + +const dogModel = { + displayName: 'Dog', + singularName: 'dog', + pluralName: 'dogs', + kind: 'collectionType', + attributes: { + profilePicture: { + type: 'media', + }, + }, +}; + +describe('Upload', () => { + beforeAll(async () => { + await builder.addContentType(dogModel).build(); + strapi = await createStrapiInstance(); + rq = await createAuthRequest({ strapi }); + }); + + afterAll(async () => { + await strapi.destroy(); + await builder.cleanup(); + }); + + describe('POST /upload => Upload a file', () => { + test('Simple image upload', async () => { + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), + }, + }); + + expect(res.statusCode).toBe(200); + expect(Array.isArray(res.body)).toBe(true); + expect(res.body.length).toBe(1); + expect(res.body[0]).toEqual( + expect.objectContaining({ + id: expect.anything(), + name: 'rec.jpg', + ext: '.jpg', + mime: 'image/jpeg', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + }) + ); + }); + + test('Generates a thumbnail on large enough files', async () => { + const res = await rq({ + method: 'POST', + url: '/upload', + formData: { + files: fs.createReadStream(path.join(__dirname, '../utils/thumbnail_target.png')), + }, + }); + + expect(res.statusCode).toBe(200); + expect(Array.isArray(res.body)).toBe(true); + expect(res.body.length).toBe(1); + expect(res.body[0]).toEqual( + expect.objectContaining({ + id: expect.anything(), + name: 'thumbnail_target.png', + ext: '.png', + mime: 'image/png', + hash: expect.any(String), + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + provider: 'local', + formats: { + thumbnail: { + name: 'thumbnail_thumbnail_target.png', + hash: expect.any(String), + ext: '.png', + mime: 'image/png', + size: expect.any(Number), + width: expect.any(Number), + height: expect.any(Number), + url: expect.any(String), + path: null, + }, + }, + }) + ); + }); + }); +}); diff --git a/packages/core/upload/tests/admin/file.test.e2e.js b/packages/core/upload/tests/admin/file.test.e2e.js index 6c5ebd0772..eb2dd9975e 100644 --- a/packages/core/upload/tests/admin/file.test.e2e.js +++ b/packages/core/upload/tests/admin/file.test.e2e.js @@ -1,379 +1,62 @@ 'use strict'; -const fs = require('fs'); -const path = require('path'); - const { createTestBuilder } = require('../../../../../test/helpers/builder'); const { createStrapiInstance } = require('../../../../../test/helpers/strapi'); const { createAuthRequest } = require('../../../../../test/helpers/request'); +const builder = createTestBuilder(); let strapi; let rq; -let data = { - folders: [], - files: [], + +const dogModel = { + displayName: 'Dog', + singularName: 'dog', + pluralName: 'dogs', + kind: 'collectionType', + attributes: { + profilePicture: { + type: 'media', + }, + }, }; -describe('File', () => { - const builder = createTestBuilder(); - +describe('Upload', () => { beforeAll(async () => { + await builder.addContentType(dogModel).build(); strapi = await createStrapiInstance(); rq = await createAuthRequest({ strapi }); - - // create 2 folders - for (let i = 1; i <= 2; i += 1) { - const folderRes = await rq({ - method: 'POST', - url: '/upload/folders', - body: { name: `my folder ${i}` }, - }); - data.folders.push(folderRes.body.data); - } }); afterAll(async () => { - await rq({ - method: 'POST', - url: '/upload/folders/batch-delete', - body: { - ids: data.folders.map(f => f.id), - }, - }); - await strapi.destroy(); await builder.cleanup(); }); - describe('create', () => { - test('Can create a file at root level', async () => { - const res = await rq({ - method: 'POST', - url: '/upload', - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - }, - }); - - expect(res.statusCode).toBe(200); - expect(Array.isArray(res.body)).toBe(true); - expect(res.body.length).toBe(1); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body[0].id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.jpg', - ext: '.jpg', - mime: 'image/jpeg', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: null, - }); - - data.files.push(file); - }); - - test('Can create a file inside a folder', async () => { - const res = await rq({ - method: 'POST', - url: '/upload', - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - fileInfo: JSON.stringify({ - folder: data.folders[0].id, - }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(Array.isArray(res.body)).toBe(true); - expect(res.body.length).toBe(1); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body[0].id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.jpg', - ext: '.jpg', - mime: 'image/jpeg', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: { id: data.folders[0].id }, - }); - - data.files.push(file); - }); - - test("Cannot create a file inside a folder that doesn't exist", async () => { - const res = await rq({ - method: 'POST', - url: '/upload', - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - fileInfo: JSON.stringify({ - folder: '1234', // id that doesn't exist - }), - }, - }); - - expect(res.status).toBe(400); - expect(res.body.error.message).toBe("the folder doesn't exist"); + describe('Create', () => { + test('Rejects when no files are provided', async () => { + const res = await rq({ method: 'POST', url: '/upload', formData: {} }); + expect(res.statusCode).toBe(400); }); }); - describe('Update info', () => { - describe('Move a file from a folder to another folder', () => { - test('when replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - fileInfo: JSON.stringify({ folder: data.folders[1].id }), - }, - }); + describe('Read', () => { + test('GET /upload/files => Find files', async () => { + const getRes = await rq({ method: 'GET', url: '/upload/files' }); - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[1].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.pdf', - ext: '.jpg', - mime: 'application/pdf', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: { id: data.folders[1].id }, - }); - data.files[1] = file; - }); - - test('without replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - fileInfo: JSON.stringify({ folder: data.folders[0].id }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[1].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.pdf', - ext: '.jpg', - mime: 'application/pdf', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: { id: data.folders[0].id }, - }); - data.files[1] = file; - }); - }); - describe('Move a file from root level to a folder', () => { - test('when replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[0].id}`, - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), - fileInfo: JSON.stringify({ folder: data.folders[0].id }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[0].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.pdf', - ext: '.jpg', - mime: 'application/pdf', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: { id: data.folders[0].id }, - }); - data.files[0] = file; - }); - - test('without replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - fileInfo: JSON.stringify({ folder: data.folders[1].id }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[1].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.pdf', - ext: '.jpg', - mime: 'application/pdf', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: { id: data.folders[1].id }, - }); - data.files[1] = file; - }); - }); - - describe('Move a file from folder to the root level', () => { - test('when replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[0].id}`, - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - fileInfo: JSON.stringify({ folder: null }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[0].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.jpg', - ext: '.jpg', - mime: 'image/jpeg', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: null, - }); - data.files[0] = file; - }); - - test('without replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - fileInfo: JSON.stringify({ folder: null }), - }, - }); - - expect(res.statusCode).toBe(200); - expect(res.body).toMatchObject({ id: data.files[1].id }); - - const { body: file } = await rq({ - method: 'GET', - url: `/upload/files/${res.body.id}`, - }); - - expect(file).toMatchObject({ - id: expect.anything(), - name: 'rec.pdf', - ext: '.jpg', - mime: 'application/pdf', - hash: expect.any(String), - size: expect.any(Number), - width: expect.any(Number), - height: expect.any(Number), - url: expect.any(String), - provider: 'local', - folder: null, - }); - data.files[1] = file; - }); - }); - - describe("Cannot create a file inside a folder that doesn't exist", () => { - test('when replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), - fileInfo: JSON.stringify({ - folder: '1234', // id that doesn't exist - }), - }, - }); - - console.log('res.body', res.body); - expect(res.status).toBe(400); - expect(res.body.error.message).toBe("the folder doesn't exist"); - }); - - test('whithout replacing the file', async () => { - const res = await rq({ - method: 'POST', - url: `/upload?id=${data.files[1].id}`, - formData: { - fileInfo: JSON.stringify({ - folder: '1234', // id that doesn't exist - }), - }, - }); - - expect(res.status).toBe(400); - expect(res.body.error.message).toBe("the folder doesn't exist"); + expect(getRes.statusCode).toBe(200); + expect(getRes.body).toEqual({ + results: expect.arrayContaining([ + expect.objectContaining({ + id: expect.anything(), + url: expect.any(String), + }), + ]), + pagination: { + page: expect.any(Number), + pageSize: expect.any(Number), + pageCount: expect.any(Number), + total: expect.any(Number), + }, }); }); }); diff --git a/packages/core/upload/tests/admin/folder.test.e2e.js b/packages/core/upload/tests/admin/folder.test.e2e.js index ad6601b5d8..f15497891c 100644 --- a/packages/core/upload/tests/admin/folder.test.e2e.js +++ b/packages/core/upload/tests/admin/folder.test.e2e.js @@ -15,8 +15,8 @@ let data = { }; const uuidRegex = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; -const rootPathRegex = /^\/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; -const getFolderPathRegex = uid => +const rootLocationRegex = /^\/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i; +const getFolderLocationRegex = uid => new RegExp( '^/' + uid + '/[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$', 'i' @@ -51,12 +51,12 @@ describe('Folder', () => { id: expect.anything(), name: 'folder 1', uid: expect.stringMatching(uuidRegex), - path: expect.stringMatching(rootPathRegex), + location: expect.stringMatching(rootLocationRegex), createdAt: expect.anything(), updatedAt: expect.anything(), parent: null, }); - expect(res.body.data.uid).toBe(res.body.data.path.split('/').pop()); + expect(res.body.data.uid).toBe(res.body.data.location.split('/').pop()); data.folders.push(omit('parent', res.body.data)); }); @@ -75,12 +75,12 @@ describe('Folder', () => { id: expect.anything(), name: 'folder-2', uid: expect.stringMatching(uuidRegex), - path: expect.stringMatching(getFolderPathRegex(data.folders[0].uid)), + location: expect.stringMatching(getFolderLocationRegex(data.folders[0].uid)), createdAt: expect.anything(), updatedAt: expect.anything(), parent: data.folders[0], }); - expect(res.body.data.uid).toBe(res.body.data.path.split('/').pop()); + expect(res.body.data.uid).toBe(res.body.data.location.split('/').pop()); data.folders.push(omit('parent', res.body.data)); }); @@ -188,7 +188,10 @@ describe('Folder', () => { username: null, }, files: { count: 0 }, - parent: pick(['createdAt', 'id', 'name', 'path', 'uid', 'updatedAt'], data.folders[0]), + parent: pick( + ['createdAt', 'id', 'name', 'location', 'uid', 'updatedAt'], + data.folders[0] + ), updatedBy: { firstname: expect.anything(), id: expect.anything(), @@ -213,8 +216,8 @@ describe('Folder', () => { expect(res.body.data).toEqual( expect.arrayContaining([ - pick(['id', 'name', 'path', 'uid', 'updatedAt', 'createdAt'])(data.folders[0]), - pick(['id', 'name', 'path', 'uid', 'updatedAt', 'createdAt'])(data.folders[1]), + pick(['id', 'name', 'location', 'uid', 'updatedAt', 'createdAt'])(data.folders[0]), + pick(['id', 'name', 'location', 'uid', 'updatedAt', 'createdAt'])(data.folders[1]), ]) ); }); diff --git a/packages/core/upload/tests/admin/settings.test.e2e.js b/packages/core/upload/tests/admin/settings.test.e2e.js new file mode 100644 index 0000000000..6b4fcb68e7 --- /dev/null +++ b/packages/core/upload/tests/admin/settings.test.e2e.js @@ -0,0 +1,81 @@ +'use strict'; + +// Helpers. +const { createTestBuilder } = require('../../../../../test/helpers/builder'); +const { createStrapiInstance } = require('../../../../../test/helpers/strapi'); +const { createAuthRequest } = require('../../../../../test/helpers/request'); + +const builder = createTestBuilder(); +let strapi; +let rq; + +const dogModel = { + displayName: 'Dog', + singularName: 'dog', + pluralName: 'dogs', + kind: 'collectionType', + attributes: { + profilePicture: { + type: 'media', + }, + }, +}; + +describe('Settings', () => { + beforeAll(async () => { + await builder.addContentType(dogModel).build(); + strapi = await createStrapiInstance(); + rq = await createAuthRequest({ strapi }); + }); + + afterAll(async () => { + await strapi.destroy(); + await builder.cleanup(); + }); + + describe('GET /upload/settings => Get settings for an environment', () => { + test('Returns the settings', async () => { + const res = await rq({ method: 'GET', url: '/upload/settings' }); + + expect(res.statusCode).toBe(200); + expect(res.body).toEqual({ + data: { + autoOrientation: false, + sizeOptimization: true, + responsiveDimensions: true, + }, + }); + }); + }); + + describe('PUT /upload/settings/:environment', () => { + test('Updates an environment config correctly', async () => { + const updateRes = await rq({ + method: 'PUT', + url: '/upload/settings', + body: { + sizeOptimization: true, + responsiveDimensions: true, + }, + }); + + expect(updateRes.statusCode).toBe(200); + expect(updateRes.body).toEqual({ + data: { + sizeOptimization: true, + responsiveDimensions: true, + }, + }); + + const getRes = await rq({ method: 'GET', url: '/upload/settings' }); + + expect(getRes.statusCode).toBe(200); + expect(getRes.body).toEqual({ + data: { + sizeOptimization: true, + responsiveDimensions: true, + }, + }); + }); + }); +}); diff --git a/packages/core/upload/tests/content-api/upload.test.e2e.js b/packages/core/upload/tests/content-api/upload.test.e2e.js index 34380cf381..0a1fedd7bc 100644 --- a/packages/core/upload/tests/content-api/upload.test.e2e.js +++ b/packages/core/upload/tests/content-api/upload.test.e2e.js @@ -36,53 +36,7 @@ describe('Upload plugin end to end tests', () => { await builder.cleanup(); }); - describe('GET /upload/settings => Get settings for an environment', () => { - test('Returns the settings', async () => { - const res = await rq({ method: 'GET', url: '/upload/settings' }); - - expect(res.statusCode).toBe(200); - expect(res.body).toEqual({ - data: { - autoOrientation: false, - sizeOptimization: true, - responsiveDimensions: true, - }, - }); - }); - }); - - describe('PUT /upload/settings/:environment', () => { - test('Updates an environment config correctly', async () => { - const updateRes = await rq({ - method: 'PUT', - url: '/upload/settings', - body: { - sizeOptimization: true, - responsiveDimensions: true, - }, - }); - - expect(updateRes.statusCode).toBe(200); - expect(updateRes.body).toEqual({ - data: { - sizeOptimization: true, - responsiveDimensions: true, - }, - }); - - const getRes = await rq({ method: 'GET', url: '/upload/settings' }); - - expect(getRes.statusCode).toBe(200); - expect(getRes.body).toEqual({ - data: { - sizeOptimization: true, - responsiveDimensions: true, - }, - }); - }); - }); - - describe('POST /upload => Upload a file', () => { + describe('Create', () => { test('Simple image upload', async () => { const res = await rq({ method: 'POST', @@ -158,31 +112,27 @@ describe('Upload plugin end to end tests', () => { }); }); - test('GET /upload/files => Find files', async () => { - const getRes = await rq({ method: 'GET', url: '/upload/files' }); + describe('Read', () => { + test('Get files', async () => { + const getRes = await rq({ method: 'GET', url: '/upload/files' }); - expect(getRes.statusCode).toBe(200); - expect(getRes.body).toEqual({ - results: expect.arrayContaining([ - expect.objectContaining({ - id: expect.anything(), - url: expect.any(String), - }), - ]), - pagination: { - page: expect.any(Number), - pageSize: expect.any(Number), - pageCount: expect.any(Number), - total: expect.any(Number), - }, + expect(getRes.statusCode).toBe(200); + expect(getRes.body).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: expect.anything(), + url: expect.any(String), + }), + ]) + ); }); }); - describe('POST /api/:uid => Create an entity with a file', () => { + describe('Create an entity with a file', () => { test('With an image', async () => { const res = await rq({ method: 'POST', - url: '/api/dogs?populate=*', + url: '/dogs?populate=*', formData: { data: '{}', 'files.profilePicture': fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')), @@ -210,7 +160,7 @@ describe('Upload plugin end to end tests', () => { test('With a pdf', async () => { const res = await rq({ method: 'POST', - url: '/api/dogs?populate=*', + url: '/dogs?populate=*', formData: { data: '{}', 'files.profilePicture': fs.createReadStream(path.join(__dirname, '../utils/rec.pdf')), @@ -235,7 +185,4 @@ describe('Upload plugin end to end tests', () => { }); }); }); - test.todo('GET /upload/files/:id => Find one file'); - test.todo('GET /upload/search/:id => Search files'); - test.todo('DELETE /upload/files/:id => Delete a file'); });