From 532fdb080633fc9970d3755e1a032dedd956caa0 Mon Sep 17 00:00:00 2001 From: Nazar Gargol Date: Tue, 6 Aug 2019 14:56:47 +0200 Subject: [PATCH] Added migrations for scheduler integration, permission and role refs #10060 - Modification of https://github.com/TryGhost/Ghost/pull/10974/files - Added publish permission migrations for all roles having "post": "all" permission --- ...ackup-content-permission-to-roles copy.js} | 0 .../2.28/3-insert-ghost-scheduler-role.js | 84 +++++++++++++++++++ .../2.28/4-insert-scheduler-integration.js | 69 +++++++++++++++ .../5-add-scheduler-permission-to-roles.js | 52 ++++++++++++ .../server/data/schema/fixtures/fixtures.json | 10 +-- core/test/regression/api/v0.1/roles_spec.js | 3 +- .../regression/migrations/migration_spec.js | 9 +- core/test/unit/data/schema/integrity_spec.js | 2 +- 8 files changed, 220 insertions(+), 9 deletions(-) rename core/server/data/migrations/versions/2.28/{2-add-db-backup-content-permission-to-roles.js => 2-add-db-backup-content-permission-to-roles copy.js} (100%) create mode 100644 core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js create mode 100644 core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js create mode 100644 core/server/data/migrations/versions/2.28/5-add-scheduler-permission-to-roles.js diff --git a/core/server/data/migrations/versions/2.28/2-add-db-backup-content-permission-to-roles.js b/core/server/data/migrations/versions/2.28/2-add-db-backup-content-permission-to-roles copy.js similarity index 100% rename from core/server/data/migrations/versions/2.28/2-add-db-backup-content-permission-to-roles.js rename to core/server/data/migrations/versions/2.28/2-add-db-backup-content-permission-to-roles copy.js diff --git a/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js b/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js new file mode 100644 index 000000000000..625a44d46d65 --- /dev/null +++ b/core/server/data/migrations/versions/2.28/3-insert-ghost-scheduler-role.js @@ -0,0 +1,84 @@ +const logging = require('../../../../lib/common/logging'); +const merge = require('lodash/merge'); +const models = require('../../../../models'); +const utils = require('../../../schema/fixtures/utils'); + +const resource = 'post'; +const _private = {}; + +_private.printResult = function printResult(result, message) { + if (result.done === result.expected) { + logging.info(message); + } else { + logging.warn(`(${result.done}/${result.expected}) ${message}`); + } +}; + +_private.addSchedulerRole = (options) => { + const message = 'Adding "Scheduler Integration" role to roles table'; + const apiKeyRole = utils.findModelFixtureEntry('Role', {name: 'Scheduler Integration'}); + + return models.Role.findOne({name: apiKeyRole.name}, options) + .then((role) => { + if (!role) { + return utils.addFixturesForModel({ + name: 'Role', + entries: [apiKeyRole] + }, options).then(result => _private.printResult(result, message)); + } + + logging.warn(message); + }); +}; + +_private.addPublishPermission = (options) => { + const modelToAdd = utils.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'}); + + return utils.addFixturesForModel(modelToAdd, options) + .then(result => _private.printResult(result, `Adding "publish" permissions fixtures for ${resource}s`)); +}; + +_private.removeApiKeyPermissionsAndRole = (options) => { + const message = 'Rollback: Removing "Scheduler Integration" role and permissions'; + + const modelToRemove = utils.findModelFixtures('Permission', {object_type: resource, action_type: 'publish'}); + + // permission model automatically cleans up permissions_roles on .destroy() + return utils.removeFixturesForModel(modelToRemove, options) + .then(result => _private.printResult(result, `Removing "publish" permissions fixtures for ${resource}s`)) + .then(() => models.Role.findOne({name: 'Scheduler Integration'}, options)) + .then((role) => { + if (!role) { + logging.warn(message); + return; + } + + return role.destroy(options); + }) + .then(() => { + logging.info(message); + }); +}; + +module.exports.config = { + transaction: true +}; + +module.exports.up = (options) => { + const localOptions = merge({ + context: {internal: true}, + migrating: true + }, options); + + return _private.addSchedulerRole(localOptions) + .then(() => _private.addPublishPermission(localOptions)); +}; + +module.exports.down = (options) => { + const localOptions = merge({ + context: {internal: true}, + migrating: true + }, options); + + return _private.removeApiKeyPermissionsAndRole(localOptions); +}; diff --git a/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js b/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js new file mode 100644 index 000000000000..e68b3edbce26 --- /dev/null +++ b/core/server/data/migrations/versions/2.28/4-insert-scheduler-integration.js @@ -0,0 +1,69 @@ +const logging = require('../../../../lib/common/logging'); +const merge = require('lodash/merge'); +const models = require('../../../../models'); +const utils = require('../../../schema/fixtures/utils'); + +const _private = {}; + +_private.printResult = function printResult(result, message) { + if (result.done === result.expected) { + logging.info(message); + } else { + logging.warn(`(${result.done}/${result.expected}) ${message}`); + } +}; + +_private.addGhostSchedulerIntegration = (options) => { + const message = 'Adding "Ghost Scheduler" integration'; + const fixtureIntegration = utils.findModelFixtureEntry('Integration', {slug: 'ghost-scheduler'}); + + return models.Integration.findOne({slug: fixtureIntegration.slug}, options) + .then((integration) => { + if (!integration) { + return utils.addFixturesForModel({ + name: 'Integration', + entries: [fixtureIntegration] + }, options).then(result => _private.printResult(result, message)); + } + + logging.warn(message); + }); +}; + +_private.removeGhostSchedulerIntegration = (options) => { + const message = 'Rollback: Removing "Ghost Scheduler" integration'; + + return models.Integration.findOne({slug: 'ghost-scheduler'}, options) + .then((integration) => { + if (!integration) { + logging.warn(message); + return; + } + + return integration.destroy().then(() => { + logging.info(message); + }); + }); +}; + +module.exports.config = { + transaction: true +}; + +module.exports.up = (options) => { + const localOptions = merge({ + context: {internal: true}, + migrating: true + }, options); + + return _private.addGhostSchedulerIntegration(localOptions); +}; + +module.exports.down = (options) => { + const localOptions = merge({ + context: {internal: true}, + migrating: true + }, options); + + return _private.removeGhostSchedulerIntegration(localOptions); +}; diff --git a/core/server/data/migrations/versions/2.28/5-add-scheduler-permission-to-roles.js b/core/server/data/migrations/versions/2.28/5-add-scheduler-permission-to-roles.js new file mode 100644 index 000000000000..bbdfd5c885d4 --- /dev/null +++ b/core/server/data/migrations/versions/2.28/5-add-scheduler-permission-to-roles.js @@ -0,0 +1,52 @@ +const logging = require('../../../../lib/common/logging'); +const utils = require('../../../schema/fixtures/utils'); + +const relationFixtures = { + from: { + model: 'Role', + match: 'name', + relation: 'permissions' + }, + to: { + model: 'Permission', + match: ['object_type', 'action_type'] + }, + entries: { + Administrator: { + post: 'publish' + }, + 'Admin Integration': { + post: 'publish' + }, + Editor: { + post: 'publish' + }, + 'Scheduler Integration': { + post: 'publish' + } + } +}; + +module.exports = { + config: { + transaction: true + }, + + async up(options) { + try { + await utils.addFixturesForRelation(relationFixtures, options); + return logging.info('Completed adding post.publish permission to roles'); + } catch (err) { + return logging.warn('Issue adding post.publish permission to roles'); + } + }, + + async down(options) { + try { + await utils.removeFixturesForRelation(relationFixtures, options); + return logging.info('Completed removing post.publish permission from roles'); + } catch (err) { + return logging.warn('Issue removing post.publish permission from roles'); + } + } +}; diff --git a/core/server/data/schema/fixtures/fixtures.json b/core/server/data/schema/fixtures/fixtures.json index 3e1684abce0a..5c40b92af7ec 100644 --- a/core/server/data/schema/fixtures/fixtures.json +++ b/core/server/data/schema/fixtures/fixtures.json @@ -145,11 +145,6 @@ "action_type": "destroy", "object_type": "post" }, - { - "name": "Publish posts", - "action_type": "publish", - "object_type": "post" - }, { "name": "Browse settings", "action_type": "browse", @@ -439,6 +434,11 @@ "name": "Delete Members", "action_type": "destroy", "object_type": "member" + }, + { + "name": "Publish posts", + "action_type": "publish", + "object_type": "post" } ] }, diff --git a/core/test/regression/api/v0.1/roles_spec.js b/core/test/regression/api/v0.1/roles_spec.js index 009aa90459bf..e31499acfb4a 100644 --- a/core/test/regression/api/v0.1/roles_spec.js +++ b/core/test/regression/api/v0.1/roles_spec.js @@ -40,7 +40,7 @@ describe('Roles API', function () { should.exist(response); should.exist(response.roles); localUtils.API.checkResponse(response, 'roles'); - response.roles.should.have.length(7); + response.roles.should.have.length(8); localUtils.API.checkResponse(response.roles[0], 'role'); localUtils.API.checkResponse(response.roles[1], 'role'); localUtils.API.checkResponse(response.roles[2], 'role'); @@ -48,6 +48,7 @@ describe('Roles API', function () { localUtils.API.checkResponse(response.roles[4], 'role'); localUtils.API.checkResponse(response.roles[5], 'role'); localUtils.API.checkResponse(response.roles[6], 'role'); + localUtils.API.checkResponse(response.roles[7], 'role'); done(); }); diff --git a/core/test/regression/migrations/migration_spec.js b/core/test/regression/migrations/migration_spec.js index 04fc297097e1..678939e40b04 100644 --- a/core/test/regression/migrations/migration_spec.js +++ b/core/test/regression/migrations/migration_spec.js @@ -205,6 +205,10 @@ describe('Database Migration (special functions)', function () { permissions[67].name.should.eql('Edit Members'); permissions[68].name.should.eql('Add Members'); permissions[69].name.should.eql('Delete Members'); + + // Posts + permissions[70].name.should.eql('Publish posts'); + permissions[70].should.be.AssignedToRoles(['Administrator', 'Editor', 'Admin Integration', 'Scheduler Integration']); }); describe('Populate', function () { @@ -260,7 +264,7 @@ describe('Database Migration (special functions)', function () { // Roles should.exist(result.roles); - result.roles.length.should.eql(7); + result.roles.length.should.eql(8); result.roles.at(0).get('name').should.eql('Administrator'); result.roles.at(1).get('name').should.eql('Editor'); result.roles.at(2).get('name').should.eql('Author'); @@ -268,9 +272,10 @@ describe('Database Migration (special functions)', function () { result.roles.at(4).get('name').should.eql('Owner'); result.roles.at(5).get('name').should.eql('Admin Integration'); result.roles.at(6).get('name').should.eql('DB Backup Integration'); + result.roles.at(7).get('name').should.eql('Scheduler Integration'); // Permissions - result.permissions.length.should.eql(70); + result.permissions.length.should.eql(71); result.permissions.toJSON().should.be.CompletePermissions(); }); }); diff --git a/core/test/unit/data/schema/integrity_spec.js b/core/test/unit/data/schema/integrity_spec.js index 5fc7c016b278..7db868a05000 100644 --- a/core/test/unit/data/schema/integrity_spec.js +++ b/core/test/unit/data/schema/integrity_spec.js @@ -20,7 +20,7 @@ var should = require('should'), describe('DB version integrity', function () { // Only these variables should need updating const currentSchemaHash = 'fda0398e93a74b2dc435cb4c026679ba'; - const currentFixturesHash = 'c61a52e138abb31de3a58c7728ca3d79'; + const currentFixturesHash = 'd0ee1deaea406f78e1f2145384196b48'; // If this test is failing, then it is likely a change has been made that requires a DB version bump, // and the values above will need updating as confirmation