openvibers/openvibe.blog Commits
An edit that does not send citations keeps them: the /write editor does not resend a post's citations, so every edit made there dropped them from the new revision. Sending a list (even an empty one) still replaces them. lifecycle test
Changes
@@@ -293,7 +293,12 @@ function createPosts({ store, blogs, publication, access, outbox, log = console});revision = out.revision;created = out.created;-- if (created) attachCitations(post, revision.number, input.citations);++ if (created) {++ // An edit that does not send citations keeps the ones it had (the /write editor does not++ // resend them); sending a list, even an empty one, replaces them.++ if (input.citations !== undefined) attachCitations(post, revision.number, input.citations);++ else store.citations.carryForward({ entityId: post.id, fromRevision: head.number, toRevision: revision.number, attachedBy: viewer.subject });++ }}const sets = {};if (input.slug !== undefined && input.slug !== '' && input.slug !== post.slug) {@@@ -165,6 +165,20 @@ const LONG = Array.from({ length: 120 }, (_, i) => `word${i}`).join(' ');assert.strictEqual(r.headers.get('content-type'), 'application/problem+json');});++ await check('an edit that does not send citations keeps them; sending a list replaces them', async () => {++ const made = await t.get('/api/v1/blogs/alice/posts', { as: alice, json: { title: 'Cited', body: `Sources below.\n\n${LONG}`, citations: [{ url: 'https://example.org/a', title: 'A', quote: 'quoted' }] } });++ assert.strictEqual(made.status, 201, made.text);++ const id = made.json().post.id;++ const citesAt = () => { const h = t.ctx.store.revisions.head(id); return t.ctx.store.citations.forRevision(id, h.number).map((c) => c.url); };++ assert.deepStrictEqual(citesAt(), ['https://example.org/a']);++ let r = await t.get(`/api/v1/posts/${id}`, { as: alice, method: 'PATCH', json: { expected_revision: t.ctx.store.revisions.head(id).number, body: `Edited in /write.\n\n${LONG}` } });++ assert.strictEqual(r.status, 200, r.text);++ assert.deepStrictEqual(citesAt(), ['https://example.org/a'], 'carried forward');++ r = await t.get(`/api/v1/posts/${id}`, { as: alice, method: 'PATCH', json: { expected_revision: t.ctx.store.revisions.head(id).number, body: `Replaced.\n\n${LONG}`, citations: [] } });++ assert.strictEqual(r.status, 200, r.text);++ assert.deepStrictEqual(citesAt(), [], 'an explicit empty list removes them');++ });++await t.close();done();})();
@@ -293,7 +293,12 @@ function createPosts({ store, blogs, publication, access, outbox, log = console
@@ -293,7 +293,12 @@ function createPosts({ store, blogs, publication, access, outbox, log = console
});
});
revision = out.revision;
revision = out.revision;
created = out.created;
created = out.created;
- if (created) attachCitations(post, revision.number, input.citations);
+ if (created) {
+ // An edit that does not send citations keeps the ones it had (the /write editor does not
+ // resend them); sending a list, even an empty one, replaces them.
+ if (input.citations !== undefined) attachCitations(post, revision.number, input.citations);
+ else store.citations.carryForward({ entityId: post.id, fromRevision: head.number, toRevision: revision.number, attachedBy: viewer.subject });
+ }
}
}
const sets = {};
const sets = {};
if (input.slug !== undefined && input.slug !== '' && input.slug !== post.slug) {
if (input.slug !== undefined && input.slug !== '' && input.slug !== post.slug) {
@@ -165,6 +165,20 @@ const LONG = Array.from({ length: 120 }, (_, i) => `word${i}`).join(' ');
@@ -165,6 +165,20 @@ const LONG = Array.from({ length: 120 }, (_, i) => `word${i}`).join(' ');
assert.strictEqual(r.headers.get('content-type'), 'application/problem+json');
assert.strictEqual(r.headers.get('content-type'), 'application/problem+json');
});
});
+ await check('an edit that does not send citations keeps them; sending a list replaces them', async () => {
+ const made = await t.get('/api/v1/blogs/alice/posts', { as: alice, json: { title: 'Cited', body: `Sources below.\n\n${LONG}`, citations: [{ url: 'https://example.org/a', title: 'A', quote: 'quoted' }] } });
+ assert.strictEqual(made.status, 201, made.text);
+ const id = made.json().post.id;
+ const citesAt = () => { const h = t.ctx.store.revisions.head(id); return t.ctx.store.citations.forRevision(id, h.number).map((c) => c.url); };
+ assert.deepStrictEqual(citesAt(), ['https://example.org/a']);
+ let r = await t.get(`/api/v1/posts/${id}`, { as: alice, method: 'PATCH', json: { expected_revision: t.ctx.store.revisions.head(id).number, body: `Edited in /write.\n\n${LONG}` } });
+ assert.strictEqual(r.status, 200, r.text);
+ assert.deepStrictEqual(citesAt(), ['https://example.org/a'], 'carried forward');
+ r = await t.get(`/api/v1/posts/${id}`, { as: alice, method: 'PATCH', json: { expected_revision: t.ctx.store.revisions.head(id).number, body: `Replaced.\n\n${LONG}`, citations: [] } });
+ assert.strictEqual(r.status, 200, r.text);
+ assert.deepStrictEqual(citesAt(), [], 'an explicit empty list removes them');
+ });
+
await t.close();
await t.close();
done();
done();
})();
})();