Skip to content

Commit

Permalink
fix: ensure published records are updated accordingly (#4180)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrians5j authored Jun 27, 2024
1 parent 668d4d7 commit 251da99
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 22 deletions.
64 changes: 50 additions & 14 deletions packages/api-headless-cms-ddb-es/src/operations/entry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { createElasticsearchBody } from "./elasticsearch/body";
import { createLatestRecordType, createPublishedRecordType, createRecordType } from "./recordType";
import { StorageOperationsCmsModelPlugin } from "@webiny/api-headless-cms";
import { WriteRequest } from "@webiny/aws-sdk/client-dynamodb";
import { batchReadAll, BatchReadItem, put } from "@webiny/db-dynamodb";
import { batchReadAll, BatchReadItem } from "@webiny/db-dynamodb";
import { createTransformer } from "./transformations";
import { convertEntryKeysFromStorage } from "./transformations/convertEntryKeys";
import {
Expand Down Expand Up @@ -278,6 +278,18 @@ export const createEntriesStorageOperations = (
SK: createLatestSortKey()
};

const publishedKeys = {
PK: createPartitionKey({
id: entry.id,
locale: model.locale,
tenant: model.tenant
}),
SK: createPublishedSortKey()
};

// We'll need this flag below.
const isPublished = entry.status === "published";

const esLatestData = await transformer.getElasticsearchLatestEntryData();

const items = [
Expand All @@ -293,9 +305,16 @@ export const createEntriesStorageOperations = (
})
];

const { index } = configurations.es({
model
});
if (isPublished) {
items.push(
entity.putBatch({
...storageEntry,
TYPE: createPublishedRecordType(),
...publishedKeys
})
);
}

try {
await batchWriteAll({
table: entity.table,
Expand All @@ -315,17 +334,34 @@ export const createEntriesStorageOperations = (
}
);
}
/**
* Update the "latest" entry item in the Elasticsearch
*/

const { index: esIndex } = configurations.es({
model
});

const esItems: BatchWriteItem[] = [
esEntity.putBatch({
...latestKeys,
index: esIndex,
data: esLatestData
})
];

if (isPublished) {
const esPublishedData = await transformer.getElasticsearchPublishedEntryData();
esItems.push(
esEntity.putBatch({
...publishedKeys,
index: esIndex,
data: esPublishedData
})
);
}

try {
await put({
entity: esEntity,
item: {
...latestKeys,
index,
data: esLatestData
}
await batchWriteAll({
table: esEntity.table,
items: esItems
});
} catch (ex) {
throw new WebinyError(
Expand Down
16 changes: 16 additions & 0 deletions packages/api-headless-cms-ddb/src/operations/entry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export const createEntriesStorageOperations = (
* We need to:
* - create the main entry item
* - update the last entry item to a current one
* - update the published entry item to a current one (if the entry is published)
*/
const items = [
entity.putBatch({
Expand All @@ -266,6 +267,21 @@ export const createEntriesStorageOperations = (
GSI1_SK: createGSISortKey(storageEntry)
})
];

const isPublished = entry.status === "published";
if (isPublished) {
items.push(
entity.putBatch({
...storageEntry,
PK: partitionKey,
SK: createPublishedSortKey(),
TYPE: createPublishedType(),
GSI1_PK: createGSIPartitionKey(model, "P"),
GSI1_SK: createGSISortKey(storageEntry)
})
);
}

try {
await batchWriteAll({
table: entity.table,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { useTestModelHandler } from "~tests/testHelpers/useTestModelHandler";
import { identityA, identityB, identityC, identityD } from "./security/utils";

describe("Content entries - Entry Meta Fields Overrides", () => {
const { manage: managerIdentityA } = useTestModelHandler({
const { read: readIdentityA, manage: manageIdentityA } = useTestModelHandler({
identity: identityA
});

beforeEach(async () => {
await managerIdentityA.setup();
await manageIdentityA.setup();
});

test("users should be able to create and immediately publish an entry with custom publishing-related values", async () => {
// 1. Initially, all meta fields should be populated, except the "modified" ones.
const testDate = new Date("2020-01-01T00:00:00.000Z").toISOString();

const { data: rev } = await managerIdentityA.createTestEntry({
const { data: rev } = await manageIdentityA.createTestEntry({
data: {
status: "published",
revisionFirstPublishedOn: testDate,
Expand Down Expand Up @@ -50,7 +50,7 @@ describe("Content entries - Entry Meta Fields Overrides", () => {
const testDate2 = new Date("2021-01-01T00:00:00.000Z").toISOString();
const testDate3 = new Date("2022-01-01T00:00:00.000Z").toISOString();

const { data: rev } = await managerIdentityA.createTestEntry({
const { data: rev } = await manageIdentityA.createTestEntry({
data: {
status: "published",
revisionFirstPublishedOn: testDate1,
Expand All @@ -65,7 +65,7 @@ describe("Content entries - Entry Meta Fields Overrides", () => {
});

const { data: publishedRevWithCustomLastPublishedValues } =
await managerIdentityA.createTestEntryFrom({
await manageIdentityA.createTestEntryFrom({
revision: rev.id,
data: {
status: "published",
Expand Down Expand Up @@ -98,8 +98,8 @@ describe("Content entries - Entry Meta Fields Overrides", () => {
rev.revisionFirstPublishedOn
).toBeTrue();

const { data: publishedRevWithAllCustomValues } =
await managerIdentityA.createTestEntryFrom({
const { data: publishedRevWithAllCustomValues } = await manageIdentityA.createTestEntryFrom(
{
revision: publishedRevWithCustomLastPublishedValues.id,
data: {
status: "published",
Expand All @@ -112,7 +112,8 @@ describe("Content entries - Entry Meta Fields Overrides", () => {
firstPublishedBy: identityD,
lastPublishedBy: identityD
}
});
}
);

expect(publishedRevWithAllCustomValues).toMatchObject({
createdOn: expect.toBeDateString(),
Expand All @@ -128,5 +129,39 @@ describe("Content entries - Entry Meta Fields Overrides", () => {
firstPublishedBy: identityD,
lastPublishedBy: identityD
});

// Ensure that the new published revision is the one that is returned when listing or getting the entry.

// 1. Manage API.
const { data: getEntryManage } = await manageIdentityA.getTestEntry({
entryId: rev.entryId
});

expect(getEntryManage).toMatchObject({
meta: {
status: "published",
version: 3
}
});

const { data: listEntriesManage } = await manageIdentityA.listTestEntries();

expect(listEntriesManage).toMatchObject([
{
meta: {
status: "published",
version: 3
}
}
]);

// 2. Read API (here we can't get versions directly, so we're just inspecting the revision ID).
const { data: getEntryRead } = await readIdentityA.getTestEntry({
where: { entryId: rev.entryId }
});
expect(getEntryRead.id).toEndWith("#0003");

const { data: listEntriesRead } = await readIdentityA.listTestEntries();
expect(listEntriesRead[0].id).toEndWith("#0003");
});
});

0 comments on commit 251da99

Please sign in to comment.