From 388a625f378307529e71113c32c9b9fc7e86178a Mon Sep 17 00:00:00 2001 From: Naz Date: Wed, 19 Apr 2023 16:00:37 +0200 Subject: [PATCH] Added announcement_* fields to Settings Admin API refs https://github.com/TryGhost/Team/issues/3011 - Allows to edit and read following settings fields: - announcement_content - announcement_background - announcement_visibility --- .../utils/serializers/input/settings.js | 5 +- .../utils/validators/input/settings.js | 28 ++++- .../admin/__snapshots__/settings.test.js.snap | 107 ++++++++++++++++-- .../core/test/e2e-api/admin/settings.test.js | 68 +++++++++++ 4 files changed, 199 insertions(+), 9 deletions(-) diff --git a/ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js b/ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js index bd9343c5f7..60c23a3b0c 100644 --- a/ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js +++ b/ghost/core/core/server/api/endpoints/utils/serializers/input/settings.js @@ -62,7 +62,10 @@ const EDITABLE_SETTINGS = [ 'editor_default_email_recipients_filter', 'labs', 'comments_enabled', - 'outbound_link_tagging' + 'outbound_link_tagging', + 'announcement_content', + 'announcement_background', + 'announcement_visibility' ]; module.exports = { diff --git a/ghost/core/core/server/api/endpoints/utils/validators/input/settings.js b/ghost/core/core/server/api/endpoints/utils/validators/input/settings.js index 617db6f48d..3b9b80c48d 100644 --- a/ghost/core/core/server/api/endpoints/utils/validators/input/settings.js +++ b/ghost/core/core/server/api/endpoints/utils/validators/input/settings.js @@ -7,7 +7,9 @@ const tpl = require('@tryghost/tpl'); const messages = { invalidEmailReceived: 'Please send a valid email', invalidEmailValueReceived: 'Please enter a valid email address.', - invalidEmailTypeReceived: 'Invalid email type received' + invalidEmailTypeReceived: 'Invalid email type received', + invalidAnnouncementVisibilityValueReceived: 'Please enter a valid announcement visibility value', + invalidAnnouncementBackgroundValueReceived: 'Please enter a valid announcement background value' }; module.exports = { @@ -60,6 +62,30 @@ module.exports = { errors.push(typeError); } } + + if (setting.key === 'announcement_visibility') { + const visibilityValue = setting.value; + + if (!['public', 'visitors', 'members', 'paid'].includes(visibilityValue)) { + const visibilityError = new ValidationError({ + message: tpl(messages.invalidAnnouncementVisibilityValueReceived), + property: setting.key + }); + errors.push(visibilityError); + } + } + + if (setting.key === 'announcement_background') { + const announcementBackgroundValue = setting.value; + + if (!['accent', 'dark', 'light'].includes(announcementBackgroundValue)) { + const visibilityError = new ValidationError({ + message: tpl(messages.invalidAnnouncementBackgroundValueReceived), + property: setting.key + }); + errors.push(visibilityError); + } + } }); // Prevent setting icon to the resized one when sending all settings received from browse again in the edit endpoint diff --git a/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap b/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap index d7a4c218cf..e9234ecced 100644 --- a/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap +++ b/ghost/core/test/e2e-api/admin/__snapshots__/settings.test.js.snap @@ -652,7 +652,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", @@ -694,7 +694,7 @@ exports[`Settings API Edit Can edit a setting 2: [headers] 1`] = ` Object { "access-control-allow-origin": "http://127.0.0.1:2369", "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", - "content-length": "3906", + "content-length": "3934", "content-type": "application/json; charset=utf-8", "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, @@ -978,7 +978,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", @@ -1303,7 +1303,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", @@ -1633,7 +1633,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", @@ -1684,6 +1684,99 @@ Object { } `; +exports[`Settings API Edit fails to edit setting with unsupported announcement_background value 1: [body] 1`] = ` +Object { + "errors": Array [ + Object { + "code": null, + "context": "Please enter a valid announcement background value", + "details": null, + "ghostErrorCode": null, + "help": null, + "id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + "message": "Validation error, cannot edit setting.", + "property": "announcement_background", + "type": "ValidationError", + }, + ], +} +`; + +exports[`Settings API Edit fails to edit setting with unsupported announcement_background value 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "295", + "content-type": "application/json; charset=utf-8", + "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Accept-Version, Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Settings API Edit fails to edit setting with unsupported announcement_visibility value 1: [body] 1`] = ` +Object { + "errors": Array [ + Object { + "code": null, + "context": "Please enter a valid announcement visibility value", + "details": null, + "ghostErrorCode": null, + "help": null, + "id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + "message": "Validation error, cannot edit setting.", + "property": "announcement_visibility", + "type": "ValidationError", + }, + ], +} +`; + +exports[`Settings API Edit fails to edit setting with unsupported announcement_visibility value 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "295", + "content-type": "application/json; charset=utf-8", + "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Accept-Version, Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + +exports[`Settings API Edit fails to edit setting with unsupported value 1: [body] 1`] = ` +Object { + "errors": Array [ + Object { + "code": null, + "context": "Please enter a valid announcement visibility value", + "details": null, + "ghostErrorCode": null, + "help": null, + "id": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/, + "message": "Validation error, cannot edit setting.", + "property": "announcement_visibility", + "type": "ValidationError", + }, + ], +} +`; + +exports[`Settings API Edit fails to edit setting with unsupported value 2: [headers] 1`] = ` +Object { + "access-control-allow-origin": "http://127.0.0.1:2369", + "cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0", + "content-length": "295", + "content-type": "application/json; charset=utf-8", + "content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/, + "etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/, + "vary": "Accept-Version, Origin, Accept-Encoding", + "x-powered-by": "Express", +} +`; + exports[`Settings API Edit removes image size prefixes when setting the icon 1: [body] 1`] = ` Object { "meta": Object {}, @@ -1958,7 +2051,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", @@ -2348,7 +2441,7 @@ Object { }, Object { "key": "announcement_content", - "value": null, + "value": "

Great news coming soon!

", }, Object { "key": "announcement_visibility", diff --git a/ghost/core/test/e2e-api/admin/settings.test.js b/ghost/core/test/e2e-api/admin/settings.test.js index 17714d3482..74ee8c808a 100644 --- a/ghost/core/test/e2e-api/admin/settings.test.js +++ b/ghost/core/test/e2e-api/admin/settings.test.js @@ -1,4 +1,6 @@ const assert = require('assert'); +const sinon = require('sinon'); +const logging = require('@tryghost/logging'); const SingleUseTokenProvider = require('../../../core/server/services/members/SingleUseTokenProvider'); const settingsCache = require('../../../core/shared/settings-cache'); const {agentProvider, fixtureManager, mockManager, matchers} = require('../../utils/e2e-framework'); @@ -51,6 +53,7 @@ describe('Settings API', function () { afterEach(function () { mockManager.restore(); + sinon.restore(); }); describe('Browse', function () { @@ -105,6 +108,10 @@ describe('Settings API', function () { key: 'codeinjection_head', value: null }, + { + key: 'announcement_content', + value: '

Great news coming soon!

' + }, { key: 'navigation', value: JSON.stringify([{ @@ -302,6 +309,64 @@ describe('Settings API', function () { mockManager.assert.sentEmailCount(0); }); + + it('fails to edit setting with unsupported announcement_visibility value', async function () { + const loggingStub = sinon.stub(logging, 'error'); + const settingsToChange = [ + { + key: 'announcement_visibility', + value: 'invalid value' + } + ]; + + await agent.put('settings/') + .body({ + settings: settingsToChange + }) + .expectStatus(422) + .matchBodySnapshot({ + errors: [ + { + id: anyErrorId + } + ] + }) + .matchHeaderSnapshot({ + 'content-version': anyContentVersion, + etag: anyEtag + }); + + sinon.assert.calledOnce(loggingStub); + }); + + it('fails to edit setting with unsupported announcement_background value', async function () { + const loggingStub = sinon.stub(logging, 'error'); + const settingsToChange = [ + { + key: 'announcement_background', + value: 'not a background value' + } + ]; + + await agent.put('settings/') + .body({ + settings: settingsToChange + }) + .expectStatus(422) + .matchBodySnapshot({ + errors: [ + { + id: anyErrorId + } + ] + }) + .matchHeaderSnapshot({ + 'content-version': anyContentVersion, + etag: anyEtag + }); + + sinon.assert.calledOnce(loggingStub); + }); }); describe('verify key update', function () { @@ -335,6 +400,7 @@ describe('Settings API', function () { }); it('cannot update invalid keys via token', async function () { + const loggingStub = sinon.stub(logging, 'error'); const token = await (new SingleUseTokenProvider({ SingleUseTokenModel: models.SingleUseToken, validityPeriod: 24 * 60 * 60 * 1000, @@ -357,6 +423,8 @@ describe('Settings API', function () { 'content-version': anyContentVersion, etag: anyEtag }); + + sinon.assert.calledOnce(loggingStub); }); });