Adding test case for new endpoint and covering public, builder and normal roles.
This commit is contained in:
parent
bb2892cbc2
commit
e916178046
|
@ -253,7 +253,10 @@ export function checkForRoleResourceArray(
|
||||||
* Given an app ID this will retrieve all of the roles that are currently within that app.
|
* Given an app ID this will retrieve all of the roles that are currently within that app.
|
||||||
* @return {Promise<object[]>} An array of the role objects that were found.
|
* @return {Promise<object[]>} An array of the role objects that were found.
|
||||||
*/
|
*/
|
||||||
export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
|
export async function getAllRoles(
|
||||||
|
appId?: string,
|
||||||
|
opts?: { idOnly: boolean }
|
||||||
|
): Promise<RoleDoc[]> {
|
||||||
if (appId) {
|
if (appId) {
|
||||||
return doWithDB(appId, internal)
|
return doWithDB(appId, internal)
|
||||||
} else {
|
} else {
|
||||||
|
@ -308,7 +311,7 @@ export async function getAllRoles(appId?: string): Promise<RoleDoc[]> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return roles
|
return opts?.idOnly ? roles.map(role => role._id) : roles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,14 @@
|
||||||
import { Heading, Icon, clickOutside } from "@budibase/bbui"
|
import { Heading, Icon, clickOutside } from "@budibase/bbui"
|
||||||
import { FieldTypes } from "constants"
|
import { FieldTypes } from "constants"
|
||||||
import active from "svelte-spa-router/active"
|
import active from "svelte-spa-router/active"
|
||||||
import { RoleUtils } from "@budibase/frontend-core"
|
|
||||||
|
|
||||||
const sdk = getContext("sdk")
|
const sdk = getContext("sdk")
|
||||||
const {
|
const {
|
||||||
routeStore,
|
routeStore,
|
||||||
|
roleStore,
|
||||||
styleable,
|
styleable,
|
||||||
linkable,
|
linkable,
|
||||||
builderStore,
|
builderStore,
|
||||||
currentRole,
|
|
||||||
sidePanelStore,
|
sidePanelStore,
|
||||||
} = sdk
|
} = sdk
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
@ -61,7 +60,8 @@
|
||||||
})
|
})
|
||||||
setContext("layout", store)
|
setContext("layout", store)
|
||||||
|
|
||||||
$: validLinks = getValidLinks(links, $currentRole)
|
$: accessibleRoles = $roleStore
|
||||||
|
$: validLinks = getValidLinks(links)
|
||||||
$: typeClass = NavigationClasses[navigation] || NavigationClasses.None
|
$: typeClass = NavigationClasses[navigation] || NavigationClasses.None
|
||||||
$: navWidthClass = WidthClasses[navWidth || width] || WidthClasses.Large
|
$: navWidthClass = WidthClasses[navWidth || width] || WidthClasses.Large
|
||||||
$: pageWidthClass = WidthClasses[pageWidth || width] || WidthClasses.Large
|
$: pageWidthClass = WidthClasses[pageWidth || width] || WidthClasses.Large
|
||||||
|
@ -99,14 +99,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getValidLinks = (allLinks, role) => {
|
const getValidLinks = allLinks => {
|
||||||
// Strip links missing required info
|
// Strip links missing required info
|
||||||
let validLinks = (allLinks || []).filter(link => link.text && link.url)
|
let validLinks = (allLinks || []).filter(link => link.text && link.url)
|
||||||
|
|
||||||
// Filter to only links allowed by the current role
|
// Filter to only links allowed by the current role
|
||||||
const priority = RoleUtils.getRolePriority(role)
|
|
||||||
return validLinks.filter(link => {
|
return validLinks.filter(link => {
|
||||||
return !link.roleId || RoleUtils.getRolePriority(link.roleId) <= priority
|
return accessibleRoles?.find(roleId => roleId === link.roleId)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
sidePanelStore,
|
sidePanelStore,
|
||||||
dndIsDragging,
|
dndIsDragging,
|
||||||
confirmationStore,
|
confirmationStore,
|
||||||
|
roleStore,
|
||||||
} from "stores"
|
} from "stores"
|
||||||
import { styleable } from "utils/styleable"
|
import { styleable } from "utils/styleable"
|
||||||
import { linkable } from "utils/linkable"
|
import { linkable } from "utils/linkable"
|
||||||
|
@ -39,6 +40,7 @@ export default {
|
||||||
dndIsDragging,
|
dndIsDragging,
|
||||||
currentRole,
|
currentRole,
|
||||||
confirmationStore,
|
confirmationStore,
|
||||||
|
roleStore,
|
||||||
styleable,
|
styleable,
|
||||||
linkable,
|
linkable,
|
||||||
getAction,
|
getAction,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { context, db as dbCore, events, roles } from "@budibase/backend-core"
|
import { context, db as dbCore, events, roles } from "@budibase/backend-core"
|
||||||
import { getUserMetadataParams, InternalTables } from "../../db/utils"
|
import { getUserMetadataParams, InternalTables } from "../../db/utils"
|
||||||
import { Database, Role, UserCtx, UserRoles } from "@budibase/types"
|
import { Database, Role, UserCtx, UserRoles } from "@budibase/types"
|
||||||
|
import { sdk as sharedSdk } from "@budibase/shared-core"
|
||||||
import sdk from "../../sdk"
|
import sdk from "../../sdk"
|
||||||
|
|
||||||
const UpdateRolesOptions = {
|
const UpdateRolesOptions = {
|
||||||
|
@ -128,12 +129,18 @@ export async function destroy(ctx: UserCtx) {
|
||||||
role.version
|
role.version
|
||||||
)
|
)
|
||||||
ctx.message = `Role ${ctx.params.roleId} deleted successfully`
|
ctx.message = `Role ${ctx.params.roleId} deleted successfully`
|
||||||
|
ctx.status = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function accessible(ctx: UserCtx) {
|
export async function accessible(ctx: UserCtx) {
|
||||||
const user = ctx.user
|
let roleId = ctx.user?.roleId
|
||||||
if (!user || !user.roleId) {
|
if (!roleId) {
|
||||||
ctx.throw(400, "User does not have a valid role")
|
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||||
|
}
|
||||||
|
if (ctx.user && sharedSdk.users.isAdminOrBuilder(ctx.user)) {
|
||||||
|
const appId = context.getAppId()
|
||||||
|
ctx.body = await roles.getAllRoles(appId, { idOnly: true })
|
||||||
|
} else {
|
||||||
|
ctx.body = await roles.getUserRoleHierarchy(roleId!, { idOnly: true })
|
||||||
}
|
}
|
||||||
ctx.body = await roles.getUserRoleHierarchy(user.roleId!)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,8 +199,9 @@ export const serveBuilderPreview = async function (ctx: any) {
|
||||||
|
|
||||||
export const serveClientLibrary = async function (ctx: any) {
|
export const serveClientLibrary = async function (ctx: any) {
|
||||||
let rootPath = join(NODE_MODULES_PATH, "@budibase", "client", "dist")
|
let rootPath = join(NODE_MODULES_PATH, "@budibase", "client", "dist")
|
||||||
if (!fs.existsSync(rootPath)) {
|
// incase running from TS directly
|
||||||
rootPath = join(__dirname, "..", "..", "..", "..", "client")
|
if (env.isDev() && !fs.existsSync(rootPath)) {
|
||||||
|
rootPath = join(require.resolve("@budibase/client"), "..")
|
||||||
}
|
}
|
||||||
return send(ctx, "budibase-client.js", {
|
return send(ctx, "budibase-client.js", {
|
||||||
root: rootPath,
|
root: rootPath,
|
||||||
|
|
|
@ -3,17 +3,13 @@ import * as controller from "../controllers/role"
|
||||||
import authorized from "../../middleware/authorized"
|
import authorized from "../../middleware/authorized"
|
||||||
import { permissions } from "@budibase/backend-core"
|
import { permissions } from "@budibase/backend-core"
|
||||||
import { roleValidator } from "./utils/validators"
|
import { roleValidator } from "./utils/validators"
|
||||||
import { PermissionLevel, PermissionType } from "@budibase/types"
|
|
||||||
|
|
||||||
const router: Router = new Router()
|
const router: Router = new Router()
|
||||||
|
|
||||||
router
|
router
|
||||||
// retrieve a list of the roles a user can access
|
// retrieve a list of the roles a user can access
|
||||||
.get(
|
// needs to be public for public screens
|
||||||
"/api/roles/accessible",
|
.get("/api/roles/accessible", controller.accessible)
|
||||||
authorized(PermissionType.APP, PermissionLevel.READ),
|
|
||||||
controller.accessible
|
|
||||||
)
|
|
||||||
.post(
|
.post(
|
||||||
"/api/roles",
|
"/api/roles",
|
||||||
authorized(permissions.BUILDER),
|
authorized(permissions.BUILDER),
|
||||||
|
|
|
@ -15,7 +15,7 @@ describe("/roles", () => {
|
||||||
await config.init()
|
await config.init()
|
||||||
})
|
})
|
||||||
|
|
||||||
const createRole = async (role) => {
|
const createRole = async role => {
|
||||||
if (!role) {
|
if (!role) {
|
||||||
role = basicRole()
|
role = basicRole()
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,6 @@ describe("/roles", () => {
|
||||||
const role = basicRole()
|
const role = basicRole()
|
||||||
const res = await createRole(role)
|
const res = await createRole(role)
|
||||||
|
|
||||||
expect(res.res.statusMessage).toEqual(
|
|
||||||
`Role '${role.name}' created successfully.`
|
|
||||||
)
|
|
||||||
expect(res.body._id).toBeDefined()
|
expect(res.body._id).toBeDefined()
|
||||||
expect(res.body._rev).toBeDefined()
|
expect(res.body._rev).toBeDefined()
|
||||||
expect(events.role.updated).not.toBeCalled()
|
expect(events.role.updated).not.toBeCalled()
|
||||||
|
@ -51,9 +48,6 @@ describe("/roles", () => {
|
||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
res = await createRole(res.body)
|
res = await createRole(res.body)
|
||||||
|
|
||||||
expect(res.res.statusMessage).toEqual(
|
|
||||||
`Role '${role.name}' created successfully.`
|
|
||||||
)
|
|
||||||
expect(res.body._id).toBeDefined()
|
expect(res.body._id).toBeDefined()
|
||||||
expect(res.body._rev).toBeDefined()
|
expect(res.body._rev).toBeDefined()
|
||||||
expect(events.role.created).not.toBeCalled()
|
expect(events.role.created).not.toBeCalled()
|
||||||
|
@ -99,7 +93,11 @@ describe("/roles", () => {
|
||||||
|
|
||||||
it("should be able to get the role with a permission added", async () => {
|
it("should be able to get the role with a permission added", async () => {
|
||||||
const table = await config.createTable()
|
const table = await config.createTable()
|
||||||
await config.api.permission.set({ roleId: BUILTIN_ROLE_IDS.POWER, resourceId: table._id, level: PermissionLevel.READ })
|
await config.api.permission.set({
|
||||||
|
roleId: BUILTIN_ROLE_IDS.POWER,
|
||||||
|
resourceId: table._id,
|
||||||
|
level: PermissionLevel.READ,
|
||||||
|
})
|
||||||
const res = await request
|
const res = await request
|
||||||
.get(`/api/roles`)
|
.get(`/api/roles`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
|
@ -131,4 +129,34 @@ describe("/roles", () => {
|
||||||
expect(events.role.deleted).toBeCalledWith(customRole)
|
expect(events.role.deleted).toBeCalledWith(customRole)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("accessible", () => {
|
||||||
|
it("should be able to fetch accessible roles (with builder)", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get("/api/roles/accessible")
|
||||||
|
.set(config.defaultHeaders())
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.length).toBe(5)
|
||||||
|
expect(typeof res.body[0]).toBe("string")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to fetch accessible roles (basic user)", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get("/api/roles/accessible")
|
||||||
|
.set(await config.basicRoleHeaders())
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.length).toBe(2)
|
||||||
|
expect(res.body[0]).toBe("BASIC")
|
||||||
|
expect(res.body[1]).toBe("PUBLIC")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should be able to fetch accessible roles (no user)", async () => {
|
||||||
|
const res = await request
|
||||||
|
.get("/api/roles/accessible")
|
||||||
|
.set(config.publicHeaders())
|
||||||
|
.expect(200)
|
||||||
|
expect(res.body.length).toBe(1)
|
||||||
|
expect(res.body[0]).toBe("PUBLIC")
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -425,6 +425,15 @@ class TestConfiguration {
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async basicRoleHeaders() {
|
||||||
|
return await this.roleHeaders({
|
||||||
|
email: this.defaultUserValues.email,
|
||||||
|
builder: false,
|
||||||
|
prodApp: true,
|
||||||
|
roleId: roles.BUILTIN_ROLE_IDS.BASIC,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async roleHeaders({
|
async roleHeaders({
|
||||||
email = this.defaultUserValues.email,
|
email = this.defaultUserValues.email,
|
||||||
roleId = roles.BUILTIN_ROLE_IDS.ADMIN,
|
roleId = roles.BUILTIN_ROLE_IDS.ADMIN,
|
||||||
|
|
Loading…
Reference in New Issue