mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 08:52:26 +00:00
Merge pull request #16748 from strapi/feature/review-workflow-delete-route
This commit is contained in:
commit
88d5169528
@ -379,6 +379,12 @@ describe('Role CRUD End to End', () => {
|
|||||||
"displayName": "Create",
|
"displayName": "Create",
|
||||||
"subCategory": "options",
|
"subCategory": "options",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"action": "admin::review-workflows.delete",
|
||||||
|
"category": "review workflows",
|
||||||
|
"displayName": "Delete",
|
||||||
|
"subCategory": "options",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"action": "admin::review-workflows.read",
|
"action": "admin::review-workflows.read",
|
||||||
"category": "review workflows",
|
"category": "review workflows",
|
||||||
|
@ -54,6 +54,10 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteWorkflow = async (id) => {
|
||||||
|
return requests.admin.delete(`/admin/review-workflows/workflows/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
const getWorkflow = async (id) => {
|
const getWorkflow = async (id) => {
|
||||||
const { body } = await requests.admin.get(`/admin/review-workflows/workflows/${id}?populate=*`);
|
const { body } = await requests.admin.get(`/admin/review-workflows/workflows/${id}?populate=*`);
|
||||||
return body.data;
|
return body.data;
|
||||||
@ -106,7 +110,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
let workflow1, workflow2;
|
let workflow1, workflow2;
|
||||||
|
|
||||||
describe('Create workflow and assign content type', () => {
|
describe('Create workflow and assign content type', () => {
|
||||||
test('Can create and assign a content type', async () => {
|
test('It should create a workflow and assign a content type', async () => {
|
||||||
const res = await createWorkflow({ contentTypes: [productUID] });
|
const res = await createWorkflow({ contentTypes: [productUID] });
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
@ -114,7 +118,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
workflow1 = res.body.data;
|
workflow1 = res.body.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have the first stage', async () => {
|
test('All product entities should have the first stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -125,7 +129,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Create workflow and steal content type from another workflow', () => {
|
describe('Create workflow and steal content type from another workflow', () => {
|
||||||
test('Can create workflow stealing content type from another', async () => {
|
test('It should create workflow stealing content type from another', async () => {
|
||||||
const res = await createWorkflow({
|
const res = await createWorkflow({
|
||||||
contentTypes: [productUID],
|
contentTypes: [productUID],
|
||||||
stages: [{ name: 'Review' }],
|
stages: [{ name: 'Review' }],
|
||||||
@ -136,7 +140,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
workflow2 = res.body.data;
|
workflow2 = res.body.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have the new first stage', async () => {
|
test('All product entities should have the new first stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -145,13 +149,13 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Original workflow is updated', async () => {
|
test('Original workflow should be updated', async () => {
|
||||||
const workflow = await getWorkflow(workflow1.id);
|
const workflow = await getWorkflow(workflow1.id);
|
||||||
expect(workflow).toMatchObject({ contentTypes: [] });
|
expect(workflow).toMatchObject({ contentTypes: [] });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Can not create with invalid content type', async () => {
|
test("It shouldn't create a workflow with invalid content type", async () => {
|
||||||
const res = await createWorkflow({ contentTypes: ['someUID'] });
|
const res = await createWorkflow({ contentTypes: ['someUID'] });
|
||||||
expect(res.status).toBe(400);
|
expect(res.status).toBe(400);
|
||||||
});
|
});
|
||||||
@ -161,7 +165,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
let workflow1, workflow2;
|
let workflow1, workflow2;
|
||||||
|
|
||||||
describe('Basic update', () => {
|
describe('Basic update', () => {
|
||||||
test('Can assign a content type', async () => {
|
test('It should assign a content type', async () => {
|
||||||
workflow1 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
workflow1 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
||||||
|
|
||||||
const res = await updateWorkflow(workflow1.id, {
|
const res = await updateWorkflow(workflow1.id, {
|
||||||
@ -172,7 +176,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
expect(res.body.data).toMatchObject({ contentTypes: [productUID] });
|
expect(res.body.data).toMatchObject({ contentTypes: [productUID] });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have the first stage', async () => {
|
test('All product entities should have the first stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -184,14 +188,14 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
|
|
||||||
// Depends on the previous test
|
// Depends on the previous test
|
||||||
describe('Steal content type', () => {
|
describe('Steal content type', () => {
|
||||||
test('Can steal content type from another', async () => {
|
test('It should be able to steal a content type from another workflow', async () => {
|
||||||
workflow2 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
workflow2 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
||||||
const res = await updateWorkflow(workflow2.id, { contentTypes: [productUID] });
|
const res = await updateWorkflow(workflow2.id, { contentTypes: [productUID] });
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
expect(res.body.data).toMatchObject({ contentTypes: [productUID] });
|
expect(res.body.data).toMatchObject({ contentTypes: [productUID] });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have the new first stage', async () => {
|
test('All product entities should have the new first stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -200,7 +204,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Original workflow is updated', async () => {
|
test('Original workflow should be updated', async () => {
|
||||||
const workflow = await getWorkflow(workflow1.id);
|
const workflow = await getWorkflow(workflow1.id);
|
||||||
expect(workflow).toMatchObject({ contentTypes: [] });
|
expect(workflow).toMatchObject({ contentTypes: [] });
|
||||||
});
|
});
|
||||||
@ -208,13 +212,13 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
|
|
||||||
// Depends on the previous test
|
// Depends on the previous test
|
||||||
describe('Unassign content type', () => {
|
describe('Unassign content type', () => {
|
||||||
test('Can unassign content type', async () => {
|
test('It should unassign content type', async () => {
|
||||||
const res = await updateWorkflow(workflow2.id, { contentTypes: [] });
|
const res = await updateWorkflow(workflow2.id, { contentTypes: [] });
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
expect(res.body.data).toMatchObject({ contentTypes: [] });
|
expect(res.body.data).toMatchObject({ contentTypes: [] });
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have null stage', async () => {
|
test('All product entities should have null stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -225,7 +229,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Assign and update stages', () => {
|
describe('Assign and update stages', () => {
|
||||||
test('Can assign and update stages', async () => {
|
test('It should assign and update stages', async () => {
|
||||||
workflow1 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
workflow1 = await createWorkflow({ contentTypes: [] }).then((res) => res.body.data);
|
||||||
|
|
||||||
// Update stages
|
// Update stages
|
||||||
@ -241,7 +245,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('All product entities have the new first stage', async () => {
|
test('All product entities should have the new first stage', async () => {
|
||||||
const products = await findAll(productUID);
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
expect(products.results).toHaveLength(2);
|
expect(products.results).toHaveLength(2);
|
||||||
@ -253,9 +257,28 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Creating an entity in a review workflow content type', () => {
|
describe('Delete workflow', () => {
|
||||||
let workflow;
|
let workflow;
|
||||||
test('when content type is assigned to workflow, new entries should be added to the first stage of the default workflow', async () => {
|
test('It should delete the workflow', async () => {
|
||||||
|
workflow = await createWorkflow({ contentTypes: [productUID] }).then((res) => res.body.data);
|
||||||
|
|
||||||
|
const res = await deleteWorkflow(workflow.id);
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Depends on the previous test
|
||||||
|
test('All entities should have null stage', async () => {
|
||||||
|
const products = await findAll(productUID);
|
||||||
|
|
||||||
|
expect(products.results).toHaveLength(2);
|
||||||
|
for (const product of products.results) {
|
||||||
|
expect(product[ENTITY_STAGE_ATTRIBUTE]).toBeNull();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Creating entity assigned to a workflow', () => {
|
||||||
|
let workflow;
|
||||||
|
test('When content type is assigned to workflow, new entries should be added to the first stage of the default workflow', async () => {
|
||||||
// Create a workflow with product content type
|
// Create a workflow with product content type
|
||||||
workflow = await createWorkflow({ contentTypes: [productUID] }).then((res) => res.body.data);
|
workflow = await createWorkflow({ contentTypes: [productUID] }).then((res) => res.body.data);
|
||||||
|
|
||||||
@ -264,7 +287,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Depends on the previous test
|
// Depends on the previous test
|
||||||
test('when content type is not assigned to workflow, new entries should have a null stage', async () => {
|
test('When content type is not assigned to workflow, new entries should have a null stage', async () => {
|
||||||
// Unassign product content type from default workflow
|
// Unassign product content type from default workflow
|
||||||
await updateWorkflow(workflow.id, { contentTypes: [] });
|
await updateWorkflow(workflow.id, { contentTypes: [] });
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Create workflow', () => {
|
describe('Create workflow', () => {
|
||||||
test('You can not create a workflow without stages', async () => {
|
test('It should create a workflow without stages', async () => {
|
||||||
const res = await requests.admin.post('/admin/review-workflows/workflows', {
|
const res = await requests.admin.post('/admin/review-workflows/workflows', {
|
||||||
body: {
|
body: {
|
||||||
name: 'testWorkflow',
|
name: 'testWorkflow',
|
||||||
@ -193,7 +193,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
expect(res.body.data).toBeUndefined();
|
expect(res.body.data).toBeUndefined();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
test('You can create a workflow with stages', async () => {
|
test('It should create a workflow with stages', async () => {
|
||||||
const res = await requests.admin.post('/admin/review-workflows/workflows?populate=stages', {
|
const res = await requests.admin.post('/admin/review-workflows/workflows?populate=stages', {
|
||||||
body: {
|
body: {
|
||||||
name: 'createdWorkflow',
|
name: 'createdWorkflow',
|
||||||
@ -217,7 +217,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Update workflow', () => {
|
describe('Update workflow', () => {
|
||||||
test('You can update a workflow', async () => {
|
test('It should update a workflow', async () => {
|
||||||
const res = await requests.admin.put(
|
const res = await requests.admin.put(
|
||||||
`/admin/review-workflows/workflows/${createdWorkflow.id}`,
|
`/admin/review-workflows/workflows/${createdWorkflow.id}`,
|
||||||
{ body: { name: 'updatedWorkflow' } }
|
{ body: { name: 'updatedWorkflow' } }
|
||||||
@ -232,7 +232,7 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('You can update a workflow with stages', async () => {
|
test('It should update a workflow with stages', async () => {
|
||||||
const res = await requests.admin.put(
|
const res = await requests.admin.put(
|
||||||
`/admin/review-workflows/workflows/${createdWorkflow.id}?populate=stages`,
|
`/admin/review-workflows/workflows/${createdWorkflow.id}?populate=stages`,
|
||||||
{
|
{
|
||||||
@ -262,6 +262,27 @@ describeOnCondition(edition === 'EE')('Review workflows', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Delete workflow', () => {
|
||||||
|
test('It should delete a workflow', async () => {
|
||||||
|
const createdRes = await requests.admin.post('/admin/review-workflows/workflows', {
|
||||||
|
body: { name: 'testWorkflow', stages: [{ name: 'Stage 1' }] },
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await requests.admin.delete(
|
||||||
|
`/admin/review-workflows/workflows/${createdRes.body.data.id}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
expect(res.body.data).toMatchObject({ name: 'testWorkflow' });
|
||||||
|
});
|
||||||
|
test("It shouldn't delete a workflow that does not exist", async () => {
|
||||||
|
const res = await requests.admin.delete(`/admin/review-workflows/workflows/123456789`);
|
||||||
|
|
||||||
|
expect(res.status).toBe(404);
|
||||||
|
expect(res.body.data).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Get workflow stages', () => {
|
describe('Get workflow stages', () => {
|
||||||
test("It shouldn't be available for public", async () => {
|
test("It shouldn't be available for public", async () => {
|
||||||
const res = await requests.public.get(
|
const res = await requests.public.get(
|
||||||
|
@ -46,6 +46,14 @@ module.exports = {
|
|||||||
category: 'review workflows',
|
category: 'review workflows',
|
||||||
subCategory: 'options',
|
subCategory: 'options',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
uid: 'review-workflows.delete',
|
||||||
|
displayName: 'Delete',
|
||||||
|
pluginName: 'admin',
|
||||||
|
section: 'settings',
|
||||||
|
category: 'review workflows',
|
||||||
|
subCategory: 'options',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
uid: 'review-workflows.read',
|
uid: 'review-workflows.read',
|
||||||
displayName: 'Read',
|
displayName: 'Read',
|
||||||
|
@ -50,6 +50,27 @@ module.exports = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a workflow
|
||||||
|
* @param {import('koa').BaseContext} ctx - koa context
|
||||||
|
*/
|
||||||
|
async delete(ctx) {
|
||||||
|
const { id } = ctx.params;
|
||||||
|
const { populate } = ctx.query;
|
||||||
|
const workflowService = getService('workflows');
|
||||||
|
|
||||||
|
const workflow = await workflowService.findById(id, { populate: ['stages'] });
|
||||||
|
if (!workflow) {
|
||||||
|
return ctx.notFound("Workflow doesn't exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await workflowService.delete(workflow, { populate });
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all workflows
|
* List all workflows
|
||||||
* @param {import('koa').BaseContext} ctx - koa context
|
* @param {import('koa').BaseContext} ctx - koa context
|
||||||
|
@ -40,6 +40,23 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: 'DELETE',
|
||||||
|
path: '/review-workflows/workflows/:id',
|
||||||
|
handler: 'workflows.delete',
|
||||||
|
config: {
|
||||||
|
middlewares: [enableFeatureMiddleware('review-workflows')],
|
||||||
|
policies: [
|
||||||
|
'admin::isAuthenticatedAdmin',
|
||||||
|
{
|
||||||
|
name: 'admin::hasPermissions',
|
||||||
|
config: {
|
||||||
|
actions: ['admin::review-workflows.delete'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/review-workflows/workflows',
|
path: '/review-workflows/workflows',
|
||||||
|
@ -60,6 +60,12 @@ module.exports = ({ strapi }) => {
|
|||||||
return stage;
|
return stage;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async deleteMany(stagesId) {
|
||||||
|
return strapi.entityService.deleteMany(STAGE_MODEL_UID, {
|
||||||
|
filters: { id: { $in: stagesId } },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
count() {
|
count() {
|
||||||
return strapi.entityService.count(STAGE_MODEL_UID);
|
return strapi.entityService.count(STAGE_MODEL_UID);
|
||||||
},
|
},
|
||||||
|
@ -122,6 +122,36 @@ module.exports = ({ strapi }) => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an existing workflow.
|
||||||
|
* Also deletes all the workflow stages and migrate all assigned the content types.
|
||||||
|
* @param {*} workflow
|
||||||
|
* @param {*} opts
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async delete(workflow, opts) {
|
||||||
|
const stageService = getService('stages', { strapi });
|
||||||
|
|
||||||
|
const workflowCount = await this.count();
|
||||||
|
|
||||||
|
if (workflowCount <= 1) {
|
||||||
|
throw new ApplicationError('Can not delete the last workflow');
|
||||||
|
}
|
||||||
|
|
||||||
|
return strapi.db.transaction(async () => {
|
||||||
|
// Delete stages
|
||||||
|
await stageService.deleteMany(workflow.stages.map((stage) => stage.id));
|
||||||
|
|
||||||
|
// Unassign all content types, this will migrate the content types to null
|
||||||
|
await workflowsContentTypes.migrate({
|
||||||
|
srcContentTypes: workflow.contentTypes,
|
||||||
|
destContentTypes: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete Workflow
|
||||||
|
return strapi.entityService.delete(WORKFLOW_MODEL_UID, workflow.id, opts);
|
||||||
|
});
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Returns the total count of workflows.
|
* Returns the total count of workflows.
|
||||||
* @returns {Promise<number>} - Total count of workflows.
|
* @returns {Promise<number>} - Total count of workflows.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user