From 57effd9585cbe25d257de9b4a7f75ddb766ca4e6 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Thu, 23 Sep 2021 11:51:18 +0100 Subject: [PATCH] Added `custom_theme_settings` table/model (#13327) refs https://github.com/TryGhost/Team/issues/1070 - stores values of custom theme settings - will be merged with full settings data parsed from themes for API output - will be cached and made available for lookup in themes to avoid db roundtrips - stores type of custom theme settings so we can coerce values and know if the type has changed when syncing - records will be synced with themes upon activation --- core/server/data/exporter/table-lists.js | 1 + .../4.16/01-add-custom-theme-settings-table.js | 9 +++++++++ core/server/data/schema/schema.js | 16 ++++++++++++++++ core/server/models/custom-theme-setting.js | 9 +++++++++ core/server/models/index.js | 1 + test/regression/api/canary/admin/db.test.js | 6 +++--- test/regression/api/v2/admin/db.test.js | 6 +++--- test/regression/api/v3/admin/db.test.js | 6 +++--- test/regression/exporter/exporter.test.js | 1 + test/unit/data/exporter/index.test.js | 10 ++++++---- test/unit/data/schema/integrity.test.js | 2 +- test/utils/fixtures/export/body-generator.js | 1 + 12 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js create mode 100644 core/server/models/custom-theme-setting.js diff --git a/core/server/data/exporter/table-lists.js b/core/server/data/exporter/table-lists.js index ddbfb2205a..0414842a3d 100644 --- a/core/server/data/exporter/table-lists.js +++ b/core/server/data/exporter/table-lists.js @@ -50,6 +50,7 @@ const TABLES_ALLOWLIST = [ 'roles', 'roles_users', 'settings', + 'custom_theme_settings', 'tags', 'users' ]; diff --git a/core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js b/core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js new file mode 100644 index 0000000000..d201844b57 --- /dev/null +++ b/core/server/data/migrations/versions/4.16/01-add-custom-theme-settings-table.js @@ -0,0 +1,9 @@ +const utils = require('../../utils'); + +module.exports = utils.addTable('custom_theme_settings', { + id: {type: 'string', maxlength: 24, nullable: false, primary: true}, + theme: {type: 'string', maxlength: 191, nullable: false}, + key: {type: 'string', maxlength: 191, nullable: false}, + type: {type: 'string', maxlength: 50, nullable: false}, + value: {type: 'text', maxlength: 65535, nullable: true} +}); diff --git a/core/server/data/schema/schema.js b/core/server/data/schema/schema.js index f316b2f4d4..5bc29ce9c2 100644 --- a/core/server/data/schema/schema.js +++ b/core/server/data/schema/schema.js @@ -643,5 +643,21 @@ module.exports = { entry_id: {type: 'string', maxlength: 24, nullable: true}, source_url: {type: 'string', maxlength: 2000, nullable: true}, metadata: {type: 'string', maxlength: 191, nullable: true} + }, + custom_theme_settings: { + id: {type: 'string', maxlength: 24, nullable: false, primary: true}, + theme: {type: 'string', maxlength: 191, nullable: false}, + key: {type: 'string', maxlength: 191, nullable: false}, + type: { + type: 'string', + maxlength: 50, + nullable: false, + validations: { + isIn: [[ + 'select' + ]] + } + }, + value: {type: 'text', maxlength: 65535, nullable: true} } }; diff --git a/core/server/models/custom-theme-setting.js b/core/server/models/custom-theme-setting.js new file mode 100644 index 0000000000..5b254cd505 --- /dev/null +++ b/core/server/models/custom-theme-setting.js @@ -0,0 +1,9 @@ +const ghostBookshelf = require('./base'); + +const CustomThemeSetting = ghostBookshelf.Model.extend({ + tableName: 'custom_theme_settings' +}); + +module.exports = { + CustomThemeSetting: ghostBookshelf.model('CustomThemeSetting', CustomThemeSetting) +}; diff --git a/core/server/models/index.js b/core/server/models/index.js index b5f01c7caf..43ea2493c8 100644 --- a/core/server/models/index.js +++ b/core/server/models/index.js @@ -17,6 +17,7 @@ const models = [ 'post', 'role', 'settings', + 'custom-theme-setting', 'session', 'tag', 'tag-public', diff --git a/test/regression/api/canary/admin/db.test.js b/test/regression/api/canary/admin/db.test.js index 39ba0e1b00..fde2dad959 100644 --- a/test/regression/api/canary/admin/db.test.js +++ b/test/regression/api/canary/admin/db.test.js @@ -15,7 +15,7 @@ let ghost = testUtils.startGhost; let request; let eventsTriggered; -describe('DB API', function () { +describe('DB API (canary)', function () { let backupKey; let schedulerKey; @@ -59,8 +59,8 @@ describe('DB API', function () { should.exist(jsonResponse.db); jsonResponse.db.should.have.length(1); - // NOTE: 9 default tables + 1 from include parameters - Object.keys(jsonResponse.db[0].data).length.should.eql(10); + // NOTE: 10 default tables + 1 from include parameters + Object.keys(jsonResponse.db[0].data).length.should.eql(11); }); }); diff --git a/test/regression/api/v2/admin/db.test.js b/test/regression/api/v2/admin/db.test.js index 7b881e13db..f442020f2e 100644 --- a/test/regression/api/v2/admin/db.test.js +++ b/test/regression/api/v2/admin/db.test.js @@ -15,7 +15,7 @@ let ghost = testUtils.startGhost; let request; let eventsTriggered; -describe('DB API', function () { +describe('DB API (v2)', function () { let backupKey; let schedulerKey; @@ -59,8 +59,8 @@ describe('DB API', function () { should.exist(jsonResponse.db); jsonResponse.db.should.have.length(1); - // NOTE: 9 default tables + 1 from include parameters - Object.keys(jsonResponse.db[0].data).length.should.eql(10); + // NOTE: 10 default tables + 1 from include parameters + Object.keys(jsonResponse.db[0].data).length.should.eql(11); }); }); diff --git a/test/regression/api/v3/admin/db.test.js b/test/regression/api/v3/admin/db.test.js index 43b355e8f8..69013ed197 100644 --- a/test/regression/api/v3/admin/db.test.js +++ b/test/regression/api/v3/admin/db.test.js @@ -15,7 +15,7 @@ let ghost = testUtils.startGhost; let request; let eventsTriggered; -describe('DB API', function () { +describe('DB API (v3)', function () { let backupKey; let schedulerKey; @@ -59,8 +59,8 @@ describe('DB API', function () { should.exist(jsonResponse.db); jsonResponse.db.should.have.length(1); - // NOTE: 9 default tables + 1 from include parameters - Object.keys(jsonResponse.db[0].data).length.should.eql(10); + // NOTE: 10 default tables + 1 from include parameters + Object.keys(jsonResponse.db[0].data).length.should.eql(11); }); }); diff --git a/test/regression/exporter/exporter.test.js b/test/regression/exporter/exporter.test.js index 0334d691b0..fae200535f 100644 --- a/test/regression/exporter/exporter.test.js +++ b/test/regression/exporter/exporter.test.js @@ -25,6 +25,7 @@ describe('Exporter', function () { 'actions', 'api_keys', 'brute', + 'custom_theme_settings', 'email_batches', 'email_recipients', 'emails', diff --git a/test/unit/data/exporter/index.test.js b/test/unit/data/exporter/index.test.js index 427c5f2aef..39bb217e98 100644 --- a/test/unit/data/exporter/index.test.js +++ b/test/unit/data/exporter/index.test.js @@ -40,8 +40,8 @@ describe('Exporter', function () { it('should try to export all the correct tables (without excluded)', function (done) { exporter.doExport().then(function (exportData) { - // NOTE: 9 default tables - const expectedCallCount = 9; + // NOTE: 10 default tables + const expectedCallCount = 10; should.exist(exportData); @@ -62,6 +62,7 @@ describe('Exporter', function () { knexMock.getCall(6).args[0].should.eql('settings'); knexMock.getCall(7).args[0].should.eql('tags'); knexMock.getCall(8).args[0].should.eql('posts_tags'); + knexMock.getCall(9).args[0].should.eql('custom_theme_settings'); done(); }).catch(done); @@ -71,8 +72,8 @@ describe('Exporter', function () { const include = ['mobiledoc_revisions', 'email_recipients']; exporter.doExport({include}).then(function (exportData) { - // NOTE: 9 default tables + 2 includes - const expectedCallCount = 11; + // NOTE: 10 default tables + 2 includes + const expectedCallCount = 12; should.exist(exportData); @@ -96,6 +97,7 @@ describe('Exporter', function () { knexMock.getCall(8).args[0].should.eql('posts_tags'); knexMock.getCall(9).args[0].should.eql('mobiledoc_revisions'); knexMock.getCall(10).args[0].should.eql('email_recipients'); + knexMock.getCall(11).args[0].should.eql('custom_theme_settings'); done(); }).catch(done); diff --git a/test/unit/data/schema/integrity.test.js b/test/unit/data/schema/integrity.test.js index 67badf22f5..cd86e5e31b 100644 --- a/test/unit/data/schema/integrity.test.js +++ b/test/unit/data/schema/integrity.test.js @@ -32,7 +32,7 @@ const defaultSettings = require('../../../../core/server/data/schema/default-set */ describe('DB version integrity', function () { // Only these variables should need updating - const currentSchemaHash = '939c4993e183e0664362383a875cfc2d'; + const currentSchemaHash = '66e58a7b9081ccf78ac539a527f27332'; const currentFixturesHash = '8e04dbcb4b8e429e70989572fc9c67b9'; const currentSettingsHash = 'aa3fcbc8ab119b630aeda7366ead5493'; const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01'; diff --git a/test/utils/fixtures/export/body-generator.js b/test/utils/fixtures/export/body-generator.js index eaa910c53f..990dbe8606 100644 --- a/test/utils/fixtures/export/body-generator.js +++ b/test/utils/fixtures/export/body-generator.js @@ -141,6 +141,7 @@ const exportedBodyLatest = () => { version: '4.1.2' }, data: { + custom_theme_settings: [], posts: [], posts_authors: [], posts_meta: [],