strapi/tests/api/core/upload/admin/folder.test.api.js

521 lines
15 KiB
JavaScript
Raw Normal View History

'use strict';
2022-04-26 11:23:07 +02:00
const fs = require('fs');
const path = require('path');
2022-05-05 15:35:52 +02:00
const { pick, map } = require('lodash/fp');
const { createTestBuilder } = require('api-tests/builder');
const { createStrapiInstance } = require('api-tests/strapi');
const { createAuthRequest } = require('api-tests/request');
let strapi;
let rq;
2022-08-08 15:50:34 +02:00
const data = {
folders: [],
};
2022-06-03 16:21:52 +02:00
const rootPathRegex = /^\/[0-9]*$/i;
2022-08-08 23:33:39 +02:00
const getFolderPathRegex = (pathId) => new RegExp(`^/${pathId}/[0-9]*$`, 'i');
2022-04-05 17:36:09 +02:00
2022-04-26 11:23:07 +02:00
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];
};
feat(cm): D&P pt2 (#19380) * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * fix(cm): list view & build process * feat: save and publish * feat: update contract * feat: dp tests * chore: use document from create and update * feat: save and publish single types * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * fix(cm): list view & build process * feat: add publish & update action (#19423) * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * feat: add publish & update action * feat: add published disabled state * test: fix suite * test: add unit for Panels * fix(cm): status not state for redirect * fix(cm): list view status & component main field property * chore: pr feedback * chore: apply suggestions Co-authored-by: markkaylor <mark.kaylor@strapi.io> --------- Co-authored-by: Marc Roig <marc12info@gmail.com> Co-authored-by: markkaylor <mark.kaylor@strapi.io> * feat: test single types * feat: wrap single type publish into a transaction * feat(cm): add unpublish & delete actions, also re-enable single-types (#19459) * fix: delete url was wrong way round * feat: compute modified status * fix(cm): reimplement ListSettingsView (#19432) * chore: PR feedback * feat: discard endpoint * feat: discard draft api tests * feat: unpublish and discard * chore: pr comments * chore: update sanitizer * feat(cm): add publish and save (#19500) * feat(cm): add publish and save * test(cm): fix unit for useDocumentActions * Update packages/core/content-manager/server/src/controllers/collection-types.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * Update packages/core/content-manager/shared/contracts/single-types-v5.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * feat(document-service): map document ID to entry ID (#19248) * feat: use document service in content manager * feat: update contracts with meta information * chore: group metadata types into a single type * feat: metadata information in single types * chore: change meta contract to return documents instead of strings * fix: remove unused type * fix: ignore doc id if entry is null * fix: update contract metadata * feat: document metadata service * feat: locale and status filtering * chore: add comment * chore: refactor metadata service * chore: refactor entity manager exists to handle single types * feat: refactor single type controllers to use documents * feat: get locale param from in cm endpoints * Revert "feat: get locale param from in cm endpoints" This reverts commit 856c38588b8f8521cadd85c8c933f42a36a2178a. * feat: get locale param from cm endpoints * Update packages/plugins/i18n/server/src/controllers/validate-locale-creation.ts Co-authored-by: Ben Irvin <ben@innerdvations.com> * fix: entity manager unit tests * chore: unit test document metadata * feat: prevent empty string locale filtering * fix: cm contract import * chore: test new d&p cm features * fix: search content manager api test * fix: cm tests * fix: cm tests * fix: cm tests * fix(content-manager): access to non default locale documents (#19190) * fix(content-manager): access to non default locale documents * chore(content-manager): revert route construction * fix(content-manager): api tests for number of draft relations * test(content-manager): counting number of draft relations for non default locales * chore(content-manager): remove default locale from entity manager countDraftRelations * chore: basic relations testing for document service * chore(e2e): disable edit view tests (#19235) * feat: get relation ids * chore: clean functions into other folders * chore: rename files * fix: group document ids by its uid * feat: id mapper * chore: improve typings * chore: rename transform functions * fix: id-transform tests * chore: simplify function return value * chore: improve comments * fix: api tests * fix: single types unit test * fix: skip relations test * fix: exclude fields * fix: short hand ifs * fix: merge conflict * fix: transform output of find one * Update packages/core/core/src/services/document-service/transform/utils.ts Co-authored-by: Ben Irvin <ben.irvin@strapi.io> * feat[Document Service]: Param transformation (#19373) * fix(core): wip param transformation * feat(core): wip param transformation based on relational status * feat(core): wip populate and filter transformation based on relational status * chore(core): simplify fields and sort * chore(core): clean up * feat(core): wip filter transformation with traverseQueryFilters * feat(core): reorganise and PR feedback * fix(core): filters traversal logic * feat(core): populate relational transformations * chore(core): reintroduce populate transformation * fix(core): enforce that fields must include id * fix(core): enforce that fields must include id * fix(core): filter and sort transformation * chore(core): typos * chore(core): further filters test cases * feat(core): support object based sorts * chore(core): fields test naming * feat(core): handle logical operators in filters * fix: skip conditions test * fix(core): switchIdForDocumentId (#19497) * fix: uniqueness test * fix: available status should be an array * fix: available statuses * fix: skip uniqueness folder * fix: skip uniqueness test errors * fix: skip failing test --------- Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> Co-authored-by: Ben Irvin <ben.irvin@strapi.io> * chore: re-implement edit configuration (#19488) * chore: re-implement edit configuration * chore: cleanups * test: fix unit tests * feat(cm): add discard changes action (#19509) * feat(cm): add discard changes action * feat(cm): add discard when unpublishing * test(e2e): fix editview e2e * test(e2e): fix uniqueness partially * test(unit): fix unit tests for actions & add for discard * chore: bump playwright * fix(webkit): add shim for requestIdCallback * chore: pr amends * feat: return status on available locales * feat: add document-actions to list-view (#19523) * fix(cm): add gap and alignment for edit-view heading with super long names * fix(cm): list view status' * feat: add list-view actions * fix: conditions for actions to be enabled * fix: stay on draft tab when published * fix: stop propogation on list-view row click * test(e2e): fix editview tests * chore: update spelling error Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> --------- Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * feat: test document metadata * chore: remove unnecessary unit test * fix: return modified on published documents * chore: init split single-type collection-type in document service * Fix/fields test case (#19481) * Update packages/core/content-manager/server/src/services/document-metadata.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * fix: pretty * chore: refactor middlewares * feat: send empty object if locale does not exist on document * feat: single types * chore: add tests to middlewares * feat: update locale using query params (#19546) * feat: return available locales when not finding locale * chore: update typings * feat: add clone action (#19526) * feat: add clone action * test(e2e): add auto clone tests * chore: pr amends * feat: add information to header actions menu (#19548) * feat: add information to header actions menu * fix: dont use non-null-assertion * feat: manage relations on publish (#19427) --------- Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> * feat: v5 i18n relations (#19504) Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> * fix: locale test api * chore: refactor i18n (#19555) * chore: remove types package, should be using strapi * chore: refactor i18n settings page * feat: add i18n to CM * feat(i18n): add delete locale action (#19562) * chore: pr amends Co-authored-by: Simone <startae14@gmail.com> --------- Co-authored-by: Simone <startae14@gmail.com> * feat(cm): re-implement validation (#19578) * feat: re-implement validation in the CM feat: add blocker feat: handle validation errors from the API chore: reimplement useFieldHint test(unit): fix fe tests chore: fix bad logical operator * chore: await notifications to leave before trying to go to other pages * fix: validation issues & blocker showing up incorrectly * fix: broken publish behaviour * fix(content-manager): uid availability and generation (#19518) * fix(content-manager): uid availability and generation * fix(content-manager): pass locale as is from UID service * fix(content-manager): match UIDs based on startsWith --------- Co-authored-by: Marc Roig <marc12info@gmail.com> Co-authored-by: markkaylor <mark.kaylor@strapi.io> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> Co-authored-by: Ben Irvin <ben.irvin@strapi.io> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com> Co-authored-by: Alexandre BODIN <alexandrebodin@users.noreply.github.com> Co-authored-by: Simone <startae14@gmail.com>
2024-02-22 17:18:32 +00:00
describe.skip('Folder', () => {
const builder = createTestBuilder();
beforeAll(async () => {
strapi = await createStrapiInstance();
rq = await createAuthRequest({ strapi });
});
afterAll(async () => {
2022-04-07 18:00:21 +02:00
await rq({
method: 'POST',
2022-04-26 11:23:07 +02:00
url: '/upload/actions/bulk-delete',
2022-04-07 18:00:21 +02:00
body: {
2022-08-08 23:33:39 +02:00
folderIds: data.folders.map((f) => f.id),
2022-04-07 18:00:21 +02:00
},
});
await strapi.destroy();
await builder.cleanup();
});
describe('create', () => {
test('Can create a folder at root level', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name: 'folder 1',
parent: null,
},
});
expect(res.status).toBe(201);
expect(res.body.data).toMatchObject({
id: expect.anything(),
name: 'folder 1',
2022-06-03 16:21:52 +02:00
pathId: expect.any(Number),
2022-04-12 16:32:05 +02:00
path: expect.stringMatching(rootPathRegex),
createdAt: expect.anything(),
updatedAt: expect.anything(),
});
2022-06-03 16:21:52 +02:00
expect(res.body.data.pathId.toString()).toBe(res.body.data.path.split('/').pop());
2022-05-05 15:35:52 +02:00
data.folders.push(res.body.data);
});
test('Can create a folder inside another folder', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name: 'folder-2',
parent: data.folders[0].id,
},
});
expect(res.body.data).toMatchObject({
id: expect.anything(),
name: 'folder-2',
2022-06-03 16:21:52 +02:00
pathId: expect.any(Number),
path: expect.stringMatching(getFolderPathRegex(data.folders[0].pathId)),
createdAt: expect.anything(),
updatedAt: expect.anything(),
});
2022-06-03 16:21:52 +02:00
expect(res.body.data.pathId.toString()).toBe(res.body.data.path.split('/').pop());
2022-05-05 15:35:52 +02:00
data.folders.push(res.body.data);
});
test('Cannot create a folder with duplicated name at root level', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name: 'folder 1',
parent: null,
},
});
expect(res.status).toBe(400);
2022-05-13 16:10:18 +02:00
expect(res.body.error.message).toBe('A folder with this name already exists');
});
test('Cannot create a folder with duplicated name inside a folder', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name: 'folder-2',
2022-04-26 11:23:07 +02:00
parent: data.folders[0].id,
},
});
expect(res.status).toBe(400);
2022-05-13 16:10:18 +02:00
expect(res.body.error.message).toBe('A folder with this name already exists');
});
2022-04-26 11:23:07 +02:00
test('Cannot create a folder inside a folder that does not exist', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
2022-04-26 11:23:07 +02:00
body: {
name: 'folder-3',
parent: 99999,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('parent folder does not exist');
});
test('Cannot create a folder with name containing a slash', async () => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name: 'folder 1/2',
parent: null,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('name cannot contain slashes');
});
test.each([[' abc'], [' abc '], ['abc '], [' abc '], [' abc ']])(
'Cannot create a folder with name starting or ending with a whitespace (%p)',
2022-08-08 23:33:39 +02:00
async (name) => {
const res = await rq({
method: 'POST',
2022-05-05 15:35:52 +02:00
url: '/upload/folders',
body: {
name,
parent: null,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('name cannot start or end with a whitespace');
}
);
});
describe('read', () => {
2022-05-05 18:44:50 +02:00
test('Can read a folder', async () => {
const res = await rq({
method: 'GET',
url: `/upload/folders/${data.folders[0].id}`,
});
expect(res.body.data).toMatchObject({
2022-06-03 16:21:52 +02:00
...pick(['id', 'name', 'pathId', 'path', 'createAt', 'updatedAt'], data.folders[0]),
2022-05-05 18:44:50 +02:00
children: {
count: expect.anything(),
},
files: {
count: expect.anything(),
},
2022-06-14 15:54:45 +01:00
});
});
test('Can read a folder & populate its parent', async () => {
const res = await rq({
method: 'GET',
url: `/upload/folders/${data.folders[1].id}`,
qs: {
populate: 'parent',
},
});
expect(res.body.data).toMatchObject({
...pick(['id', 'name', 'pathId', 'path', 'createAt', 'updatedAt'], data.folders[1]),
parent: {
id: expect.any(Number),
},
2022-05-05 18:44:50 +02:00
});
});
test('Return 404 when folder does not exist', async () => {
const res = await rq({
method: 'GET',
url: '/upload/folders/99999',
});
expect(res.status).toBe(404);
});
test('Can read folders', async () => {
const res = await rq({
method: 'GET',
url: '/upload/folders',
});
2022-05-19 14:47:23 +02:00
expect(res.body.data).toEqual(
expect.arrayContaining([
{
2022-04-05 17:36:09 +02:00
...data.folders[0],
children: { count: 1 },
files: { count: 0 },
},
{
2022-04-05 17:36:09 +02:00
...data.folders[1],
children: { count: 0 },
2022-03-22 18:57:50 +01:00
files: { count: 0 },
},
])
);
});
});
2022-04-29 09:51:55 +02:00
describe('update', () => {
2022-05-19 14:09:54 +02:00
test('Return 404 when folder does not exist', async () => {
const res = await rq({
method: 'PUT',
url: '/upload/folders/99999',
body: {
name: 'new name',
},
});
expect(res.status).toBe(404);
});
test('Rename a folder', async () => {
2022-04-29 09:51:55 +02:00
const folder = await createFolder('folder-name', null);
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder.id}`,
body: {
feat(cm): D&P pt2 (#19380) * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * fix(cm): list view & build process * feat: save and publish * feat: update contract * feat: dp tests * chore: use document from create and update * feat: save and publish single types * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * fix(cm): list view & build process * feat: add publish & update action (#19423) * feat: return metadata on content manager endpoints (#19361) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * feat: fix cm metadata api tests (#19375) * feat: return metadata on content manager endpoints * feat: return meta * fix: cm tests * fix: admin test * chore(cm): refactor CM (#19341) * chore(cm): refactor EditView comes with a host of new re-usable APIs! * feat(cm): add useDocument hook * feat(cm): add useDocumentOperations hook * feat(cm): initialise EditView header * feat(cm): add useDocumentLayout hook * fix: listView from layout refactor * chore(cm): refactor editview form input renderer * chore: fix lint & ts * fix: re-add custom fields * test: fix admin/CM unit tests * docs(cm): add docs at a high level of how the CM works * test: add useDocumentRBAC tests * chore: pr amends * feat: add addEditViewSidePanel API to strapi (#19398) * feat: add addEditViewSidePanel API to strapi fix: don't pass all the query params to the create route * chore: pr amends * fix: return available status when content type doesnt have i18n enabled (#19419) * fix: return available status when content type doesnt have i18n enabled * chore: remove comment * feat: add publish & update action * feat: add published disabled state * test: fix suite * test: add unit for Panels * fix(cm): status not state for redirect * fix(cm): list view status & component main field property * chore: pr feedback * chore: apply suggestions Co-authored-by: markkaylor <mark.kaylor@strapi.io> --------- Co-authored-by: Marc Roig <marc12info@gmail.com> Co-authored-by: markkaylor <mark.kaylor@strapi.io> * feat: test single types * feat: wrap single type publish into a transaction * feat(cm): add unpublish & delete actions, also re-enable single-types (#19459) * fix: delete url was wrong way round * feat: compute modified status * fix(cm): reimplement ListSettingsView (#19432) * chore: PR feedback * feat: discard endpoint * feat: discard draft api tests * feat: unpublish and discard * chore: pr comments * chore: update sanitizer * feat(cm): add publish and save (#19500) * feat(cm): add publish and save * test(cm): fix unit for useDocumentActions * Update packages/core/content-manager/server/src/controllers/collection-types.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * Update packages/core/content-manager/shared/contracts/single-types-v5.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * feat(document-service): map document ID to entry ID (#19248) * feat: use document service in content manager * feat: update contracts with meta information * chore: group metadata types into a single type * feat: metadata information in single types * chore: change meta contract to return documents instead of strings * fix: remove unused type * fix: ignore doc id if entry is null * fix: update contract metadata * feat: document metadata service * feat: locale and status filtering * chore: add comment * chore: refactor metadata service * chore: refactor entity manager exists to handle single types * feat: refactor single type controllers to use documents * feat: get locale param from in cm endpoints * Revert "feat: get locale param from in cm endpoints" This reverts commit 856c38588b8f8521cadd85c8c933f42a36a2178a. * feat: get locale param from cm endpoints * Update packages/plugins/i18n/server/src/controllers/validate-locale-creation.ts Co-authored-by: Ben Irvin <ben@innerdvations.com> * fix: entity manager unit tests * chore: unit test document metadata * feat: prevent empty string locale filtering * fix: cm contract import * chore: test new d&p cm features * fix: search content manager api test * fix: cm tests * fix: cm tests * fix: cm tests * fix(content-manager): access to non default locale documents (#19190) * fix(content-manager): access to non default locale documents * chore(content-manager): revert route construction * fix(content-manager): api tests for number of draft relations * test(content-manager): counting number of draft relations for non default locales * chore(content-manager): remove default locale from entity manager countDraftRelations * chore: basic relations testing for document service * chore(e2e): disable edit view tests (#19235) * feat: get relation ids * chore: clean functions into other folders * chore: rename files * fix: group document ids by its uid * feat: id mapper * chore: improve typings * chore: rename transform functions * fix: id-transform tests * chore: simplify function return value * chore: improve comments * fix: api tests * fix: single types unit test * fix: skip relations test * fix: exclude fields * fix: short hand ifs * fix: merge conflict * fix: transform output of find one * Update packages/core/core/src/services/document-service/transform/utils.ts Co-authored-by: Ben Irvin <ben.irvin@strapi.io> * feat[Document Service]: Param transformation (#19373) * fix(core): wip param transformation * feat(core): wip param transformation based on relational status * feat(core): wip populate and filter transformation based on relational status * chore(core): simplify fields and sort * chore(core): clean up * feat(core): wip filter transformation with traverseQueryFilters * feat(core): reorganise and PR feedback * fix(core): filters traversal logic * feat(core): populate relational transformations * chore(core): reintroduce populate transformation * fix(core): enforce that fields must include id * fix(core): enforce that fields must include id * fix(core): filter and sort transformation * chore(core): typos * chore(core): further filters test cases * feat(core): support object based sorts * chore(core): fields test naming * feat(core): handle logical operators in filters * fix: skip conditions test * fix(core): switchIdForDocumentId (#19497) * fix: uniqueness test * fix: available status should be an array * fix: available statuses * fix: skip uniqueness folder * fix: skip uniqueness test errors * fix: skip failing test --------- Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> Co-authored-by: Ben Irvin <ben.irvin@strapi.io> * chore: re-implement edit configuration (#19488) * chore: re-implement edit configuration * chore: cleanups * test: fix unit tests * feat(cm): add discard changes action (#19509) * feat(cm): add discard changes action * feat(cm): add discard when unpublishing * test(e2e): fix editview e2e * test(e2e): fix uniqueness partially * test(unit): fix unit tests for actions & add for discard * chore: bump playwright * fix(webkit): add shim for requestIdCallback * chore: pr amends * feat: return status on available locales * feat: add document-actions to list-view (#19523) * fix(cm): add gap and alignment for edit-view heading with super long names * fix(cm): list view status' * feat: add list-view actions * fix: conditions for actions to be enabled * fix: stay on draft tab when published * fix: stop propogation on list-view row click * test(e2e): fix editview tests * chore: update spelling error Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> --------- Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * feat: test document metadata * chore: remove unnecessary unit test * fix: return modified on published documents * chore: init split single-type collection-type in document service * Fix/fields test case (#19481) * Update packages/core/content-manager/server/src/services/document-metadata.ts Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> * fix: pretty * chore: refactor middlewares * feat: send empty object if locale does not exist on document * feat: single types * chore: add tests to middlewares * feat: update locale using query params (#19546) * feat: return available locales when not finding locale * chore: update typings * feat: add clone action (#19526) * feat: add clone action * test(e2e): add auto clone tests * chore: pr amends * feat: add information to header actions menu (#19548) * feat: add information to header actions menu * fix: dont use non-null-assertion * feat: manage relations on publish (#19427) --------- Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> * feat: v5 i18n relations (#19504) Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Josh <37798644+joshuaellis@users.noreply.github.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> * fix: locale test api * chore: refactor i18n (#19555) * chore: remove types package, should be using strapi * chore: refactor i18n settings page * feat: add i18n to CM * feat(i18n): add delete locale action (#19562) * chore: pr amends Co-authored-by: Simone <startae14@gmail.com> --------- Co-authored-by: Simone <startae14@gmail.com> * feat(cm): re-implement validation (#19578) * feat: re-implement validation in the CM feat: add blocker feat: handle validation errors from the API chore: reimplement useFieldHint test(unit): fix fe tests chore: fix bad logical operator * chore: await notifications to leave before trying to go to other pages * fix: validation issues & blocker showing up incorrectly * fix: broken publish behaviour * fix(content-manager): uid availability and generation (#19518) * fix(content-manager): uid availability and generation * fix(content-manager): pass locale as is from UID service * fix(content-manager): match UIDs based on startsWith --------- Co-authored-by: Marc Roig <marc12info@gmail.com> Co-authored-by: markkaylor <mark.kaylor@strapi.io> Co-authored-by: Jamie Howard <48524071+jhoward1994@users.noreply.github.com> Co-authored-by: Ben Irvin <ben@innerdvations.com> Co-authored-by: Jamie Howard <jamie.howard@strapi.io> Co-authored-by: Ben Irvin <ben.irvin@strapi.io> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com> Co-authored-by: Alexandre BODIN <alexandrebodin@users.noreply.github.com> Co-authored-by: Simone <startae14@gmail.com>
2024-02-22 17:18:32 +00:00
name: 'new name folder',
2022-04-29 09:51:55 +02:00
},
});
expect(res.body.data).toMatchObject({
name: 'new name',
path: folder.path,
});
data.folders.push(res.body.data);
});
2022-05-19 14:09:54 +02:00
test('Cannot move and rename a folder if duplicated', async () => {
2022-04-29 09:51:55 +02:00
const folder0 = await createFolder('folder-a-0', null);
const folder1 = await createFolder('folder-a-1', null);
2022-05-02 10:35:48 +02:00
const folder00 = await createFolder('folder-a-00', folder0.id);
data.folders.push(folder0, folder1, folder00);
2022-04-29 09:51:55 +02:00
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder1.id}`,
body: {
name: 'folder-a-00',
parent: folder0.id,
},
});
expect(res.status).toBe(400);
2022-05-13 16:10:18 +02:00
expect(res.body.error.message).toBe('A folder with this name already exists');
2022-05-02 16:31:27 +02:00
});
2022-05-19 14:09:54 +02:00
test('Cannot move a folder if duplicated', async () => {
2022-05-02 16:31:27 +02:00
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);
2022-05-13 16:10:18 +02:00
expect(res.body.error.message).toBe('A folder with this name already exists');
2022-04-29 09:51:55 +02:00
});
2022-05-19 14:09:54 +02:00
test('Cannot move a folder to a folder that does not exist', async () => {
2022-05-02 16:31:27 +02:00
const folder = await createFolder('folder-c-0', null);
2022-05-02 10:35:48 +02:00
data.folders.push(folder);
2022-04-29 09:51:55 +02:00
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder.id}`,
body: {
parent: 9999,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('parent folder does not exist');
});
2022-05-19 14:09:54 +02:00
test('Cannot move a folder inside itself (0 level)', async () => {
2022-05-05 16:14:32 +02:00
const folder = await createFolder('folder-d-0', null);
data.folders.push(folder);
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder.id}`,
body: {
parent: folder.id,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('folder cannot be moved inside itself');
});
2022-05-19 14:09:54 +02:00
test('Cannot move a folder inside itself (1 level)', async () => {
2022-05-05 16:14:32 +02:00
const folder0 = await createFolder('folder-e-0', null);
const folder00 = await createFolder('folder-e-00', folder0.id);
data.folders.push(folder0, folder00);
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder0.id}`,
body: {
parent: folder00.id,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('folder cannot be moved inside itself');
});
2022-05-19 14:09:54 +02:00
test('Cannot move a folder inside itself (2 levels)', async () => {
2022-05-05 16:14:32 +02:00
const folder0 = await createFolder('folder-f-0', null);
const folder00 = await createFolder('folder-f-00', folder0.id);
const folder000 = await createFolder('folder-f-000', folder00.id);
data.folders.push(folder0, folder00, folder000);
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder0.id}`,
body: {
parent: folder000.id,
},
});
expect(res.status).toBe(400);
expect(res.body.error.message).toBe('folder cannot be moved inside itself');
});
2022-05-19 14:09:54 +02:00
test('Move a folder inside another folder', async () => {
2022-04-29 09:51:55 +02:00
const folder0 = await createFolder('folder-0', null);
const folder00 = await createFolder('folder-00', folder0.id);
const folder01 = await createFolder('folder-01', folder0.id);
const folder02 = await createFolder('folder-02', folder0.id);
const folder000 = await createFolder('folder-000', folder00.id);
const file000 = await createAFile(folder000.id);
const file02 = await createAFile(folder02.id);
// moving folder00 in folder01
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder00.id}`,
body: {
name: 'folder-00-new',
parent: folder01.id,
},
});
expect(res.body.data).toMatchObject({
name: 'folder-00-new',
2022-06-03 16:21:52 +02:00
path: `${folder01.path}/${folder00.pathId}`,
2022-04-29 09:51:55 +02:00
});
const resFolders = await rq({
method: 'GET',
url: '/upload/folders',
qs: {
filters: { id: { $in: map('id', [folder0, folder00, folder01, folder02, folder000]) } },
sort: 'id:asc',
2022-05-05 18:44:50 +02:00
populate: { parent: '*' },
2022-04-29 09:51:55 +02:00
},
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[0]).toMatchObject({ path: folder0.path, parent: null });
expect(resFolders.body.data[1]).toMatchObject({
2022-06-03 16:21:52 +02:00
path: `${folder01.path}/${folder00.pathId}`,
2022-04-29 09:51:55 +02:00
parent: { id: folder01.id },
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[2]).toMatchObject({
2022-04-29 09:51:55 +02:00
path: folder01.path,
parent: { id: folder0.id },
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[3]).toMatchObject({
2022-04-29 09:51:55 +02:00
path: folder02.path,
parent: { id: folder0.id },
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[4]).toMatchObject({
2022-06-03 16:21:52 +02:00
path: `${folder01.path}/${folder00.pathId}/${folder000.pathId}`,
2022-04-29 09:51:55 +02:00
parent: { id: folder00.id },
});
const resFiles = await rq({
method: 'GET',
url: '/upload/files',
qs: {
filters: { id: { $in: [file000.id, file02.id] } },
sort: 'id:asc',
},
});
expect(resFiles.body.results[0]).toMatchObject({
2022-06-03 16:21:52 +02:00
folderPath: `${folder01.path}/${folder00.pathId}/${folder000.pathId}`,
2022-04-29 09:51:55 +02:00
});
expect(resFiles.body.results[1]).toMatchObject({ folderPath: file02.folderPath });
2022-05-19 14:47:23 +02:00
data.folders.push(...resFolders.body.data);
2022-04-29 09:51:55 +02:00
});
2022-05-19 14:09:54 +02:00
test('Move a folder to root level', async () => {
2022-04-29 09:51:55 +02:00
const folder0 = await createFolder('folder-test-0', null);
const folder00 = await createFolder('folder-test-00', folder0.id);
const folder02 = await createFolder('folder-test-02', folder0.id);
const folder000 = await createFolder('folder-test-000', folder00.id);
const file000 = await createAFile(folder000.id);
const file02 = await createAFile(folder02.id);
// moving folder00 in folder01
const res = await rq({
method: 'PUT',
url: `/upload/folders/${folder00.id}`,
body: {
name: 'folder-test-00-new',
parent: null,
},
});
expect(res.body.data).toMatchObject({
name: 'folder-test-00-new',
2022-06-03 16:21:52 +02:00
path: `/${folder00.pathId}`,
2022-04-29 09:51:55 +02:00
});
const resFolders = await rq({
method: 'GET',
url: '/upload/folders',
qs: {
filters: { id: { $in: map('id', [folder0, folder00, folder02, folder000]) } },
sort: 'id:asc',
2022-05-05 18:44:50 +02:00
populate: { parent: '*' },
2022-04-29 09:51:55 +02:00
},
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[0]).toMatchObject({ path: folder0.path, parent: null });
expect(resFolders.body.data[1]).toMatchObject({
2022-06-03 16:21:52 +02:00
path: `/${folder00.pathId}`,
2022-04-29 09:51:55 +02:00
parent: null,
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[2]).toMatchObject({
2022-04-29 09:51:55 +02:00
path: folder02.path,
parent: { id: folder0.id },
});
2022-05-19 14:47:23 +02:00
expect(resFolders.body.data[3]).toMatchObject({
2022-06-03 16:21:52 +02:00
path: `/${folder00.pathId}/${folder000.pathId}`,
2022-04-29 09:51:55 +02:00
parent: { id: folder00.id },
});
const resFiles = await rq({
method: 'GET',
url: '/upload/files',
qs: {
filters: { id: { $in: [file000.id, file02.id] } },
sort: 'id:asc',
},
});
expect(resFiles.body.results[0]).toMatchObject({
2022-06-03 16:21:52 +02:00
folderPath: `/${folder00.pathId}/${folder000.pathId}`,
2022-04-29 09:51:55 +02:00
});
expect(resFiles.body.results[1]).toMatchObject({ folderPath: file02.folderPath });
2022-05-19 14:47:23 +02:00
data.folders.push(...resFolders.body.data);
2022-04-29 09:51:55 +02:00
});
});
});