mirror of
https://github.com/strapi/strapi.git
synced 2025-11-02 19:04:38 +00:00
add bulk move route
This commit is contained in:
parent
352d16a47f
commit
34372daf8b
@ -1,11 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
const { getService } = require('../utils');
|
||||
const { validateDeleteManyFoldersFiles } = require('./validation/admin/folder-file');
|
||||
const { ACTIONS } = require('../constants');
|
||||
const {
|
||||
validateDeleteManyFoldersFiles,
|
||||
validateMoveManyFoldersFiles,
|
||||
} = require('./validation/admin/folder-file');
|
||||
|
||||
const folderModel = 'plugin::upload.folder';
|
||||
const fileModel = 'plugin::upload.file';
|
||||
|
||||
module.exports = {
|
||||
async deleteMany(ctx) {
|
||||
const { body } = ctx.request;
|
||||
const {
|
||||
state: { userAbility },
|
||||
} = ctx;
|
||||
|
||||
const pmFolder = strapi.admin.services.permission.createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: folderModel,
|
||||
});
|
||||
|
||||
const pmFile = strapi.admin.services.permission.createPermissionsManager({
|
||||
ability: userAbility,
|
||||
action: ACTIONS.read,
|
||||
model: fileModel,
|
||||
});
|
||||
|
||||
await validateDeleteManyFoldersFiles(body);
|
||||
|
||||
@ -17,8 +38,55 @@ module.exports = {
|
||||
|
||||
ctx.body = {
|
||||
data: {
|
||||
files: deletedFiles,
|
||||
folders: deletedFolders,
|
||||
files: await pmFile.sanitizeOutput(deletedFiles),
|
||||
folders: await pmFolder.sanitizeOutput(deletedFolders),
|
||||
},
|
||||
};
|
||||
},
|
||||
async moveMany(ctx) {
|
||||
const { body } = ctx.request;
|
||||
const {
|
||||
state: { userAbility, user },
|
||||
} = ctx;
|
||||
|
||||
const pmFolder = strapi.admin.services.permission.createPermissionsManager({
|
||||
ability: ctx.state.userAbility,
|
||||
model: folderModel,
|
||||
});
|
||||
|
||||
const pmFile = strapi.admin.services.permission.createPermissionsManager({
|
||||
ability: userAbility,
|
||||
action: ACTIONS.read,
|
||||
model: fileModel,
|
||||
});
|
||||
|
||||
await validateMoveManyFoldersFiles(body);
|
||||
const { folderIds = [], fileIds = [], destinationFolderId } = body;
|
||||
|
||||
const uploadService = getService('upload');
|
||||
const folderService = getService('folder');
|
||||
|
||||
const updatedFolders = [];
|
||||
// updates are done in order (not in parallele) to avoid mixing queries (path)
|
||||
for (let folderId of folderIds) {
|
||||
const updatedFolder = await folderService.update(
|
||||
folderId,
|
||||
{ parent: destinationFolderId },
|
||||
{ user }
|
||||
);
|
||||
updatedFolders.push(updatedFolder);
|
||||
}
|
||||
|
||||
const updatedFiles = await Promise.all(
|
||||
fileIds.map(fileId =>
|
||||
uploadService.updateFileInfo(fileId, { folder: destinationFolderId }, { user })
|
||||
)
|
||||
);
|
||||
|
||||
ctx.body = {
|
||||
data: {
|
||||
files: await pmFile.sanitizeOutput(updatedFiles),
|
||||
folders: await pmFolder.sanitizeOutput(updatedFolders),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -72,7 +72,7 @@ module.exports = {
|
||||
model: folderModel,
|
||||
});
|
||||
|
||||
await validateUpdateFolder(body);
|
||||
await validateUpdateFolder(id)(body);
|
||||
|
||||
const { update } = getService('folder');
|
||||
|
||||
|
||||
@ -1,22 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
const { intersection, map, isEmpty } = require('lodash/fp');
|
||||
const { yup, validateYupSchema } = require('@strapi/utils');
|
||||
const { folderExists } = require('./utils');
|
||||
|
||||
const folderModel = 'plugin::upload.folder';
|
||||
|
||||
const validateDeleteManyFoldersFilesSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
fileIds: yup
|
||||
.array()
|
||||
.min(1)
|
||||
.of(yup.strapiID().required()),
|
||||
folderIds: yup
|
||||
.array()
|
||||
.min(1)
|
||||
.of(yup.strapiID().required()),
|
||||
fileIds: yup.array().of(yup.strapiID().required()),
|
||||
folderIds: yup.array().of(yup.strapiID().required()),
|
||||
})
|
||||
.noUnknown()
|
||||
.required();
|
||||
|
||||
const validateStructureMoveManyFoldersFilesSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
destinationFolderId: yup
|
||||
.strapiID()
|
||||
.nullable()
|
||||
.test('folder-exists', 'destination folder does not exist', folderExists),
|
||||
fileIds: yup.array().of(yup.strapiID().required()),
|
||||
folderIds: yup.array().of(yup.strapiID().required()),
|
||||
})
|
||||
.noUnknown()
|
||||
.required();
|
||||
|
||||
const validateDuplicatesMoveManyFoldersFilesSchema = yup
|
||||
.object()
|
||||
.test('are-folders-unique', 'some folders already exist', async function(value) {
|
||||
const { folderIds, destinationFolderId } = value;
|
||||
if (isEmpty(folderIds)) return true;
|
||||
|
||||
const folders = await strapi.entityService.findMany(folderModel, {
|
||||
fields: ['name'],
|
||||
filters: { id: { $in: folderIds } },
|
||||
});
|
||||
// TODO: handle when parent is null
|
||||
const existingFolders = await strapi.entityService.findMany(folderModel, {
|
||||
fields: ['name'],
|
||||
filters: { parent: { id: destinationFolderId } },
|
||||
});
|
||||
const duplicatedNames = intersection(map('name', folders), map('name', existingFolders));
|
||||
if (duplicatedNames.length > 0) {
|
||||
return this.createError({
|
||||
message: `some folders already exists: ${duplicatedNames.join(', ')}`,
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const validateMoveFoldersNotInsideThemselvesSchema = yup
|
||||
.object()
|
||||
.test('dont-move-inside-self', 'folders cannot be moved inside themselves', async function(
|
||||
value
|
||||
) {
|
||||
const { folderIds, destinationFolderId } = value;
|
||||
if (destinationFolderId === null || isEmpty(folderIds)) return true;
|
||||
|
||||
const destinationFolder = await strapi.entityService.findOne(folderModel, destinationFolderId, {
|
||||
fields: ['path'],
|
||||
});
|
||||
const folders = await strapi.entityService.findMany(folderModel, {
|
||||
fields: ['name', 'path'],
|
||||
filters: { id: { $in: folderIds } },
|
||||
});
|
||||
|
||||
const unmovableFoldersNames = folders
|
||||
.filter(folder => destinationFolder.path.startsWith(folder.path))
|
||||
.map(f => f.name);
|
||||
if (unmovableFoldersNames.length > 0) {
|
||||
return this.createError({
|
||||
message: `folders cannot be moved inside themselves: ${unmovableFoldersNames.join(', ')}`,
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
validateDeleteManyFoldersFiles: validateYupSchema(validateDeleteManyFoldersFilesSchema),
|
||||
async validateMoveManyFoldersFiles(body) {
|
||||
await validateYupSchema(validateStructureMoveManyFoldersFilesSchema)(body);
|
||||
await validateYupSchema(validateDuplicatesMoveManyFoldersFilesSchema)(body);
|
||||
await validateYupSchema(validateMoveFoldersNotInsideThemselvesSchema)(body);
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,25 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const { isUndefined, get } = require('lodash/fp');
|
||||
const { yup, validateYupSchema } = require('@strapi/utils');
|
||||
const { isNil } = require('lodash/fp');
|
||||
const { getService } = require('../../../utils');
|
||||
const { folderExists } = require('./utils');
|
||||
|
||||
const folderModel = 'plugin::upload.folder';
|
||||
const NO_SLASH_REGEX = /^[^/]+$/;
|
||||
const NO_SPACES_AROUND = /^(?! ).+(?<! )$/;
|
||||
|
||||
const folderExists = async folderId => {
|
||||
if (isNil(folderId)) {
|
||||
return true;
|
||||
const isNameUniqueInFolder = (id) => async function(name) {
|
||||
const { exists } = getService('folder');
|
||||
const filters = { name, parent: this.parent.parent || null };
|
||||
if (id) {
|
||||
filters.id = { $ne: id };
|
||||
|
||||
if (isUndefined(name)) {
|
||||
const existingFolder = await strapi.entityService.findOne(folderModel, id);
|
||||
filters.name = get('name', existingFolder);
|
||||
}
|
||||
}
|
||||
|
||||
const exists = await getService('folder').exists({ id: folderId });
|
||||
|
||||
return exists;
|
||||
};
|
||||
|
||||
const isNameUniqueInFolder = async function(name) {
|
||||
const { exists } = getService('folder');
|
||||
const doesExist = await exists({ parent: this.parent.parent || null, name });
|
||||
const doesExist = await exists(filters);
|
||||
return !doesExist;
|
||||
}
|
||||
|
||||
@ -32,7 +34,7 @@ const validateCreateFolderSchema = yup
|
||||
.matches(NO_SLASH_REGEX, 'name cannot contain slashes')
|
||||
.matches(NO_SPACES_AROUND, 'name cannot start or end with a whitespace')
|
||||
.required()
|
||||
.test('is-folder-unique', 'name already taken', isNameUniqueInFolder),
|
||||
.test('is-folder-unique', 'folder already exists', isNameUniqueInFolder()),
|
||||
parent: yup
|
||||
.strapiID()
|
||||
.nullable()
|
||||
@ -41,7 +43,8 @@ const validateCreateFolderSchema = yup
|
||||
.noUnknown()
|
||||
.required();
|
||||
|
||||
const validateUpdateFolderSchema = yup
|
||||
const validateUpdateFolderSchema = id =>
|
||||
yup
|
||||
.object()
|
||||
.shape({
|
||||
name: yup
|
||||
@ -49,7 +52,7 @@ const validateUpdateFolderSchema = yup
|
||||
.min(1)
|
||||
.matches(NO_SLASH_REGEX, 'name cannot contain slashes')
|
||||
.matches(NO_SPACES_AROUND, 'name cannot start or end with a whitespace')
|
||||
.test('is-folder-unique', 'name already taken', isNameUniqueInFolder),
|
||||
.test('is-folder-unique', 'folder already exists', isNameUniqueInFolder(id)),
|
||||
parent: yup
|
||||
.strapiID()
|
||||
.nullable()
|
||||
@ -60,5 +63,5 @@ const validateUpdateFolderSchema = yup
|
||||
|
||||
module.exports = {
|
||||
validateCreateFolder: validateYupSchema(validateCreateFolderSchema),
|
||||
validateUpdateFolder: validateYupSchema(validateUpdateFolderSchema),
|
||||
validateUpdateFolder: id => validateYupSchema(validateUpdateFolderSchema(id)),
|
||||
};
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const { isNil } = require('lodash/fp');
|
||||
const { getService } = require('../../../utils');
|
||||
|
||||
const folderExists = async folderId => {
|
||||
if (isNil(folderId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const exists = await getService('folder').exists({ id: folderId });
|
||||
|
||||
return exists;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
folderExists,
|
||||
};
|
||||
@ -171,5 +171,21 @@ module.exports = {
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
path: '/actions/bulk-move',
|
||||
handler: 'admin-folder-file.moveMany',
|
||||
config: {
|
||||
policies: [
|
||||
'admin::isAuthenticatedAdmin',
|
||||
{
|
||||
name: 'admin::hasPermissions',
|
||||
config: {
|
||||
actions: ['plugin::upload.read'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
433
packages/core/upload/tests/admin/folder-file.test.e2e.js
Normal file
433
packages/core/upload/tests/admin/folder-file.test.e2e.js
Normal file
@ -0,0 +1,433 @@
|
||||
'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: [],
|
||||
};
|
||||
|
||||
const createFolder = async (name, parent = null) => {
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/folders',
|
||||
body: { name, parent },
|
||||
});
|
||||
return res.body.data;
|
||||
};
|
||||
|
||||
const createAFile = async (parent = null) => {
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload',
|
||||
formData: {
|
||||
files: fs.createReadStream(path.join(__dirname, '../utils/rec.jpg')),
|
||||
fileInfo: JSON.stringify({ folder: parent }),
|
||||
},
|
||||
});
|
||||
return res.body[0];
|
||||
};
|
||||
|
||||
describe('Bulk actions fot folders & files', () => {
|
||||
const builder = createTestBuilder();
|
||||
|
||||
beforeAll(async () => {
|
||||
strapi = await createStrapiInstance();
|
||||
rq = await createAuthRequest({ strapi });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-delete',
|
||||
body: {
|
||||
folderIds: data.folders.map(f => f.id),
|
||||
},
|
||||
});
|
||||
|
||||
await strapi.destroy();
|
||||
await builder.cleanup();
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
test('Can delete folders and files', async () => {
|
||||
const folder1 = await createFolder('folder-a-1', null);
|
||||
const folder1a = await createFolder('folder-a-1a', folder1.id);
|
||||
const folder1b = await createFolder('folder-a-1b', folder1.id);
|
||||
const folder1a1 = await createFolder('folder-a-1a1', folder1a.id);
|
||||
const file1 = await createAFile(null);
|
||||
const file1b = await createAFile(folder1b.id);
|
||||
const file1a = await createAFile(folder1a.id);
|
||||
const file1a1 = await createAFile(folder1a1.id);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-delete',
|
||||
body: {
|
||||
fileIds: [file1.id],
|
||||
folderIds: [folder1a.id],
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.body.data).toMatchObject({
|
||||
files: [
|
||||
{
|
||||
alternativeText: null,
|
||||
caption: null,
|
||||
createdAt: expect.anything(),
|
||||
ext: '.jpg',
|
||||
folderPath: '/',
|
||||
formats: null,
|
||||
hash: expect.anything(),
|
||||
height: 20,
|
||||
id: file1.id,
|
||||
mime: 'image/jpeg',
|
||||
name: 'rec.jpg',
|
||||
previewUrl: null,
|
||||
provider: 'local',
|
||||
provider_metadata: null,
|
||||
size: 0.27,
|
||||
updatedAt: expect.anything(),
|
||||
url: expect.anything(),
|
||||
width: 20,
|
||||
},
|
||||
],
|
||||
folders: [
|
||||
{
|
||||
id: folder1a.id,
|
||||
name: 'folder-a-1a',
|
||||
path: expect.anything(),
|
||||
uid: expect.anything(),
|
||||
createdAt: expect.anything(),
|
||||
updatedAt: expect.anything(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const resFolder = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/folders?pagination[pageSize]=100',
|
||||
});
|
||||
|
||||
const existingfoldersIds = resFolder.body.results.map(f => f.id);
|
||||
expect(existingfoldersIds).toEqual(expect.not.arrayContaining([folder1a.id, folder1a1.id]));
|
||||
expect(existingfoldersIds).toEqual(expect.arrayContaining([folder1.id, folder1b.id]));
|
||||
|
||||
const resFiles = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/files',
|
||||
qs: {
|
||||
pageSize: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const existingfilesIds = resFiles.body.results.map(f => f.id);
|
||||
expect(existingfilesIds).toEqual(
|
||||
expect.not.arrayContaining([file1.id, file1a.id, file1a1.id])
|
||||
);
|
||||
expect(existingfilesIds).toEqual(expect.arrayContaining([file1b.id]));
|
||||
|
||||
data.folders.push(folder1, folder1b);
|
||||
data.files.push(file1b);
|
||||
});
|
||||
});
|
||||
|
||||
describe('move', () => {
|
||||
test('Can move folders and files into another folder', async () => {
|
||||
const folder1 = await createFolder('folder-b-1', null);
|
||||
const folder1a = await createFolder('folder-b-1a', folder1.id);
|
||||
const folder1b = await createFolder('folder-b-1b', folder1.id);
|
||||
const folder1a1 = await createFolder('folder-b-1a1', folder1a.id);
|
||||
const file1 = await createAFile(null);
|
||||
const file1a = await createAFile(folder1a.id);
|
||||
const file1b = await createAFile(folder1b.id);
|
||||
const file1a1 = await createAFile(folder1a1.id);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: folder1b.id,
|
||||
fileIds: [file1a.id],
|
||||
folderIds: [folder1a.id],
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.body.data).toMatchObject({
|
||||
files: [
|
||||
{
|
||||
alternativeText: null,
|
||||
caption: null,
|
||||
createdAt: expect.anything(),
|
||||
ext: '.jpg',
|
||||
folderPath: folder1b.path,
|
||||
formats: null,
|
||||
hash: expect.anything(),
|
||||
height: 20,
|
||||
id: file1a.id,
|
||||
mime: 'image/jpeg',
|
||||
name: 'rec.jpg',
|
||||
previewUrl: null,
|
||||
provider: 'local',
|
||||
provider_metadata: null,
|
||||
size: 0.27,
|
||||
updatedAt: expect.anything(),
|
||||
url: expect.anything(),
|
||||
width: 20,
|
||||
},
|
||||
],
|
||||
folders: [
|
||||
{
|
||||
id: folder1a.id,
|
||||
name: 'folder-b-1a',
|
||||
path: `${folder1b.path}/${folder1a.uid}`,
|
||||
uid: expect.anything(),
|
||||
createdAt: expect.anything(),
|
||||
updatedAt: expect.anything(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const {
|
||||
body: { results: folderResults },
|
||||
} = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/folders?pagination[pageSize]=100&populate=parent',
|
||||
qs: {
|
||||
pagination: { pageSize: 100 },
|
||||
populate: 'parent',
|
||||
sort: 'id:asc',
|
||||
filters: { id: { $in: [folder1.id, folder1a.id, folder1b.id, folder1a1.id] } },
|
||||
},
|
||||
});
|
||||
|
||||
expect(folderResults[0]).toMatchObject({ ...folder1, parent: null });
|
||||
expect(folderResults[1]).toMatchObject({
|
||||
...folder1a,
|
||||
path: `${folder1b.path}/${folder1a.uid}`,
|
||||
parent: { id: folder1b.id },
|
||||
updatedAt: expect.anything(),
|
||||
});
|
||||
expect(folderResults[2]).toMatchObject({ ...folder1b, parent: { id: folder1.id } });
|
||||
expect(folderResults[3]).toMatchObject({
|
||||
...folder1a1,
|
||||
path: `${folder1b.path}/${folder1a.uid}/${folder1a1.uid}`,
|
||||
parent: { id: folder1a.id },
|
||||
});
|
||||
|
||||
const {
|
||||
body: { results: fileResults },
|
||||
} = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/files',
|
||||
qs: {
|
||||
pageSize: 100,
|
||||
populate: 'folder',
|
||||
sort: 'id:asc',
|
||||
filters: { id: { $in: [file1.id, file1a.id, file1b.id, file1a1.id] } },
|
||||
},
|
||||
});
|
||||
|
||||
expect(fileResults[0]).toMatchObject({ ...file1, folder: null });
|
||||
expect(fileResults[1]).toMatchObject({
|
||||
...file1a,
|
||||
folderPath: folder1b.path,
|
||||
folder: { id: folder1b.id },
|
||||
updatedAt: expect.anything(),
|
||||
});
|
||||
expect(fileResults[2]).toMatchObject({ ...file1b, folder: { id: folder1b.id } });
|
||||
expect(fileResults[3]).toMatchObject({
|
||||
...file1a1,
|
||||
folderPath: `${folder1b.path}/${folder1a.uid}/${folder1a1.uid}`,
|
||||
folder: { id: folder1a1.id },
|
||||
});
|
||||
|
||||
data.folders.push(...folderResults);
|
||||
data.files.push(...fileResults);
|
||||
});
|
||||
test('Can move folders and files to the root level', async () => {
|
||||
const folder1 = await createFolder('folder-c-1', null);
|
||||
const folder1a = await createFolder('folder-c-1a', folder1.id);
|
||||
const folder1a1 = await createFolder('folder-c-1a1', folder1a.id);
|
||||
const file1 = await createAFile(null);
|
||||
const file1a = await createAFile(folder1a.id);
|
||||
const file1a1 = await createAFile(folder1a1.id);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: null,
|
||||
fileIds: [file1a.id],
|
||||
folderIds: [folder1a.id],
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.body.data).toMatchObject({
|
||||
files: [
|
||||
{
|
||||
alternativeText: null,
|
||||
caption: null,
|
||||
createdAt: expect.anything(),
|
||||
ext: '.jpg',
|
||||
folderPath: '/',
|
||||
formats: null,
|
||||
hash: expect.anything(),
|
||||
height: 20,
|
||||
id: file1a.id,
|
||||
mime: 'image/jpeg',
|
||||
name: 'rec.jpg',
|
||||
previewUrl: null,
|
||||
provider: 'local',
|
||||
provider_metadata: null,
|
||||
size: 0.27,
|
||||
updatedAt: expect.anything(),
|
||||
url: expect.anything(),
|
||||
width: 20,
|
||||
},
|
||||
],
|
||||
folders: [
|
||||
{
|
||||
id: folder1a.id,
|
||||
name: 'folder-c-1a',
|
||||
path: `/${folder1a.uid}`,
|
||||
uid: expect.anything(),
|
||||
createdAt: expect.anything(),
|
||||
updatedAt: expect.anything(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const {
|
||||
body: { results: folderResults },
|
||||
} = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/folders?pagination[pageSize]=100&populate=parent',
|
||||
qs: {
|
||||
pagination: { pageSize: 100 },
|
||||
populate: 'parent',
|
||||
sort: 'id:asc',
|
||||
filters: { id: { $in: [folder1.id, folder1a.id, folder1a1.id] } },
|
||||
},
|
||||
});
|
||||
|
||||
expect(folderResults[0]).toMatchObject({ ...folder1, parent: null });
|
||||
expect(folderResults[1]).toMatchObject({
|
||||
...folder1a,
|
||||
path: `/${folder1a.uid}`,
|
||||
parent: null,
|
||||
updatedAt: expect.anything(),
|
||||
});
|
||||
expect(folderResults[2]).toMatchObject({
|
||||
...folder1a1,
|
||||
path: `/${folder1a.uid}/${folder1a1.uid}`,
|
||||
parent: { id: folder1a.id },
|
||||
});
|
||||
|
||||
const {
|
||||
body: { results: fileResults },
|
||||
} = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/files',
|
||||
qs: {
|
||||
pageSize: 100,
|
||||
populate: 'folder',
|
||||
sort: 'id:asc',
|
||||
filters: { id: { $in: [file1.id, file1a.id, file1a1.id] } },
|
||||
},
|
||||
});
|
||||
|
||||
expect(fileResults[0]).toMatchObject({ ...file1, folder: null });
|
||||
expect(fileResults[1]).toMatchObject({
|
||||
...file1a,
|
||||
folderPath: '/',
|
||||
folder: null,
|
||||
updatedAt: expect.anything(),
|
||||
});
|
||||
expect(fileResults[2]).toMatchObject({
|
||||
...file1a1,
|
||||
folderPath: `/${folder1a.uid}/${folder1a1.uid}`,
|
||||
folder: { id: folder1a1.id },
|
||||
});
|
||||
|
||||
data.folders.push(...folderResults);
|
||||
data.files.push(...fileResults);
|
||||
});
|
||||
|
||||
test('Cannot move a folder inside itself (0 level)', async () => {
|
||||
const folder1 = await createFolder('folder-d-1', null);
|
||||
data.folders.push(folder1);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: folder1.id,
|
||||
folderIds: [folder1.id],
|
||||
},
|
||||
});
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('folders cannot be moved inside themselves: folder-d-1');
|
||||
});
|
||||
|
||||
test('Cannot move a folder inside itself (1 level)', async () => {
|
||||
const folder1 = await createFolder('folder-e-1', null);
|
||||
const folder1a = await createFolder('folder-e-1a', folder1.id);
|
||||
data.folders.push(folder1, folder1a);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: folder1a.id,
|
||||
folderIds: [folder1.id],
|
||||
},
|
||||
});
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('folders cannot be moved inside themselves: folder-e-1');
|
||||
});
|
||||
|
||||
test('Cannot move a folder inside itself (2 levels)', async () => {
|
||||
const folder1 = await createFolder('folder-f-1', null);
|
||||
const folder1a = await createFolder('folder-f-1a', folder1.id);
|
||||
const folder1a1 = await createFolder('folder-f-1a1', folder1a.id);
|
||||
data.folders.push(folder1, folder1a, folder1a1);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: folder1a1.id,
|
||||
folderIds: [folder1.id],
|
||||
},
|
||||
});
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('folders cannot be moved inside themselves: folder-f-1');
|
||||
});
|
||||
|
||||
test('Cannot move a folder if it creates a duplicate', async () => {
|
||||
const folder1 = await createFolder('folder-g-1', null);
|
||||
const folder1a = await createFolder('folder-g-1a', folder1.id);
|
||||
const folder2 = await createFolder('folder-g-1a', null);
|
||||
data.folders.push(folder1, folder1a, folder2);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-move',
|
||||
body: {
|
||||
destinationFolderId: folder1.id,
|
||||
folderIds: [folder2.id],
|
||||
},
|
||||
});
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('some folders already exists: folder-g-1a');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -126,7 +126,7 @@ describe('Folder', () => {
|
||||
});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('name already taken');
|
||||
expect(res.body.error.message).toBe('folder already exists');
|
||||
});
|
||||
|
||||
test('Cannot create a folder with duplicated name inside a folder', async () => {
|
||||
@ -140,7 +140,7 @@ describe('Folder', () => {
|
||||
});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('name already taken');
|
||||
expect(res.body.error.message).toBe('folder already exists');
|
||||
});
|
||||
|
||||
test('Cannot create a folder inside a folder that does not exist', async () => {
|
||||
@ -245,88 +245,6 @@ describe('Folder', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('delete', () => {
|
||||
test('Can delete folders and belonging files', async () => {
|
||||
const folder1 = await createFolder('folder1', null);
|
||||
const folder1a = await createFolder('folder1a', folder1.id);
|
||||
const folder1b = await createFolder('folder1b', folder1.id);
|
||||
const folder1a1 = await createFolder('folder1a1', folder1a.id);
|
||||
const file1 = await createAFile(null);
|
||||
const file1b = await createAFile(folder1b.id);
|
||||
const file1a = await createAFile(folder1a.id);
|
||||
const file1a1 = await createAFile(folder1a1.id);
|
||||
|
||||
const res = await rq({
|
||||
method: 'POST',
|
||||
url: '/upload/actions/bulk-delete',
|
||||
body: {
|
||||
fileIds: [file1.id],
|
||||
folderIds: [folder1a.id],
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.body.data).toMatchObject({
|
||||
files: [
|
||||
{
|
||||
alternativeText: null,
|
||||
caption: null,
|
||||
createdAt: expect.anything(),
|
||||
ext: '.jpg',
|
||||
folderPath: '/',
|
||||
formats: null,
|
||||
hash: expect.anything(),
|
||||
height: 20,
|
||||
id: file1.id,
|
||||
mime: 'image/jpeg',
|
||||
name: 'rec.jpg',
|
||||
previewUrl: null,
|
||||
provider: 'local',
|
||||
provider_metadata: null,
|
||||
size: 0.27,
|
||||
updatedAt: expect.anything(),
|
||||
url: expect.anything(),
|
||||
width: 20,
|
||||
},
|
||||
],
|
||||
folders: [
|
||||
{
|
||||
id: folder1a.id,
|
||||
name: 'folder1a',
|
||||
path: expect.anything(),
|
||||
uid: expect.anything(),
|
||||
createdAt: expect.anything(),
|
||||
updatedAt: expect.anything(),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const resFolder = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/folders?pagination[pageSize]=100',
|
||||
});
|
||||
|
||||
const existingfoldersIds = resFolder.body.results.map(f => f.id);
|
||||
expect(existingfoldersIds).toEqual(expect.not.arrayContaining([folder1a.id, folder1a1.id]));
|
||||
expect(existingfoldersIds).toEqual(expect.arrayContaining([folder1.id, folder1b.id]));
|
||||
|
||||
const resFiles = await rq({
|
||||
method: 'GET',
|
||||
url: '/upload/files',
|
||||
qs: {
|
||||
pageSize: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const existingfilesIds = resFiles.body.results.map(f => f.id);
|
||||
expect(existingfilesIds).toEqual(
|
||||
expect.not.arrayContaining([file1.id, file1a.id, file1a1.id])
|
||||
);
|
||||
expect(existingfilesIds).toEqual(expect.arrayContaining([file1b.id]));
|
||||
|
||||
data.folders.push(folder1, folder1b);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', () => {
|
||||
test('rename a folder', async () => {
|
||||
const folder = await createFolder('folder-name', null);
|
||||
@ -346,7 +264,7 @@ describe('Folder', () => {
|
||||
data.folders.push(res.body.data);
|
||||
});
|
||||
|
||||
test('cannot rename a folder if duplicated', async () => {
|
||||
test('cannot move and rename a folder if duplicated', async () => {
|
||||
const folder0 = await createFolder('folder-a-0', null);
|
||||
const folder1 = await createFolder('folder-a-1', null);
|
||||
const folder00 = await createFolder('folder-a-00', folder0.id);
|
||||
@ -362,11 +280,29 @@ describe('Folder', () => {
|
||||
});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('name already taken');
|
||||
expect(res.body.error.message).toBe('folder already exists');
|
||||
});
|
||||
|
||||
test('cannot move a folder if duplicated', async () => {
|
||||
const folder0 = await createFolder('folder-b-0', null);
|
||||
const folder1 = await createFolder('folder-b-samename', null);
|
||||
await createFolder('folder-b-samename', folder0.id);
|
||||
data.folders.push(folder0, folder1);
|
||||
|
||||
const res = await rq({
|
||||
method: 'PUT',
|
||||
url: `/upload/folders/${folder1.id}`,
|
||||
body: {
|
||||
parent: folder0.id,
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.status).toBe(400);
|
||||
expect(res.body.error.message).toBe('folder already exists');
|
||||
});
|
||||
|
||||
test('cannot move a folder to a folder that does not exist', async () => {
|
||||
const folder = await createFolder('folder-b-0', null);
|
||||
const folder = await createFolder('folder-c-0', null);
|
||||
data.folders.push(folder);
|
||||
|
||||
const res = await rq({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user