mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added migration utils for permissions
no-issue These utils are the first steps toward getting the models out of our migrations! The utils here interact directly with the database and where possible don't reinvent the wheel, by using smaller building blocks to build more comples ones.
This commit is contained in:
parent
91e3630f36
commit
ec119c458c
2 changed files with 742 additions and 0 deletions
249
core/server/data/migrations/utils.js
Normal file
249
core/server/data/migrations/utils.js
Normal file
|
@ -0,0 +1,249 @@
|
|||
const ObjectId = require('bson-objectid').default;
|
||||
const logging = require('../../../shared/logging');
|
||||
|
||||
const MIGRATION_USER = 1;
|
||||
|
||||
/**
|
||||
* Creates a migration which will add a permission to the database
|
||||
*
|
||||
* @param {Object} config
|
||||
* @param {string} config.name - The name of the permission
|
||||
* @param {string} config.action - The action_type of the permission
|
||||
* @param {string} config.object - The object_type of the permission
|
||||
*
|
||||
* @returns {Migration}
|
||||
*/
|
||||
function addPermission(config) {
|
||||
return createTransactionalMigration(
|
||||
async function up(connection) {
|
||||
const existingPermission = await connection('permissions').where({
|
||||
name: config.name,
|
||||
action_type: config.action,
|
||||
object_type: config.object
|
||||
}).first();
|
||||
|
||||
if (existingPermission) {
|
||||
logging.warn(`Permission for ${config.action}:${config.object} already added`);
|
||||
return;
|
||||
}
|
||||
|
||||
logging.info(`Adding permission for ${config.action}:${config.object}`);
|
||||
|
||||
const date = connection.raw('CURRENT_TIMESTAMP');
|
||||
|
||||
await connection('permissions').insert({
|
||||
id: ObjectId.generate(),
|
||||
name: config.name,
|
||||
action_type: config.action,
|
||||
object_type: config.object,
|
||||
created_at: date,
|
||||
created_by: MIGRATION_USER,
|
||||
updated_at: date,
|
||||
updated_by: MIGRATION_USER
|
||||
});
|
||||
},
|
||||
async function down(connection) {
|
||||
const existingPermission = await connection('permissions').where({
|
||||
name: config.name,
|
||||
action_type: config.action,
|
||||
object_type: config.object
|
||||
}).first();
|
||||
|
||||
if (!existingPermission) {
|
||||
logging.warn(`Permission for ${config.action}:${config.object} already removed`);
|
||||
return;
|
||||
}
|
||||
|
||||
logging.info(`Removing permission for ${config.action}:${config.object}`);
|
||||
|
||||
await connection('permissions').where({
|
||||
action_type: config.action,
|
||||
object_type: config.object
|
||||
}).del();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a migration which will link a permission to a role in the database
|
||||
*
|
||||
* @param {Object} config
|
||||
* @param {string} config.permission - The name of the permission
|
||||
* @param {string} config.role - The name of the role
|
||||
*
|
||||
* @returns {Migration}
|
||||
*/
|
||||
function addPermissionToRole(config) {
|
||||
return createTransactionalMigration(
|
||||
async function up(connection) {
|
||||
const permission = await connection('permissions').where({
|
||||
name: config.permission
|
||||
}).first();
|
||||
|
||||
if (!permission) {
|
||||
throw new Error(
|
||||
`Cannot add permission(${config.permission}) to role(${config.role}) - permission does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
const role = await connection('roles').where({
|
||||
name: config.role
|
||||
}).first();
|
||||
|
||||
if (!role) {
|
||||
throw new Error(
|
||||
`Cannot add permission(${config.permission}) to role(${config.role}) - role does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
const existingRelation = await connection('permissions_roles').where({
|
||||
permission_id: permission.id,
|
||||
role_id: role.id
|
||||
}).first();
|
||||
|
||||
if (existingRelation) {
|
||||
logging.warn(`Adding permission(${config.permission}) to role(${config.role}) - already exists`);
|
||||
return;
|
||||
}
|
||||
|
||||
logging.warn(`Adding permission(${config.permission}) to role(${config.role})`);
|
||||
await connection('permissions_roles').insert({
|
||||
id: ObjectId.generate(),
|
||||
permission_id: permission.id,
|
||||
role_id: role.id
|
||||
});
|
||||
},
|
||||
async function down(connection) {
|
||||
const permission = await connection('permissions').where({
|
||||
name: config.permission
|
||||
}).first();
|
||||
|
||||
if (!permission) {
|
||||
throw new Error(
|
||||
`Cannot remove permission(${config.permission}) from role(${config.role}) - permission does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
const role = await connection('roles').where({
|
||||
name: config.role
|
||||
}).first();
|
||||
|
||||
if (!role) {
|
||||
throw new Error(
|
||||
`Cannot remove permission(${config.permission}) from role(${config.role}) - role does not exist`
|
||||
);
|
||||
}
|
||||
|
||||
const existingRelation = await connection('permissions_roles').where({
|
||||
permission_id: permission.id,
|
||||
role_id: role.id
|
||||
}).first();
|
||||
|
||||
if (!existingRelation) {
|
||||
logging.warn(`Removing permission(${config.permission}) from role(${config.role}) - already removed`);
|
||||
return;
|
||||
}
|
||||
|
||||
logging.info(`Removing permission(${config.permission}) from role(${config.role})`);
|
||||
await connection('permissions_roles').where({
|
||||
permission_id: permission.id,
|
||||
role_id: role.id
|
||||
}).del();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a migration which will add a permission to the database, and then link it to roles
|
||||
*
|
||||
* @param {Object} config
|
||||
* @param {string} config.name - The name of the permission
|
||||
* @param {string} config.action - The action_type of the permission
|
||||
* @param {string} config.object - The object_type of the permission
|
||||
*
|
||||
* @param {string[]} roles - A list of role names
|
||||
*
|
||||
* @returns {Migration}
|
||||
*/
|
||||
function addPermissionWithRoles(config, roles) {
|
||||
return combineTransactionalMigrations(
|
||||
addPermission(config),
|
||||
...roles.map((role => addPermissionToRole({permission: config.name, role})))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(connection: import('knex')) => Promise<void>} up
|
||||
* @param {(connection: import('knex')) => Promise<void>} down
|
||||
*
|
||||
* @returns {Migration}
|
||||
*/
|
||||
function createTransactionalMigration(up, down) {
|
||||
return {
|
||||
config: {
|
||||
transaction: true
|
||||
},
|
||||
async up(config) {
|
||||
await up(config.transacting);
|
||||
},
|
||||
async down(config) {
|
||||
await down(config.transacting);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Migration[]} migrations
|
||||
*
|
||||
* @returns {Migration}
|
||||
*/
|
||||
function combineTransactionalMigrations(...migrations) {
|
||||
return {
|
||||
config: {
|
||||
transaction: true
|
||||
},
|
||||
async up(config) {
|
||||
for (const migration of migrations) {
|
||||
await migration.up(config);
|
||||
}
|
||||
},
|
||||
async down(config) {
|
||||
// Down migrations must be run backwards!!
|
||||
const reverseMigrations = migrations.slice().reverse();
|
||||
for (const migration of reverseMigrations) {
|
||||
await migration.down(config);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addPermission,
|
||||
addPermissionToRole,
|
||||
addPermissionWithRoles,
|
||||
createTransactionalMigration,
|
||||
combineTransactionalMigrations,
|
||||
meta: {
|
||||
MIGRATION_USER
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} TransactionalMigrationFunctionOptions
|
||||
*
|
||||
* @prop {import('knex')} transacting
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {(options: TransactionalMigrationFunctionOptions) => Promise<void>} TransactionalMigrationFunction
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Migration
|
||||
*
|
||||
* @prop {Object} config
|
||||
* @prop {boolean} config.transaction
|
||||
*
|
||||
* @prop {TransactionalMigrationFunction} up
|
||||
* @prop {TransactionalMigrationFunction} down
|
||||
*/
|
493
test/unit/data/migrations/utils.test.js
Normal file
493
test/unit/data/migrations/utils.test.js
Normal file
|
@ -0,0 +1,493 @@
|
|||
const should = require('should');
|
||||
const sinon = require('sinon');
|
||||
|
||||
const utils = require('../../../../core/server/data/migrations/utils');
|
||||
|
||||
// Get access to the core Promise constructor
|
||||
// as global.Promise is overidden by Ghost
|
||||
// https://github.com/TryGhost/Ghost/issues/9064
|
||||
const Promise = (async () => {})().constructor;
|
||||
|
||||
class Deferred {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
this.resolve = async (val) => {
|
||||
resolve(val);
|
||||
return this.promise;
|
||||
};
|
||||
this.reject = async (val) => {
|
||||
reject(val);
|
||||
return this.promise;
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
describe('migrations/utils', function () {
|
||||
describe('createTransactionalMigration', function () {
|
||||
it('Accepts two functions and creates a transactional migration from them', function () {
|
||||
const config = {
|
||||
transacting: {}
|
||||
};
|
||||
const up = sinon.spy();
|
||||
const down = sinon.spy();
|
||||
|
||||
const migration = utils.createTransactionalMigration(up, down);
|
||||
const upResult = migration.up(config);
|
||||
const downResult = migration.down(config);
|
||||
|
||||
should.ok(migration.config.transaction, 'Migration config should set transaction to true');
|
||||
|
||||
should.ok(upResult instanceof Promise, 'Migration up method should return a Promise');
|
||||
should.ok(downResult instanceof Promise, 'Migration down method should return a Promise');
|
||||
|
||||
should.ok(up.calledOnceWith(config.transacting), 'up function should be called with transacting');
|
||||
should.ok(down.calledOnceWith(config.transacting), 'down function should be called with transacting');
|
||||
});
|
||||
});
|
||||
|
||||
describe('combineTransactionalMigrations', function () {
|
||||
it('Accepts a number of migrations and returns a single migration', async function () {
|
||||
const config = {
|
||||
transacting: {}
|
||||
};
|
||||
const upA = sinon.stub().resolves();
|
||||
const downA = sinon.stub().resolves();
|
||||
const upB = sinon.stub().resolves();
|
||||
const downB = sinon.stub().resolves();
|
||||
|
||||
const migrationA = utils.createTransactionalMigration(upA, downA);
|
||||
const migrationB = utils.createTransactionalMigration(upB, downB);
|
||||
const combinedMigration = utils.combineTransactionalMigrations(migrationA, migrationB);
|
||||
|
||||
should.ok(combinedMigration.config.transaction, 'Migration config should set transaction to true');
|
||||
|
||||
const upResult = combinedMigration.up(config);
|
||||
should.ok(upResult instanceof Promise, 'Migration up method should return a Promise');
|
||||
|
||||
await upResult;
|
||||
should.ok(upA.calledOnceWith(config.transacting), 'first up fn should be called with transacting');
|
||||
should.ok(upB.calledOnceWith(config.transacting), 'second up fn should be called with transacting');
|
||||
should.ok(upA.calledBefore(upB), 'Migration up method should call child up methods in order');
|
||||
|
||||
const downResult = combinedMigration.down(config);
|
||||
should.ok(downResult instanceof Promise, 'Migration down method should return a Promise');
|
||||
|
||||
await downResult;
|
||||
should.ok(downA.calledOnceWith(config.transacting), 'first down fn should be called with transacting');
|
||||
should.ok(downB.calledOnceWith(config.transacting), 'second down fn should be called with transacting');
|
||||
should.ok(downB.calledBefore(downA), 'Migration down method should call child down methods in reverse order');
|
||||
});
|
||||
|
||||
it('Waits for each migration to finish before executing the next', async function () {
|
||||
const config = {
|
||||
transacting: {}
|
||||
};
|
||||
const upDeferredA = new Deferred();
|
||||
const upDeferredB = new Deferred();
|
||||
const downDeferredA = new Deferred();
|
||||
const downDeferredB = new Deferred();
|
||||
|
||||
const upA = sinon.stub().returns(upDeferredA.promise);
|
||||
const downA = sinon.stub().returns(downDeferredA.promise);
|
||||
const upB = sinon.stub().returns(upDeferredB.promise);
|
||||
const downB = sinon.stub().returns(downDeferredB.promise);
|
||||
|
||||
const migrationA = utils.createTransactionalMigration(upA, downA);
|
||||
const migrationB = utils.createTransactionalMigration(upB, downB);
|
||||
const combinedMigration = utils.combineTransactionalMigrations(migrationA, migrationB);
|
||||
|
||||
combinedMigration.up(config);
|
||||
|
||||
should.ok(!upB.called, 'second up fn should not be called until first up fn has resolved');
|
||||
await upDeferredA.resolve();
|
||||
should.ok(upB.calledOnce, 'second up fn should be called once first up fn has resolved');
|
||||
|
||||
combinedMigration.down(config);
|
||||
|
||||
should.ok(!downA.called, 'penultimate down fn should not be called until last down fn has resolved');
|
||||
await downDeferredB.resolve();
|
||||
should.ok(downA.calledOnce, 'penultimate down fn should be called once last down fn has resolved');
|
||||
});
|
||||
|
||||
it('Stops execution if a migration errors, and propagates error', async function () {
|
||||
const config = {
|
||||
transacting: {}
|
||||
};
|
||||
const upDeferredA = new Deferred();
|
||||
const upDeferredB = new Deferred();
|
||||
const downDeferredA = new Deferred();
|
||||
const downDeferredB = new Deferred();
|
||||
|
||||
const upA = sinon.stub().returns(upDeferredA.promise);
|
||||
const downA = sinon.stub().returns(downDeferredA.promise);
|
||||
const upB = sinon.stub().returns(upDeferredB.promise);
|
||||
const downB = sinon.stub().returns(downDeferredB.promise);
|
||||
|
||||
const migrationA = utils.createTransactionalMigration(upA, downA);
|
||||
const migrationB = utils.createTransactionalMigration(upB, downB);
|
||||
const combinedMigration = utils.combineTransactionalMigrations(migrationA, migrationB);
|
||||
|
||||
const upResult = combinedMigration.up(config);
|
||||
|
||||
should.ok(!upB.called, 'second up fn should not be called until first up fn has resolved');
|
||||
try {
|
||||
await upDeferredA.reject(new Error('some reason'));
|
||||
} catch (err) {
|
||||
//
|
||||
} finally {
|
||||
should.ok(!upB.called, 'second up fn should not be called if first up fn has rejected');
|
||||
}
|
||||
|
||||
let upError = null;
|
||||
try {
|
||||
await upResult;
|
||||
} catch (err) {
|
||||
upError = true;
|
||||
} finally {
|
||||
should.ok(upError, 'Migration up should error if child errors');
|
||||
}
|
||||
|
||||
const downResult = combinedMigration.down(config);
|
||||
|
||||
should.ok(!downA.called, 'penultimate down fn should not be called until last down fn has resolved');
|
||||
try {
|
||||
await downDeferredB.reject(new Error('some reason'));
|
||||
} catch (err) {
|
||||
//
|
||||
} finally {
|
||||
should.ok(!downA.called, 'penultimate down fn should not be called if last down fn has rejected');
|
||||
}
|
||||
|
||||
let downErr = null;
|
||||
try {
|
||||
await downResult;
|
||||
} catch (err) {
|
||||
downErr = err;
|
||||
} finally {
|
||||
should.ok(downErr, 'Migration down should error if child errors');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const Knex = require('knex');
|
||||
const ObjectId = require('bson-objectid').default;
|
||||
|
||||
async function setupDb() {
|
||||
const knex = Knex({
|
||||
client: 'sqlite',
|
||||
connection: {
|
||||
filename: ':memory:'
|
||||
},
|
||||
// Suppress warnings from knex
|
||||
useNullAsDefault: true
|
||||
});
|
||||
|
||||
await knex.raw(`
|
||||
CREATE TABLE \`permissions\` (
|
||||
\`id\` varchar(24) not null,
|
||||
\`name\` varchar(50) not null,
|
||||
\`object_type\` varchar(50) not null,
|
||||
\`action_type\` varchar(50) not null,
|
||||
\`object_id\` varchar(24) null,
|
||||
\`created_at\` datetime not null,
|
||||
\`created_by\` varchar(24) not null,
|
||||
\`updated_at\` datetime null,
|
||||
\`updated_by\` varchar(24) null,
|
||||
primary key (\`id\`)
|
||||
);
|
||||
CREATE UNIQUE INDEX \`permissions_name_unique\` on \`permissions\` (\`name\`);\`);
|
||||
`);
|
||||
|
||||
await knex.raw(`
|
||||
CREATE TABLE \`permissions_roles\` (
|
||||
\`id\` varchar(24) not null,
|
||||
\`role_id\` varchar(24) not null,
|
||||
\`permission_id\` varchar(24) not null,
|
||||
primary key (\`id\`)
|
||||
);
|
||||
`);
|
||||
|
||||
await knex.raw(`
|
||||
CREATE TABLE \`roles\` (
|
||||
\`id\` varchar(24) not null,
|
||||
\`name\` varchar(50) not null,
|
||||
\`description\` varchar(2000) null,
|
||||
\`created_at\` datetime not null,
|
||||
\`created_by\` varchar(24) not null,
|
||||
\`updated_at\` datetime null,
|
||||
\`updated_by\` varchar(24) null,
|
||||
primary key (\`id\`)
|
||||
);
|
||||
CREATE UNIQUE INDEX \`roles_name_unique\` on \`roles\` (\`name\`);
|
||||
`);
|
||||
|
||||
const date = knex.raw('CURRENT_TIMESTAMP');
|
||||
await knex('roles').insert({
|
||||
id: ObjectId.generate(),
|
||||
name: 'Role Name',
|
||||
description: 'Role description',
|
||||
created_at: date,
|
||||
created_by: utils.meta.MIGRATION_USER,
|
||||
updated_at: date,
|
||||
updated_by: utils.meta.MIGRATION_USER
|
||||
});
|
||||
|
||||
await knex('roles').insert({
|
||||
id: ObjectId.generate(),
|
||||
name: 'Other Role Name',
|
||||
description: 'Other Role description',
|
||||
created_at: date,
|
||||
created_by: utils.meta.MIGRATION_USER,
|
||||
updated_at: date,
|
||||
updated_by: utils.meta.MIGRATION_USER
|
||||
});
|
||||
|
||||
await knex('permissions').insert({
|
||||
id: ObjectId.generate(),
|
||||
name: 'Permission Name',
|
||||
action_type: 'action',
|
||||
object_type: 'object',
|
||||
created_at: date,
|
||||
created_by: utils.meta.MIGRATION_USER,
|
||||
updated_at: date,
|
||||
updated_by: utils.meta.MIGRATION_USER
|
||||
});
|
||||
|
||||
return knex;
|
||||
}
|
||||
|
||||
async function runUpMigration(knex, migration) {
|
||||
{
|
||||
const transacting = await knex.transaction();
|
||||
await migration.up({transacting});
|
||||
transacting.commit();
|
||||
}
|
||||
|
||||
return async function runDownMigration() {
|
||||
const transacting = await knex.transaction();
|
||||
await migration.down({transacting});
|
||||
transacting.commit();
|
||||
};
|
||||
}
|
||||
|
||||
describe('migrations/utils/permissions', function () {
|
||||
describe('addPermission', function () {
|
||||
it('Accepts a name, action and object and returns a migration which adds a permission to the database', async function () {
|
||||
const knex = await setupDb();
|
||||
|
||||
const migration = utils.addPermission({
|
||||
name: 'scarface',
|
||||
object: 'my little friend',
|
||||
action: 'say hello'
|
||||
});
|
||||
|
||||
should.ok(migration.config.transaction, 'addPermission creates a transactional migration');
|
||||
|
||||
const runDownMigration = await runUpMigration(knex, migration);
|
||||
|
||||
const allPermissionsAfterUp = await knex('permissions').select();
|
||||
const insertedPermissionsAfterUp = allPermissionsAfterUp.filter((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(insertedPermissionsAfterUp.length === 1, 'The permission was inserted into the database');
|
||||
|
||||
await runDownMigration();
|
||||
|
||||
const allPermissionsAfterDown = await knex('permissions').select();
|
||||
const insertedPermissionsAfterDown = allPermissionsAfterDown.filter((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(insertedPermissionsAfterDown.length === 0, 'The permission was removed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('addPermissionToRole', function () {
|
||||
it('Accepts a permisson name and role name and returns a migration which adds a permission to the database', async function () {
|
||||
const knex = await setupDb();
|
||||
|
||||
const migration = utils.addPermissionToRole({
|
||||
permission: 'Permission Name',
|
||||
role: 'Role Name'
|
||||
});
|
||||
|
||||
const runDownMigration = await runUpMigration(knex, migration);
|
||||
|
||||
const allPermissionsForRoleAfterUp = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Role Name';
|
||||
`);
|
||||
|
||||
const attachedPermissionAfterUp = allPermissionsForRoleAfterUp.find((row) => {
|
||||
return row.name === 'Permission Name';
|
||||
});
|
||||
|
||||
should.ok(attachedPermissionAfterUp, 'The permission was attached to the role.');
|
||||
|
||||
await runDownMigration();
|
||||
|
||||
const allPermissionsForRoleAfterDown = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Role Name';
|
||||
`);
|
||||
|
||||
const attachedPermissionAfterDown = allPermissionsForRoleAfterDown.find((row) => {
|
||||
return row.name === 'Permission Name';
|
||||
});
|
||||
|
||||
should.ok(!attachedPermissionAfterDown, 'The permission was removed from the role.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('addPermissionWithRoles', function () {
|
||||
it('Accepts addPermission config and a list of roles, and creates the permission, linking it to roles', async function () {
|
||||
const knex = await setupDb();
|
||||
|
||||
const migration = utils.addPermissionWithRoles({
|
||||
name: 'scarface',
|
||||
object: 'my little friend',
|
||||
action: 'say hello'
|
||||
}, [
|
||||
'Role Name',
|
||||
'Other Role Name'
|
||||
]);
|
||||
|
||||
const runDownMigration = await runUpMigration(knex, migration);
|
||||
|
||||
const allPermissionsAfterUp = await knex('permissions').select();
|
||||
const insertedPermissionsAfterUp = allPermissionsAfterUp.filter((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(insertedPermissionsAfterUp.length === 1, 'The permission was inserted into the database');
|
||||
|
||||
const allPermissionsForRoleAfterUp = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Role Name';
|
||||
`);
|
||||
|
||||
const permissionAttachedToRoleAfterUp = allPermissionsForRoleAfterUp.find((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(permissionAttachedToRoleAfterUp, 'The permission was attached to the role.');
|
||||
|
||||
const allPermissionsForOtherRoleAfterUp = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Other Role Name';
|
||||
`);
|
||||
|
||||
const permissionAttachedToOtherRoleAfterUp = allPermissionsForRoleAfterUp.find((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(permissionAttachedToOtherRoleAfterUp, 'The permission was attached to the other role.');
|
||||
|
||||
await runDownMigration();
|
||||
|
||||
const allPermissionsAfterDown = await knex('permissions').select();
|
||||
const insertedPermissionsAfterDown = allPermissionsAfterDown.filter((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(insertedPermissionsAfterDown.length === 0, 'The permission was removed from the database');
|
||||
|
||||
const allPermissionsForRoleAfterDown = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Role Name';
|
||||
`);
|
||||
|
||||
const permissionAttachedToRoleAfterDown = allPermissionsForRoleAfterDown.find((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(!permissionAttachedToRoleAfterDown, 'The permission was removed from the role.');
|
||||
|
||||
const allPermissionsForOtherRoleAfterDown = await knex.raw(`
|
||||
SELECT
|
||||
p.name
|
||||
FROM
|
||||
permissions p
|
||||
INNER JOIN
|
||||
permissions_roles pr
|
||||
ON
|
||||
pr.permission_id = p.id
|
||||
INNER JOIN
|
||||
roles r
|
||||
ON
|
||||
pr.role_id = r.id
|
||||
WHERE
|
||||
r.name = 'Other Role Name';
|
||||
`);
|
||||
|
||||
const permissionAttachedToOtherRoleAfterDown = allPermissionsForOtherRoleAfterDown.find((row) => {
|
||||
return row.name === 'scarface';
|
||||
});
|
||||
|
||||
should.ok(!permissionAttachedToOtherRoleAfterDown, 'The permission was removed from the other role.');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue