Skip to content

Commit 9653901

Browse files
committed
feat(server): remove references to unpublished content
1 parent dcdf009 commit 9653901

File tree

5 files changed

+105
-18
lines changed

5 files changed

+105
-18
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"testserver:ci": "npm --prefix demo run testserver:ci",
3030
"e2e": "npm run build:test-client && with-server --run=testserver:ci npm run cypress -- -- ",
3131
"cypress": "cypress run --config=baseUrl=$SERVER_URL",
32-
"e2e:dev": "with-server --run=testserver npm run cypress:dev",
32+
"e2e:dev": "npm run build:test-client && with-server --run=testserver:ci npm run cypress:dev",
3333
"cypress:dev": "cypress open --config=baseUrl=$SERVER_URL",
3434
"create-test-seeds": "./scripts/createSeeds.js ./cypress/support/knexfile.js"
3535
},

src/content/convert.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,18 @@ import {
77
PreviewOpts,
88
ContentFormat
99
} from "../../typings";
10-
import visit from "../model/visit";
10+
import visit, { NO_STORE_VALUE } from "../model/visit";
1111
import formatQuillDelta from "./formatQuillDelta";
1212
import getRefUrl from "./getRefUrl";
1313

1414
/**
1515
* Converts a content from its internal representation to a format
1616
* requested by the client.
17-
*
18-
* NOTE: Currently `richtext` is the only type that gets converted.
19-
* This could also be a good place to convert `media` ids to full URLs.
2017
*/
2118

2219
type ConvertProps = {
2320
content: Data;
24-
contentRefs?: ContentRefs;
21+
contentRefs: ContentRefs;
2522
contentModel: Model;
2623
allModels: Model[];
2724
contentFormat: ContentFormat;
@@ -106,24 +103,35 @@ export default function convert({
106103
_content: ref.model
107104
};
108105

106+
// Refs can only contain an id but no model,
107+
// this means the ref is not actually a ref but a string
109108
const isAbsoluteRef = !ref.model;
110-
111109
if (isAbsoluteRef) {
112110
convertedRef._url = ref.id;
113111
return convertedRef;
114112
}
115113

116-
// For external data sources content references don't exist
117-
if (!contentRefs || !contentRefs[ref.model]) return convertedRef;
118-
119-
const refModel = allModels.find(
114+
const referencedModel = allModels.find(
120115
m => m.name.toLowerCase() === ref.model.toLowerCase()
121116
);
122-
if (!refModel || !refModel.urlPath) return convertedRef;
117+
118+
// For external data sources content references don't exist
119+
if (referencedModel!.external) return convertedRef;
120+
121+
// No content for the ref was provided,
122+
// this means the referenced content does not exists anymore.
123+
// This happens when content get deleted or is scheduled
124+
if (!referencedModel || !contentRefs[ref.model]) return NO_STORE_VALUE;
125+
126+
// If the referenced content has no `urlPath`,
127+
// we don't need to add the `_url`
128+
if (!referencedModel.urlPath) return convertedRef;
123129

124130
const allRefData = contentRefs[ref.model][ref.id];
125-
const url = getRefUrl((allRefData || {}).data, refModel.urlPath);
126-
convertedRef._url = url;
131+
convertedRef._url = getRefUrl(
132+
(allRefData || {}).data,
133+
referencedModel.urlPath
134+
);
127135

128136
return convertedRef;
129137
}

src/content/rest/__tests__/apiHelper.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,30 @@ export function createApiWriteHelpers(
145145

146146
return body;
147147
};
148-
return { create, update };
148+
149+
const schedule = async (
150+
type: string,
151+
id: string,
152+
data: {
153+
visibleFrom?: Date | string | null;
154+
visibleUntil?: Date | string | null;
155+
}
156+
) => {
157+
const { body } = await server
158+
.post(`/admin/rest/content/${type}/${id}/schedule`)
159+
.set(headers)
160+
.send(data)
161+
.expect(204);
162+
163+
return body;
164+
};
165+
166+
const publish = async (type: string, id: string) =>
167+
server
168+
.post(`/admin/rest/content/${type}/${id}/publish`)
169+
.set(headers)
170+
.send({ rev: 1 })
171+
.expect(204);
172+
173+
return { create, update, schedule, publish };
149174
}

src/content/rest/__tests__/joins.test.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ describe("joins", () => {
4343
let headers: object;
4444
let find: ReturnType<typeof createApiReadHelpers>["find"];
4545
let create: ReturnType<typeof createApiWriteHelpers>["create"];
46+
let schedule: ReturnType<typeof createApiWriteHelpers>["schedule"];
47+
let publish: ReturnType<typeof createApiWriteHelpers>["publish"];
4648

4749
let a: any;
4850
let b: any;
@@ -73,7 +75,7 @@ describe("joins", () => {
7375
));
7476

7577
({ find } = createApiReadHelpers(server));
76-
({ create } = createApiWriteHelpers(server, headers));
78+
({ create, schedule, publish } = createApiWriteHelpers(server, headers));
7779

7880
c = await create(modelC.name, {
7981
title: faker.lorem.slug()
@@ -180,4 +182,56 @@ describe("joins", () => {
180182
}
181183
});
182184
});
185+
186+
it("should not include expired refs", async () => {
187+
await publish(modelC.name, c.id);
188+
await publish(modelB.name, b.id);
189+
await publish(modelA.name, a.id);
190+
191+
await schedule(modelC.name, c.id, {
192+
visibleUntil: new Date(Date.now() - 1)
193+
});
194+
195+
const resp1 = await find(
196+
modelA.name,
197+
a.id,
198+
{ join: { B: ["refC"] } },
199+
true
200+
);
201+
202+
await expect(resp1).toStrictEqual({
203+
...expectedResponse,
204+
_refs: {
205+
...expectedResponse._refs,
206+
content: {
207+
[modelB.name]: {
208+
[b.id]: {
209+
_id: b.id,
210+
_type: modelB.name
211+
}
212+
}
213+
}
214+
}
215+
});
216+
217+
await schedule(modelB.name, b.id, {
218+
visibleUntil: new Date(Date.now() - 1)
219+
});
220+
221+
const resp2 = await find(
222+
modelA.name,
223+
a.id,
224+
{ join: { B: ["refC"] } },
225+
true
226+
);
227+
228+
await expect(resp2).toStrictEqual({
229+
_id: a.id,
230+
title: expectedResponse.title,
231+
_refs: {
232+
media: {},
233+
content: {}
234+
}
235+
});
236+
});
183237
});

src/model/visit.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as Cotype from "../../typings";
44
*/
55
import _ from "lodash";
66

7-
export const NO_STORE_VALUE = Symbol("NoStore");
7+
export const NO_STORE_VALUE = Symbol();
88

99
type Visitor = {
1010
[key: string]: (
@@ -79,7 +79,7 @@ export default function visit(
7979
);
8080
if (typeof ret !== "undefined") {
8181
if (parent && key) {
82-
if (typeof ret === "string" && ret === NO_STORE_VALUE) {
82+
if (ret === NO_STORE_VALUE) {
8383
return _.set(parent, key, undefined);
8484
}
8585
_.set(parent, key, ret);

0 commit comments

Comments
 (0)