From 3339f364b63b2328a1b038f037ff2a9e3044d826 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 7 Dec 2020 15:21:06 +0000 Subject: [PATCH] Updating role constraints and making sure roles can't be deleted if they are in use. --- packages/server/src/api/controllers/role.js | 57 ++++++++++++++++++++- packages/server/src/api/controllers/user.js | 2 +- packages/server/src/db/utils.js | 6 +-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/controllers/role.js b/packages/server/src/api/controllers/role.js index cbe55bc5d6..f20ca26dd7 100644 --- a/packages/server/src/api/controllers/role.js +++ b/packages/server/src/api/controllers/role.js @@ -4,7 +4,40 @@ const { Role, getRole, } = require("../../utilities/security/roles") -const { generateRoleID, getRoleParams } = require("../../db/utils") +const { + generateRoleID, + getRoleParams, + getUserParams, + ViewNames, +} = require("../../db/utils") + +const UpdateRolesOptions = { + CREATED: "created", + REMOVED: "removed", +} + +async function updateRolesOnUserTable(db, roleId, updateOption) { + const table = await db.get(ViewNames.USERS) + const schema = table.schema + const remove = updateOption === UpdateRolesOptions.REMOVED + let updated = false + for (let prop of Object.keys(schema)) { + if (prop === "roleId") { + updated = true + const constraints = schema[prop].constraints + const indexOf = constraints.inclusion.indexOf(roleId) + if (remove && indexOf !== -1) { + constraints.inclusion.splice(indexOf, 1) + } else if (!remove && indexOf === -1) { + constraints.inclusion.push(roleId) + } + break + } + } + if (updated) { + await db.put(table) + } +} exports.fetch = async function(ctx) { const db = new CouchDB(ctx.user.appId) @@ -42,6 +75,7 @@ exports.save = async function(ctx) { role._rev = ctx.request.body._rev } const result = await db.put(role) + await updateRolesOnUserTable(db, _id, UpdateRolesOptions.CREATED) role._rev = result.rev ctx.body = role ctx.message = `Role '${role.name}' created successfully.` @@ -49,7 +83,26 @@ exports.save = async function(ctx) { exports.destroy = async function(ctx) { const db = new CouchDB(ctx.user.appId) - await db.remove(ctx.params.roleId, ctx.params.rev) + const roleId = ctx.params.roleId + // first check no users actively attached to role + const users = ( + await db.allDocs( + getUserParams(null, { + include_docs: true, + }) + ) + ).rows.map(row => row.doc) + const usersWithRole = users.filter(user => user.roleId === roleId) + if (usersWithRole.length !== 0) { + ctx.throw("Cannot delete role when it is in use.") + } + + await db.remove(roleId, ctx.params.rev) + await updateRolesOnUserTable( + db, + ctx.params.roleId, + UpdateRolesOptions.REMOVED + ) ctx.message = `Role ${ctx.params.roleId} deleted successfully` ctx.status = 200 } diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index bea62ecbd5..bf56e6b181 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -6,7 +6,7 @@ const { getRole } = require("../../utilities/security/roles") exports.fetch = async function(ctx) { const database = new CouchDB(ctx.user.appId) const data = await database.allDocs( - getUserParams("", { + getUserParams(null, { include_docs: true, }) ) diff --git a/packages/server/src/db/utils.js b/packages/server/src/db/utils.js index 1989633463..5dc0161228 100644 --- a/packages/server/src/db/utils.js +++ b/packages/server/src/db/utils.js @@ -102,11 +102,7 @@ exports.generateRowID = tableId => { * Gets parameters for retrieving users, this is a utility function for the getDocParams function. */ exports.getUserParams = (username = "", otherProps = {}) => { - return getDocParams( - DocumentTypes.ROW, - `${ViewNames.USERS}${SEPARATOR}${DocumentTypes.USER}${SEPARATOR}${username}`, - otherProps - ) + return exports.getRowParams(ViewNames.USERS, username, otherProps) } /**