Skip to content

Commit

Permalink
fix(app-headless-cms): ensure trash bin is empty before deleting cont…
Browse files Browse the repository at this point in the history
…ent model (#4212)
  • Loading branch information
leopuleo authored Aug 2, 2024
1 parent badd76f commit 1be8d8c
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ describe("content model test", () => {
updateContentModelMutation,
deleteContentModelMutation
} = useGraphQLHandler(manageHandlerOpts);
const { createCategory } = useCategoryManageHandler(manageHandlerOpts);
const { createCategory, deleteCategory } = useCategoryManageHandler(manageHandlerOpts);
const category = models.find(m => m.modelId === "category");
if (!category) {
throw new Error("Could not find model `category`.");
Expand Down Expand Up @@ -359,22 +359,70 @@ describe("content model test", () => {
}
});

const [response] = await deleteContentModelMutation({
// Let's try to delete the content model: it should fail because we still have entries for the selected content model.
const [deleteWithEntriesResponse] = await deleteContentModelMutation({
modelId: model.modelId
});

expect(response).toEqual({
expect(deleteWithEntriesResponse).toEqual({
data: {
deleteContentModel: {
data: null,
error: {
message: `Cannot delete content model "${model.modelId}" because there are existing entries.`,
code: "CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED",
data: null
data: {
model: expect.any(Object)
}
}
}
}
});

// Let's move the entry to the trash bin and try to delete the content model: it should fail.
await deleteCategory({
revision: createCategoryResponse.data.createCategory.data.entryId,
options: {
permanently: false
}
});
const [deleteWithEntriesInTrashResponse] = await deleteContentModelMutation({
modelId: model.modelId
});
expect(deleteWithEntriesInTrashResponse).toEqual({
data: {
deleteContentModel: {
data: null,
error: {
message: `Cannot delete content model "${model.modelId}" because there are existing entries in the trash.`,
code: "CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED",
data: {
model: expect.any(Object)
}
}
}
}
});

// Let's permanently delete the entry: it should be able to delete the content model.
await deleteCategory({
revision: createCategoryResponse.data.createCategory.data.entryId,
options: {
permanently: true
}
});

const [deleteWithoutEntriesResponse] = await deleteContentModelMutation({
modelId: model.modelId
});

expect(deleteWithoutEntriesResponse).toEqual({
data: {
deleteContentModel: {
data: true,
error: null
}
}
});
});

test("get existing content model", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ describe("model delete", () => {
data: null,
error: {
code: "CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED",
data: null,
data: {
model: expect.any(Object)
},
message: `Cannot delete content model "category" because there are existing entries.`
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/api-headless-cms/src/crud/contentModel.crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,7 @@ export const createModelsCrud = (params: CreateModelsCrudParams): CmsModelContex
});
assignModelBeforeDelete({
onModelBeforeDelete,
plugins: context.plugins,
storageOperations
context
});

/**
Expand Down
52 changes: 26 additions & 26 deletions packages/api-headless-cms/src/crud/contentModel/beforeDelete.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { Topic } from "@webiny/pubsub/types";
import { HeadlessCmsStorageOperations, OnModelBeforeDeleteTopicParams } from "~/types";
import { PluginsContainer } from "@webiny/plugins";
import { CmsContext, OnModelBeforeDeleteTopicParams } from "~/types";
import WebinyError from "@webiny/error";
import { CmsModelPlugin } from "~/plugins/CmsModelPlugin";

interface AssignBeforeModelDeleteParams {
onModelBeforeDelete: Topic<OnModelBeforeDeleteTopicParams>;
storageOperations: HeadlessCmsStorageOperations;
plugins: PluginsContainer;
context: CmsContext;
}
export const assignModelBeforeDelete = (params: AssignBeforeModelDeleteParams) => {
const { onModelBeforeDelete, storageOperations, plugins } = params;
const { onModelBeforeDelete, context } = params;

onModelBeforeDelete.subscribe(async params => {
const { model } = params;

const modelPlugin = plugins
const modelPlugin = context.plugins
.byType<CmsModelPlugin>(CmsModelPlugin.type)
.find(item => item.contentModel.modelId === model.modelId);

Expand All @@ -29,30 +27,32 @@ export const assignModelBeforeDelete = (params: AssignBeforeModelDeleteParams) =
);
}

let entries = [];
try {
const result = await storageOperations.entries.list(model, {
where: {
latest: true
},
limit: 1
});
entries = result.items;
const [latestEntries] = await context.cms.listLatestEntries(model, { limit: 1 });

if (latestEntries.length > 0) {
throw new WebinyError(
`Cannot delete content model "${model.modelId}" because there are existing entries.`,
"CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED"
);
}

const [deletedEntries] = await context.cms.listDeletedEntries(model, { limit: 1 });

if (deletedEntries.length > 0) {
throw new WebinyError(
`Cannot delete content model "${model.modelId}" because there are existing entries in the trash.`,
"CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED"
);
}
} catch (ex) {
throw new WebinyError(
"Could not retrieve a list of content entries from the model.",
"ENTRIES_ERROR",
{
error: ex,
throw WebinyError.from(ex, {
message: "Could not retrieve a list of content entries from the model.",
code: "ENTRIES_ERROR",
data: {
model
}
);
}
if (entries.length > 0) {
throw new WebinyError(
`Cannot delete content model "${model.modelId}" because there are existing entries.`,
"CONTENT_MODEL_BEFORE_DELETE_HOOK_FAILED"
);
});
}
});
};

0 comments on commit 1be8d8c

Please sign in to comment.