Merge branch 'master' into view-calculation-no-deletes

This commit is contained in:
Sam Rose 2024-10-09 17:09:03 +01:00 committed by GitHub
commit cc07b1407b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 354 additions and 189 deletions

View File

@ -65,7 +65,13 @@ export enum BuiltinPermissionID {
POWER = "power", POWER = "power",
} }
export const BUILTIN_PERMISSIONS = { export const BUILTIN_PERMISSIONS: {
[key in keyof typeof BuiltinPermissionID]: {
_id: (typeof BuiltinPermissionID)[key]
name: string
permissions: Permission[]
}
} = {
PUBLIC: { PUBLIC: {
_id: BuiltinPermissionID.PUBLIC, _id: BuiltinPermissionID.PUBLIC,
name: "Public", name: "Public",

View File

@ -94,7 +94,7 @@
loadDependantInfo() loadDependantInfo()
</script> </script>
<ModalContent showCancelButton={false} confirmText="Done"> <ModalContent showCancelButton={false} showConfirmButton={false}>
<span slot="header"> <span slot="header">
Manage Access Manage Access
{#if requiresPlanToModify} {#if requiresPlanToModify}

View File

@ -1,7 +1,6 @@
import { permissions, roles, context } from "@budibase/backend-core" import { permissions, roles, context } from "@budibase/backend-core"
import { import {
UserCtx, UserCtx,
Role,
GetResourcePermsResponse, GetResourcePermsResponse,
ResourcePermissionInfo, ResourcePermissionInfo,
GetDependantResourcesResponse, GetDependantResourcesResponse,
@ -9,6 +8,7 @@ import {
AddPermissionRequest, AddPermissionRequest,
RemovePermissionRequest, RemovePermissionRequest,
RemovePermissionResponse, RemovePermissionResponse,
FetchResourcePermissionInfoResponse,
} from "@budibase/types" } from "@budibase/types"
import { import {
CURRENTLY_SUPPORTED_LEVELS, CURRENTLY_SUPPORTED_LEVELS,
@ -28,10 +28,12 @@ export function fetchLevels(ctx: UserCtx) {
ctx.body = SUPPORTED_LEVELS ctx.body = SUPPORTED_LEVELS
} }
export async function fetch(ctx: UserCtx) { export async function fetch(
ctx: UserCtx<void, FetchResourcePermissionInfoResponse>
) {
const db = context.getAppDB() const db = context.getAppDB()
const dbRoles: Role[] = await sdk.permissions.getAllDBRoles(db) const dbRoles = await sdk.permissions.getAllDBRoles(db)
let permissions: any = {} let permissions: Record<string, Record<string, string>> = {}
// create an object with structure role ID -> resource ID -> level // create an object with structure role ID -> resource ID -> level
for (let role of dbRoles) { for (let role of dbRoles) {
if (!role.permissions) { if (!role.permissions) {
@ -43,13 +45,13 @@ export async function fetch(ctx: UserCtx) {
} }
for (let [resource, levelArr] of Object.entries(role.permissions)) { for (let [resource, levelArr] of Object.entries(role.permissions)) {
const levels: string[] = Array.isArray(levelArr) ? levelArr : [levelArr] const levels: string[] = Array.isArray(levelArr) ? levelArr : [levelArr]
const perms: Record<string, string> = {} const perms: Record<string, string> = permissions[resource] || {}
levels.forEach(level => (perms[level] = roleId!)) levels.forEach(level => (perms[level] = roleId!))
permissions[resource] = perms permissions[resource] = perms
} }
} }
// apply the base permissions // apply the base permissions
const finalPermissions: Record<string, Record<string, string>> = {} const finalPermissions: FetchResourcePermissionInfoResponse = {}
for (let [resource, permission] of Object.entries(permissions)) { for (let [resource, permission] of Object.entries(permissions)) {
const basePerms = getBasePermissions(resource) const basePerms = getBasePermissions(resource)
finalPermissions[resource] = Object.assign(basePerms, permission) finalPermissions[resource] = Object.assign(basePerms, permission)
@ -92,18 +94,17 @@ export async function getDependantResources(
export async function addPermission(ctx: UserCtx<void, AddPermissionResponse>) { export async function addPermission(ctx: UserCtx<void, AddPermissionResponse>) {
const params: AddPermissionRequest = ctx.params const params: AddPermissionRequest = ctx.params
ctx.body = await sdk.permissions.updatePermissionOnRole( await sdk.permissions.updatePermissionOnRole(params, PermissionUpdateType.ADD)
params, ctx.status = 200
PermissionUpdateType.ADD
)
} }
export async function removePermission( export async function removePermission(
ctx: UserCtx<void, RemovePermissionResponse> ctx: UserCtx<void, RemovePermissionResponse>
) { ) {
const params: RemovePermissionRequest = ctx.params const params: RemovePermissionRequest = ctx.params
ctx.body = await sdk.permissions.updatePermissionOnRole( await sdk.permissions.updatePermissionOnRole(
params, params,
PermissionUpdateType.REMOVE PermissionUpdateType.REMOVE
) )
ctx.status = 200
} }

View File

@ -1,5 +1,5 @@
import { roles } from "@budibase/backend-core" import { roles } from "@budibase/backend-core"
import { Document, PermissionLevel, Row, Table, ViewV2 } from "@budibase/types" import { Document, PermissionLevel, Row } from "@budibase/types"
import * as setup from "./utilities" import * as setup from "./utilities"
import { generator, mocks } from "@budibase/backend-core/tests" import { generator, mocks } from "@budibase/backend-core/tests"
@ -9,13 +9,11 @@ const { BUILTIN_ROLE_IDS } = roles
const HIGHER_ROLE_ID = BUILTIN_ROLE_IDS.BASIC const HIGHER_ROLE_ID = BUILTIN_ROLE_IDS.BASIC
const STD_ROLE_ID = BUILTIN_ROLE_IDS.PUBLIC const STD_ROLE_ID = BUILTIN_ROLE_IDS.PUBLIC
const DEFAULT_TABLE_ROLE_ID = BUILTIN_ROLE_IDS.ADMIN
describe("/permission", () => { describe("/permission", () => {
let request = setup.getRequest() let request = setup.getRequest()
let config = setup.getConfig() let config = setup.getConfig()
let table: Table & { _id: string }
let perms: Document[]
let row: Row
let view: ViewV2
afterAll(setup.afterAll) afterAll(setup.afterAll)
@ -25,18 +23,6 @@ describe("/permission", () => {
beforeEach(async () => { beforeEach(async () => {
mocks.licenses.useCloudFree() mocks.licenses.useCloudFree()
table = (await config.createTable()) as typeof table
row = await config.createRow()
view = await config.api.viewV2.create({
tableId: table._id!,
name: generator.guid(),
})
perms = await config.api.permission.add({
roleId: STD_ROLE_ID,
resourceId: table._id,
level: PermissionLevel.READ,
})
}) })
describe("levels", () => { describe("levels", () => {
@ -54,137 +40,251 @@ describe("/permission", () => {
}) })
}) })
describe("add", () => { describe("table permissions", () => {
it("should be able to add permission to a role for the table", async () => { let tableId: string
expect(perms.length).toEqual(1)
expect(perms[0]._id).toEqual(`${STD_ROLE_ID}`)
})
it("should get the resource permissions", async () => { beforeEach(async () => {
const res = await request const table = await config.createTable()
.get(`/api/permission/${table._id}`) tableId = table._id!
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body).toEqual({
permissions: {
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
write: { permissionType: "BASE", role: HIGHER_ROLE_ID },
},
})
})
it("should get resource permissions with multiple roles", async () => {
perms = await config.api.permission.add({
roleId: HIGHER_ROLE_ID,
resourceId: table._id,
level: PermissionLevel.WRITE,
})
const res = await config.api.permission.get(table._id)
expect(res).toEqual({
permissions: {
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
write: { permissionType: "EXPLICIT", role: HIGHER_ROLE_ID },
},
})
const allRes = await request
.get(`/api/permission`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(allRes.body[table._id]["read"]).toEqual(STD_ROLE_ID)
expect(allRes.body[table._id]["write"]).toEqual(HIGHER_ROLE_ID)
})
})
describe("remove", () => {
it("should be able to remove the permission", async () => {
const res = await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: table._id,
level: PermissionLevel.READ,
})
expect(res[0]._id).toEqual(STD_ROLE_ID)
const permsRes = await config.api.permission.get(table._id)
expect(permsRes.permissions[STD_ROLE_ID]).toBeUndefined()
})
})
describe("check public user allowed", () => {
it("should be able to read the row", async () => {
// replicate changes before checking permissions
await config.publish()
const res = await request
.get(`/api/${table._id}/rows`)
.set(config.publicHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body[0]._id).toEqual(row._id)
})
it("should be able to access the view data when the table is set to public and with no view permissions overrides", async () => {
// Make view inherit table permissions. Needed for backwards compatibility with existing views.
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: view.id,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
const res = await config.api.viewV2.publicSearch(view.id)
expect(res.rows[0]._id).toEqual(row._id)
})
it("should not be able to access the view data when the table is not public and there are no view permissions overrides", async () => {
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: table._id,
level: PermissionLevel.READ,
})
// Make view inherit table permissions. Needed for backwards compatibility with existing views.
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: view.id,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
await config.api.viewV2.publicSearch(view.id, undefined, { status: 401 })
})
it("should use the view permissions", async () => {
await config.api.permission.add({ await config.api.permission.add({
roleId: STD_ROLE_ID, roleId: STD_ROLE_ID,
resourceId: view.id, resourceId: tableId,
level: PermissionLevel.READ, level: PermissionLevel.READ,
}) })
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: table._id,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
const res = await config.api.viewV2.publicSearch(view.id)
expect(res.rows[0]._id).toEqual(row._id)
}) })
it("shouldn't allow writing from a public user", async () => { it("tables should be defaulted to admin", async () => {
const res = await request const table = await config.createTable()
.post(`/api/${table._id}/rows`) const { permissions } = await config.api.permission.get(table._id!)
.send(basicRow(table._id)) expect(permissions).toEqual({
.set(config.publicHeaders()) read: {
.expect("Content-Type", /json/) permissionType: "EXPLICIT",
.expect(401) role: DEFAULT_TABLE_ROLE_ID,
expect(res.status).toEqual(401) },
write: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
},
})
})
describe("add", () => {
it("should be able to add permission to a role for the table", async () => {
const res = await request
.get(`/api/permission/${tableId}`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body).toEqual({
permissions: {
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
write: { permissionType: "EXPLICIT", role: DEFAULT_TABLE_ROLE_ID },
},
})
})
it("should get resource permissions with multiple roles", async () => {
await config.api.permission.add({
roleId: HIGHER_ROLE_ID,
resourceId: tableId,
level: PermissionLevel.WRITE,
})
const res = await config.api.permission.get(tableId)
expect(res).toEqual({
permissions: {
read: { permissionType: "EXPLICIT", role: STD_ROLE_ID },
write: { permissionType: "EXPLICIT", role: HIGHER_ROLE_ID },
},
})
const allRes = await request
.get(`/api/permission`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(allRes.body[tableId]["read"]).toEqual(STD_ROLE_ID)
expect(allRes.body[tableId]["write"]).toEqual(HIGHER_ROLE_ID)
})
})
describe("remove", () => {
it("should be able to remove the permission", async () => {
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: tableId,
level: PermissionLevel.READ,
})
const permsRes = await config.api.permission.get(tableId)
expect(permsRes.permissions[STD_ROLE_ID]).toBeUndefined()
})
})
describe("check public user allowed", () => {
let viewId: string
let row: Row
beforeEach(async () => {
const view = await config.api.viewV2.create({
tableId,
name: generator.guid(),
})
viewId = view.id
row = await config.createRow()
})
it("should be able to read the row", async () => {
// replicate changes before checking permissions
await config.publish()
const res = await request
.get(`/api/${tableId}/rows`)
.set(config.publicHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body[0]._id).toEqual(row._id)
})
it("should be able to access the view data when the table is set to public and with no view permissions overrides", async () => {
// Make view inherit table permissions. Needed for backwards compatibility with existing views.
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: viewId,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
const res = await config.api.viewV2.publicSearch(viewId)
expect(res.rows[0]._id).toEqual(row._id)
})
it("should not be able to access the view data when the table is not public and there are no view permissions overrides", async () => {
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: tableId,
level: PermissionLevel.READ,
})
// Make view inherit table permissions. Needed for backwards compatibility with existing views.
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: viewId,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
await config.api.viewV2.publicSearch(viewId, undefined, {
status: 401,
})
})
it("should use the view permissions", async () => {
await config.api.permission.add({
roleId: STD_ROLE_ID,
resourceId: viewId,
level: PermissionLevel.READ,
})
await config.api.permission.revoke({
roleId: STD_ROLE_ID,
resourceId: tableId,
level: PermissionLevel.READ,
})
// replicate changes before checking permissions
await config.publish()
const res = await config.api.viewV2.publicSearch(viewId)
expect(res.rows[0]._id).toEqual(row._id)
})
it("shouldn't allow writing from a public user", async () => {
const res = await request
.post(`/api/${tableId}/rows`)
.send(basicRow(tableId))
.set(config.publicHeaders())
.expect("Content-Type", /json/)
.expect(401)
expect(res.status).toEqual(401)
})
})
})
describe("view permissions", () => {
let tableId: string
let viewId: string
beforeEach(async () => {
const table = await config.createTable()
tableId = table._id!
const view = await config.api.viewV2.create({
tableId,
name: generator.guid(),
})
viewId = view.id
})
it("default permissions inherits and persists the table default value", async () => {
const { permissions } = await config.api.permission.get(viewId)
expect(permissions).toEqual({
read: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
inheritablePermission: DEFAULT_TABLE_ROLE_ID,
},
write: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
inheritablePermission: DEFAULT_TABLE_ROLE_ID,
},
})
})
it("does not update view permissions once persisted, even if table permissions change", async () => {
await config.api.permission.add({
roleId: STD_ROLE_ID,
resourceId: tableId,
level: PermissionLevel.READ,
})
const { permissions } = await config.api.permission.get(viewId)
expect(permissions).toEqual({
read: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
inheritablePermission: STD_ROLE_ID,
},
write: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
inheritablePermission: DEFAULT_TABLE_ROLE_ID,
},
})
})
it("can sets permissions inherits explicit view permissions", async () => {
await config.api.permission.add({
roleId: HIGHER_ROLE_ID,
resourceId: viewId,
level: PermissionLevel.WRITE,
})
const { permissions } = await config.api.permission.get(viewId)
expect(permissions).toEqual({
read: {
permissionType: "EXPLICIT",
role: DEFAULT_TABLE_ROLE_ID,
inheritablePermission: DEFAULT_TABLE_ROLE_ID,
},
write: {
permissionType: "EXPLICIT",
role: HIGHER_ROLE_ID,
inheritablePermission: DEFAULT_TABLE_ROLE_ID,
},
})
}) })
}) })

View File

@ -71,7 +71,7 @@ describe("migrations", () => {
expect(events.datasource.created).toHaveBeenCalledTimes(2) expect(events.datasource.created).toHaveBeenCalledTimes(2)
expect(events.layout.created).toHaveBeenCalledTimes(1) expect(events.layout.created).toHaveBeenCalledTimes(1)
expect(events.query.created).toHaveBeenCalledTimes(2) expect(events.query.created).toHaveBeenCalledTimes(2)
expect(events.role.created).toHaveBeenCalledTimes(2) expect(events.role.created).toHaveBeenCalledTimes(3) // created roles + admin (created on table creation)
expect(events.table.created).toHaveBeenCalledTimes(3) expect(events.table.created).toHaveBeenCalledTimes(3)
expect(events.view.created).toHaveBeenCalledTimes(2) expect(events.view.created).toHaveBeenCalledTimes(2)
expect(events.view.calculationCreated).toHaveBeenCalledTimes(1) expect(events.view.calculationCreated).toHaveBeenCalledTimes(1)
@ -82,7 +82,7 @@ describe("migrations", () => {
// to make sure caching is working as expected // to make sure caching is working as expected
expect( expect(
events.processors.analyticsProcessor.processEvent events.processors.analyticsProcessor.processEvent
).toHaveBeenCalledTimes(23) ).toHaveBeenCalledTimes(24) // Addtion of of the events above
}) })
}) })
}) })

View File

@ -185,6 +185,26 @@ export async function updatePermissionOnRole(
}) })
} }
export async function setPermissions(
resourceId: string,
{
writeRole,
readRole,
}: {
writeRole: string
readRole: string
}
) {
await updatePermissionOnRole(
{ roleId: writeRole, resourceId, level: PermissionLevel.WRITE },
PermissionUpdateType.ADD
)
await updatePermissionOnRole(
{ roleId: readRole, resourceId, level: PermissionLevel.READ },
PermissionUpdateType.ADD
)
}
// utility function to stop this repetition - permissions always stored under roles // utility function to stop this repetition - permissions always stored under roles
export async function getAllDBRoles(db: Database) { export async function getAllDBRoles(db: Database) {
const body = await db.allDocs<Role>( const body = await db.allDocs<Role>(

View File

@ -3,6 +3,8 @@ import { Row, Table } from "@budibase/types"
import * as external from "./external" import * as external from "./external"
import * as internal from "./internal" import * as internal from "./internal"
import { isExternal } from "./utils" import { isExternal } from "./utils"
import { setPermissions } from "../permissions"
import { roles } from "@budibase/backend-core"
export async function create( export async function create(
table: Omit<Table, "_id" | "_rev">, table: Omit<Table, "_id" | "_rev">,
@ -15,5 +17,11 @@ export async function create(
} else { } else {
createdTable = await internal.create(table, rows, userId) createdTable = await internal.create(table, rows, userId)
} }
await setPermissions(createdTable._id!, {
writeRole: roles.BUILTIN_ROLE_IDS.ADMIN,
readRole: roles.BUILTIN_ROLE_IDS.ADMIN,
})
return createdTable return createdTable
} }

View File

@ -13,7 +13,7 @@ import {
ViewV2ColumnEnriched, ViewV2ColumnEnriched,
ViewV2Enriched, ViewV2Enriched,
} from "@budibase/types" } from "@budibase/types"
import { context, docIds, HTTPError, roles } from "@budibase/backend-core" import { context, docIds, HTTPError } from "@budibase/backend-core"
import { import {
helpers, helpers,
PROTECTED_EXTERNAL_COLUMNS, PROTECTED_EXTERNAL_COLUMNS,
@ -26,7 +26,6 @@ import { isExternalTableID } from "../../../integrations/utils"
import * as internal from "./internal" import * as internal from "./internal"
import * as external from "./external" import * as external from "./external"
import sdk from "../../../sdk" import sdk from "../../../sdk"
import { PermissionUpdateType, updatePermissionOnRole } from "../permissions"
function pickApi(tableId: any) { function pickApi(tableId: any) {
if (isExternalTableID(tableId)) { if (isExternalTableID(tableId)) {
@ -247,24 +246,10 @@ export async function create(
// Set permissions to be the same as the table // Set permissions to be the same as the table
const tablePerms = await sdk.permissions.getResourcePerms(tableId) const tablePerms = await sdk.permissions.getResourcePerms(tableId)
const readRole = tablePerms[PermissionLevel.READ]?.role await sdk.permissions.setPermissions(view.id, {
const writeRole = tablePerms[PermissionLevel.WRITE]?.role writeRole: tablePerms[PermissionLevel.WRITE].role,
await updatePermissionOnRole( readRole: tablePerms[PermissionLevel.READ].role,
{ })
roleId: readRole || roles.BUILTIN_ROLE_IDS.BASIC,
resourceId: view.id,
level: PermissionLevel.READ,
},
PermissionUpdateType.ADD
)
await updatePermissionOnRole(
{
roleId: writeRole || roles.BUILTIN_ROLE_IDS.BASIC,
resourceId: view.id,
level: PermissionLevel.WRITE,
},
PermissionUpdateType.ADD
)
return view return view
} }

View File

@ -1,6 +1,7 @@
import { import {
AddPermissionRequest, AddPermissionRequest,
AddPermissionResponse, AddPermissionResponse,
FetchResourcePermissionInfoResponse,
GetResourcePermsResponse, GetResourcePermsResponse,
RemovePermissionRequest, RemovePermissionRequest,
RemovePermissionResponse, RemovePermissionResponse,
@ -26,6 +27,15 @@ export class PermissionAPI extends TestAPI {
) )
} }
fetch = async (
expectations?: Expectations
): Promise<FetchResourcePermissionInfoResponse> => {
return await this._get<FetchResourcePermissionInfoResponse>(
`/api/permission`,
{ expectations }
)
}
revoke = async ( revoke = async (
request: RemovePermissionRequest, request: RemovePermissionRequest,
expectations?: Expectations expectations?: Expectations

View File

@ -1,5 +1,6 @@
import { permissions, roles } from "@budibase/backend-core" import { permissions, roles } from "@budibase/backend-core"
import { DocumentType, VirtualDocumentType } from "../db/utils" import { DocumentType, VirtualDocumentType } from "../db/utils"
import { getDocumentType, getVirtualDocumentType } from "@budibase/types"
export const CURRENTLY_SUPPORTED_LEVELS: string[] = [ export const CURRENTLY_SUPPORTED_LEVELS: string[] = [
permissions.PermissionLevel.WRITE, permissions.PermissionLevel.WRITE,
@ -8,13 +9,16 @@ export const CURRENTLY_SUPPORTED_LEVELS: string[] = [
] ]
export function getPermissionType(resourceId: string) { export function getPermissionType(resourceId: string) {
const docType = Object.values(DocumentType).filter(docType => const virtualDocType = getVirtualDocumentType(resourceId)
resourceId.startsWith(docType) switch (virtualDocType) {
)[0] case VirtualDocumentType.VIEW:
switch (docType as DocumentType | VirtualDocumentType) { return permissions.PermissionType.TABLE
}
const docType = getDocumentType(resourceId)
switch (docType) {
case DocumentType.TABLE: case DocumentType.TABLE:
case DocumentType.ROW: case DocumentType.ROW:
case VirtualDocumentType.VIEW:
return permissions.PermissionType.TABLE return permissions.PermissionType.TABLE
case DocumentType.AUTOMATION: case DocumentType.AUTOMATION:
return permissions.PermissionType.AUTOMATION return permissions.PermissionType.AUTOMATION
@ -32,22 +36,25 @@ export function getPermissionType(resourceId: string) {
/** /**
* works out the basic permissions based on builtin roles for a resource, using its ID * works out the basic permissions based on builtin roles for a resource, using its ID
*/ */
export function getBasePermissions(resourceId: string) { export function getBasePermissions(resourceId: string): Record<string, string> {
const type = getPermissionType(resourceId) const type = getPermissionType(resourceId)
const basePermissions: { [key: string]: string } = {} const basePermissions: Record<string, string> = {}
for (let [roleId, role] of Object.entries(roles.getBuiltinRoles())) { for (let [roleId, role] of Object.entries(roles.getBuiltinRoles())) {
if (!role.permissionId) { if (!role.permissionId) {
continue continue
} }
const perms = permissions.getBuiltinPermissionByID(role.permissionId) const perms = permissions.getBuiltinPermissionByID(role.permissionId)
if (!perms) { if (!perms) {
continue continue
} }
const typedPermission = perms.permissions.find(perm => perm.type === type) const typedPermission = perms.permissions.find(perm => perm.type === type)
if ( if (!typedPermission) {
typedPermission && continue
CURRENTLY_SUPPORTED_LEVELS.indexOf(typedPermission.level) !== -1 }
) {
if (CURRENTLY_SUPPORTED_LEVELS.includes(typedPermission.level)) {
const level = typedPermission.level const level = typedPermission.level
basePermissions[level] = roles.lowerBuiltinRoleID( basePermissions[level] = roles.lowerBuiltinRoleID(
basePermissions[level], basePermissions[level],

View File

@ -1,5 +1,9 @@
import { PermissionLevel } from "../../../sdk" import { PermissionLevel } from "../../../sdk"
export interface FetchResourcePermissionInfoResponse {
[key: string]: Record<string, string>
}
export interface ResourcePermissionInfo { export interface ResourcePermissionInfo {
role: string role: string
permissionType: string permissionType: string
@ -21,7 +25,7 @@ export interface AddedPermission {
reason?: string reason?: string
} }
export type AddPermissionResponse = AddedPermission[] export interface AddPermissionResponse {}
export interface AddPermissionRequest { export interface AddPermissionRequest {
roleId: string roleId: string
@ -30,4 +34,4 @@ export interface AddPermissionRequest {
} }
export interface RemovePermissionRequest extends AddPermissionRequest {} export interface RemovePermissionRequest extends AddPermissionRequest {}
export interface RemovePermissionResponse extends AddPermissionResponse {} export interface RemovePermissionResponse {}

View File

@ -42,6 +42,17 @@ export enum DocumentType {
ROW_ACTIONS = "ra", ROW_ACTIONS = "ra",
} }
// Because DocumentTypes can overlap, we need to make sure that we search
// longest first to ensure we get the correct type.
const sortedDocumentTypes = Object.values(DocumentType).sort(
(a, b) => b.length - a.length // descending
)
export function getDocumentType(id: string): DocumentType | undefined {
return sortedDocumentTypes.find(docType =>
id.startsWith(`${docType}${SEPARATOR}`)
)
}
// these are the core documents that make up the data, design // these are the core documents that make up the data, design
// and automation sections of an app. This excludes any internal // and automation sections of an app. This excludes any internal
// rows as we shouldn't import data. // rows as we shouldn't import data.
@ -72,6 +83,19 @@ export enum VirtualDocumentType {
ROW_ACTION = "row_action", ROW_ACTION = "row_action",
} }
// Because VirtualDocumentTypes can overlap, we need to make sure that we search
// longest first to ensure we get the correct type.
const sortedVirtualDocumentTypes = Object.values(VirtualDocumentType).sort(
(a, b) => b.length - a.length // descending
)
export function getVirtualDocumentType(
id: string
): VirtualDocumentType | undefined {
return sortedVirtualDocumentTypes.find(docType =>
id.startsWith(`${docType}${SEPARATOR}`)
)
}
export interface Document { export interface Document {
_id?: string _id?: string
_rev?: string _rev?: string