From 7cb93be60bd346eefddbdd7928c627021f760a33 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 13 Oct 2021 17:25:32 +0100 Subject: [PATCH] Added boolean as allowed custom theme setting type refs https://github.com/TryGhost/Team/issues/1106 - updated schema validation to add `'boolean'` as an allowed `type` value - added `format()` and `parse()` methods to `CustomThemeSetting` model to match `Settings` model behaviour for boolean-type settings --- core/server/data/schema/schema.js | 3 +- core/server/models/custom-theme-setting.js | 43 ++++++++++++++- .../models/custom-theme-setting.test.js | 53 +++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 test/unit/server/models/custom-theme-setting.test.js diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index efcaa6a37e..810be04b8f 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -678,7 +678,8 @@ module.exports = { nullable: false, validations: { isIn: [[ - 'select' + 'select', + 'boolean' ]] } }, diff --git a/core/server/models/custom-theme-setting.js b/core/server/models/custom-theme-setting.js index 5b254cd505..f378f84a20 100644 --- a/core/server/models/custom-theme-setting.js +++ b/core/server/models/custom-theme-setting.js @@ -1,7 +1,48 @@ +const _ = require('lodash'); const ghostBookshelf = require('./base'); const CustomThemeSetting = ghostBookshelf.Model.extend({ - tableName: 'custom_theme_settings' + tableName: 'custom_theme_settings', + + parse() { + const attrs = ghostBookshelf.Model.prototype.parse.apply(this, arguments); + const settingType = attrs.type; + + // transform "0" to false for boolean type + if (settingType === 'boolean' && (attrs.value === '0' || attrs.value === '1')) { + attrs.value = !!+attrs.value; + } + + // transform "false" to false for boolean type + if (settingType === 'boolean' && (attrs.value === 'false' || attrs.value === 'true')) { + attrs.value = JSON.parse(attrs.value); + } + + return attrs; + }, + + format() { + const attrs = ghostBookshelf.Model.prototype.format.apply(this, arguments); + const settingType = attrs.type; + + if (settingType === 'boolean') { + // CASE: Ensure we won't forward strings, otherwise model events or model interactions can fail + if (attrs.value === '0' || attrs.value === '1') { + attrs.value = !!+attrs.value; + } + + // CASE: Ensure we won't forward strings, otherwise model events or model interactions can fail + if (attrs.value === 'false' || attrs.value === 'true') { + attrs.value = JSON.parse(attrs.value); + } + + if (_.isBoolean(attrs.value)) { + attrs.value = attrs.value.toString(); + } + } + + return attrs; + } }); module.exports = { diff --git a/test/unit/server/models/custom-theme-setting.test.js b/test/unit/server/models/custom-theme-setting.test.js new file mode 100644 index 0000000000..618a4f2a4f --- /dev/null +++ b/test/unit/server/models/custom-theme-setting.test.js @@ -0,0 +1,53 @@ +const should = require('should'); +const models = require('../../../../core/server/models'); + +describe('Unit: models/custom-theme-setting', function () { + before(function () { + models.init(); + }); + + describe('parse', function () { + it('ensure correct parsing when fetching from db', function () { + const setting = models.CustomThemeSetting.forge(); + + let returns = setting.parse({theme: 'test', key: 'dark_mode', value: 'false', type: 'boolean'}); + should.equal(returns.value, false); + + returns = setting.parse({theme: 'test', key: 'dark_mode', value: false, type: 'boolean'}); + should.equal(returns.value, false); + + returns = setting.parse({theme: 'test', key: 'dark_mode', value: true, type: 'boolean'}); + should.equal(returns.value, true); + + returns = setting.parse({theme: 'test', key: 'dark_mode', value: 'true', type: 'boolean'}); + should.equal(returns.value, true); + + returns = setting.parse({theme: 'test', key: 'dark_mode', value: '0', type: 'boolean'}); + should.equal(returns.value, false); + + returns = setting.parse({theme: 'test', key: 'dark_mode', value: '1', type: 'boolean'}); + should.equal(returns.value, true); + + returns = setting.parse({theme: 'test', key: 'something', value: 'null', type: 'select'}); + should.equal(returns.value, 'null'); + }); + }); + + describe('format', function () { + it('ensure correct formatting when setting', function () { + const setting = models.CustomThemeSetting.forge(); + + let returns = setting.format({theme: 'test', key: 'dark_mode', value: '0', type: 'boolean'}); + should.equal(returns.value, 'false'); + + returns = setting.format({theme: 'test', key: 'dark_mode', value: '1', type: 'boolean'}); + should.equal(returns.value, 'true'); + + returns = setting.format({theme: 'test', key: 'dark_mode', value: 'false', type: 'boolean'}); + should.equal(returns.value, 'false'); + + returns = setting.format({theme: 'test', key: 'dark_mode', value: 'true', type: 'boolean'}); + should.equal(returns.value, 'true'); + }); + }); +});