diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f66524eaf..1167bce455 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Uploaded SVGs now permit `` tags granted their `xlink:href` property is a local reference and begins with the `#` character. This improves SVG support while mitgating XSS vulnerabilities. * Default properties of object fields present in a widget now populate correctly even if never focused in the editor. +* Ensure parked fields are not modified for parked pages when not configured in `_defaults`. ## 4.7.0 (2024-09-05) diff --git a/modules/@apostrophecms/page/index.js b/modules/@apostrophecms/page/index.js index c26eb59f5a..fe3afa5c9f 100644 --- a/modules/@apostrophecms/page/index.js +++ b/modules/@apostrophecms/page/index.js @@ -846,6 +846,21 @@ module.exports = { }, handlers(self) { return { + '@apostrophecms/page-type:beforeSave': { + handleParkedFieldsOverride(req, doc) { + if (!doc.parkedId) { + return; + } + const parked = self.parked.find(p => p.parkedId === doc.parkedId); + if (!parked) { + return; + } + const parkedFields = Object.keys(parked).filter(field => field !== '_defaults'); + for (const parkedField of parkedFields) { + doc[parkedField] = parked[parkedField]; + } + } + }, beforeSend: { async addLevelAttributeToBody(req) { // Add level as a data attribute on the body tag diff --git a/test/content-i18n.js b/test/content-i18n.js index f15f9c719a..b1f46c4743 100644 --- a/test/content-i18n.js +++ b/test/content-i18n.js @@ -96,7 +96,7 @@ describe('content-i18n', function() { peoplePageFrCA = await apos.page.find(frCAReq, { parkedId: 'people' }).toObject(); - assert(peoplePageFrCA.title === 'Altered'); + assert(peoplePageFrCA.title === 'People'); }); let home; diff --git a/test/events2.js b/test/events2.js index 0121e7a216..15c9f37a3b 100644 --- a/test/events2.js +++ b/test/events2.js @@ -45,10 +45,12 @@ describe('Promisified Events: @apostrophecms/doc-type:beforeInsert', function() { type: 'default-page', findMeAgain: true, - title: 'Test', slug: '/test', visibility: 'public', - parkedId: 'test' + parkedId: 'test', + _defaults: { + title: 'Test' + } } ] } diff --git a/test/parked-pages.js b/test/parked-pages.js index bfddfcccca..2f96d1e344 100644 --- a/test/parked-pages.js +++ b/test/parked-pages.js @@ -271,6 +271,81 @@ describe('Parked Pages', function() { }); await validate(apos6, [ '/', '/archive', '/default1', '/default2', '/default3', '/default3/child1' ]); }); + + it('field override on save is possible only when it is configured as default', async function () { + this.timeout(20000); + await t.destroy(apos6); + apos6 = await t.create({ + root: module, + modules: { + '@apostrophecms/page': { + options: { + park: [ + ...park2, + { + parkedId: 'default3', + type: 'default-page', + title: 'Default 3', + slug: '/default3' + }, + { + parkedId: 'default4', + type: 'default-page', + title: 'Default 4', + _defaults: { + slug: '/default4' + } + } + ] + } + }, + 'default-page': {} + } + }); + const manager = apos6.doc.getManager('default-page'); + const req = apos.task.getReq({ mode: 'draft' }); + + // slug override not possible, slug is NOT configured in defaults + { + const page = await manager.find(req, { + parkedId: 'default3', + aposMode: 'draft' + }).toObject(); + assert.strictEqual(page.slug, '/default3'); + assert.deepStrictEqual(page.parked, [ 'parkedId', 'type', 'title', 'slug' ]); + + page.slug = '/default3-overridden'; + await manager.update(req, page); + const updated = await manager.find(req, { + parkedId: 'default3', + aposMode: 'draft' + }).toObject(); + + assert.strictEqual(updated.slug, '/default3'); + } + + // slug override is possible because slug is configured in defaults + { + const page = await manager.find(req, { + parkedId: 'default4', + aposMode: 'draft' + }).toObject(); + assert.strictEqual(page.slug, '/default4'); + assert.deepStrictEqual(page.parked, [ 'parkedId', 'type', 'title' ]); + + page.slug = '/default4-overridden'; + await manager.update(req, page); + const updated = await manager.find(req, { + parkedId: 'default4', + aposMode: 'draft' + }).toObject(); + + assert.strictEqual(updated.slug, '/default4-overridden'); + } + + await t.destroy(apos6); + apos6 = null; + }); }); async function validate(apos, expected) {