From 9616e8e5519cc59ca7dabd286a4d97190eecdb9c Mon Sep 17 00:00:00 2001 From: melohagan <101575380+melohagan@users.noreply.github.com> Date: Thu, 26 Oct 2023 16:28:12 +0100 Subject: [PATCH] Custom role navigation links (#12056) * Refactor routing unit tests * Filter out higher level roles in preview * unit test * Refactor --------- Co-authored-by: Michael Drury --- packages/server/src/api/controllers/role.ts | 24 +++++++++++++++++- .../server/src/api/routes/tests/role.spec.js | 20 +++++++++++++++ .../src/api/routes/tests/routing.spec.js | 25 ++++++++----------- packages/server/src/constants/screens.ts | 14 ++++++++--- .../server/src/tests/utilities/structures.ts | 19 ++++++++++++-- 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/packages/server/src/api/controllers/role.ts b/packages/server/src/api/controllers/role.ts index ed23009706..3697bbe925 100644 --- a/packages/server/src/api/controllers/role.ts +++ b/packages/server/src/api/controllers/role.ts @@ -1,4 +1,10 @@ -import { context, db as dbCore, events, roles } from "@budibase/backend-core" +import { + context, + db as dbCore, + events, + roles, + Header, +} from "@budibase/backend-core" import { getUserMetadataParams, InternalTables } from "../../db/utils" import { Database, Role, UserCtx, UserRoles } from "@budibase/types" import { sdk as sharedSdk } from "@budibase/shared-core" @@ -143,4 +149,20 @@ export async function accessible(ctx: UserCtx) { } else { ctx.body = await roles.getUserRoleIdHierarchy(roleId!) } + + // If a custom role is provided in the header, filter out higher level roles + const roleHeader = ctx.header?.[Header.PREVIEW_ROLE] as string + if (roleHeader && !Object.keys(roles.BUILTIN_ROLE_IDS).includes(roleHeader)) { + const inherits = (await roles.getRole(roleHeader))?.inherits + const orderedRoles = ctx.body.reverse() + let filteredRoles = [roleHeader] + for (let role of orderedRoles) { + filteredRoles = [role, ...filteredRoles] + if (role === inherits) { + break + } + } + filteredRoles.pop() + ctx.body = [roleHeader, ...filteredRoles] + } } diff --git a/packages/server/src/api/routes/tests/role.spec.js b/packages/server/src/api/routes/tests/role.spec.js index c8e383d5ed..d133a69d64 100644 --- a/packages/server/src/api/routes/tests/role.spec.js +++ b/packages/server/src/api/routes/tests/role.spec.js @@ -158,5 +158,25 @@ describe("/roles", () => { expect(res.body.length).toBe(1) expect(res.body[0]).toBe("PUBLIC") }) + + it("should not fetch higher level accessible roles when a custom role header is provided", async () => { + await createRole({ + name: `CUSTOM_ROLE`, + inherits: roles.BUILTIN_ROLE_IDS.BASIC, + permissionId: permissions.BuiltinPermissionID.READ_ONLY, + version: "name", + }) + const res = await request + .get("/api/roles/accessible") + .set({ + ...config.defaultHeaders(), + "x-budibase-role": "CUSTOM_ROLE" + }) + .expect(200) + expect(res.body.length).toBe(3) + expect(res.body[0]).toBe("CUSTOM_ROLE") + expect(res.body[1]).toBe("BASIC") + expect(res.body[2]).toBe("PUBLIC") + }) }) }) diff --git a/packages/server/src/api/routes/tests/routing.spec.js b/packages/server/src/api/routes/tests/routing.spec.js index ff6d7aba1d..4076f4879c 100644 --- a/packages/server/src/api/routes/tests/routing.spec.js +++ b/packages/server/src/api/routes/tests/routing.spec.js @@ -1,5 +1,5 @@ const setup = require("./utilities") -const { basicScreen } = setup.structures +const { basicScreen, powerScreen } = setup.structures const { checkBuilderEndpoint, runInProd } = require("./utilities/TestFunctions") const { roles } = require("@budibase/backend-core") const { BUILTIN_ROLE_IDS } = roles @@ -12,19 +12,14 @@ const route = "/test" describe("/routing", () => { let request = setup.getRequest() let config = setup.getConfig() - let screen, screen2 + let basic, power afterAll(setup.afterAll) beforeAll(async () => { await config.init() - screen = basicScreen() - screen.routing.route = route - screen = await config.createScreen(screen) - screen2 = basicScreen() - screen2.routing.roleId = BUILTIN_ROLE_IDS.POWER - screen2.routing.route = route - screen2 = await config.createScreen(screen2) + basic = await config.createScreen(basicScreen(route)) + power = await config.createScreen(powerScreen(route)) await config.publish() }) @@ -61,8 +56,8 @@ describe("/routing", () => { expect(res.body.routes[route]).toEqual({ subpaths: { [route]: { - screenId: screen._id, - roleId: screen.routing.roleId + screenId: basic._id, + roleId: basic.routing.roleId } } }) @@ -80,8 +75,8 @@ describe("/routing", () => { expect(res.body.routes[route]).toEqual({ subpaths: { [route]: { - screenId: screen2._id, - roleId: screen2.routing.roleId + screenId: power._id, + roleId: power.routing.roleId } } }) @@ -101,8 +96,8 @@ describe("/routing", () => { expect(res.body.routes).toBeDefined() expect(res.body.routes[route].subpaths[route]).toBeDefined() const subpath = res.body.routes[route].subpaths[route] - expect(subpath.screens[screen2.routing.roleId]).toEqual(screen2._id) - expect(subpath.screens[screen.routing.roleId]).toEqual(screen._id) + expect(subpath.screens[power.routing.roleId]).toEqual(power._id) + expect(subpath.screens[basic.routing.roleId]).toEqual(basic._id) }) it("make sure it is a builder only endpoint", async () => { diff --git a/packages/server/src/constants/screens.ts b/packages/server/src/constants/screens.ts index 23e36a65b8..6c88b0f957 100644 --- a/packages/server/src/constants/screens.ts +++ b/packages/server/src/constants/screens.ts @@ -1,7 +1,15 @@ import { roles } from "@budibase/backend-core" import { BASE_LAYOUT_PROP_IDS } from "./layouts" -export function createHomeScreen() { +export function createHomeScreen( + config: { + roleId: string + route: string + } = { + roleId: roles.BUILTIN_ROLE_IDS.BASIC, + route: "/", + } +) { return { description: "", url: "", @@ -40,8 +48,8 @@ export function createHomeScreen() { gap: "M", }, routing: { - route: "/", - roleId: roles.BUILTIN_ROLE_IDS.BASIC, + route: config.route, + roleId: config.roleId, }, name: "home-screen", } diff --git a/packages/server/src/tests/utilities/structures.ts b/packages/server/src/tests/utilities/structures.ts index d3e92ea34d..6d236062a8 100644 --- a/packages/server/src/tests/utilities/structures.ts +++ b/packages/server/src/tests/utilities/structures.ts @@ -20,6 +20,7 @@ import { SourceName, Table, } from "@budibase/types" +const { BUILTIN_ROLE_IDS } = roles export function basicTable(): Table { return { @@ -322,8 +323,22 @@ export function basicUser(role: string) { } } -export function basicScreen() { - return createHomeScreen() +export function basicScreen(route: string = "/") { + return createHomeScreen({ + roleId: BUILTIN_ROLE_IDS.BASIC, + route, + }) +} + +export function powerScreen(route: string = "/") { + return createHomeScreen({ + roleId: BUILTIN_ROLE_IDS.POWER, + route, + }) +} + +export function customScreen(config: { roleId: string; route: string }) { + return createHomeScreen(config) } export function basicLayout() {