mirror of https://github.com/Budibase/budibase.git
64 changed files with 911 additions and 814 deletions
@ -1,22 +1,13 @@ |
|||
import { Screen } from "./utils/Screen" |
|||
|
|||
export default { |
|||
name: `Create from scratch`, |
|||
create: () => createScreen(), |
|||
} |
|||
|
|||
const createScreen = () => ({ |
|||
props: { |
|||
_id: "", |
|||
_component: "@budibase/standard-components/container", |
|||
_styles: { |
|||
normal: {}, |
|||
hover: {}, |
|||
active: {}, |
|||
selected: {}, |
|||
}, |
|||
type: "div", |
|||
_children: [], |
|||
_instanceName: "", |
|||
}, |
|||
route: "", |
|||
name: "screen-id", |
|||
}) |
|||
const createScreen = () => { |
|||
return new Screen() |
|||
.mainType("div") |
|||
.component("@budibase/standard-components/container") |
|||
.json() |
|||
} |
|||
|
|||
@ -1,22 +1,13 @@ |
|||
import { Screen } from "./utils/Screen" |
|||
|
|||
export default { |
|||
name: `New Row (Empty)`, |
|||
create: () => createScreen(), |
|||
} |
|||
|
|||
const createScreen = () => ({ |
|||
props: { |
|||
_id: "", |
|||
_component: "@budibase/standard-components/newrow", |
|||
_styles: { |
|||
normal: {}, |
|||
hover: {}, |
|||
active: {}, |
|||
selected: {}, |
|||
}, |
|||
_children: [], |
|||
_instanceName: "", |
|||
table: "", |
|||
}, |
|||
route: "", |
|||
name: "screen-id", |
|||
}) |
|||
const createScreen = () => { |
|||
return new Screen() |
|||
.component("@budibase/standard-components/newrow") |
|||
.table("") |
|||
.json() |
|||
} |
|||
|
|||
@ -1,22 +1,13 @@ |
|||
import { Screen } from "./utils/Screen" |
|||
|
|||
export default { |
|||
name: `Row Detail (Empty)`, |
|||
create: () => createScreen(), |
|||
} |
|||
|
|||
const createScreen = () => ({ |
|||
props: { |
|||
_id: "", |
|||
_component: "@budibase/standard-components/rowdetail", |
|||
_styles: { |
|||
normal: {}, |
|||
hover: {}, |
|||
active: {}, |
|||
selected: {}, |
|||
}, |
|||
_children: [], |
|||
_instanceName: "", |
|||
table: "", |
|||
}, |
|||
route: "", |
|||
name: "screen-id", |
|||
}) |
|||
const createScreen = () => { |
|||
return new Screen() |
|||
.component("@budibase/standard-components/rowdetail") |
|||
.table("") |
|||
.json() |
|||
} |
|||
|
|||
@ -0,0 +1,36 @@ |
|||
import { cloneDeep } from "lodash/fp" |
|||
|
|||
export class BaseStructure { |
|||
constructor(isScreen) { |
|||
this._isScreen = isScreen |
|||
this._children = [] |
|||
this._json = { |
|||
} |
|||
} |
|||
|
|||
addChild(child) { |
|||
this._children.push(child) |
|||
return this |
|||
} |
|||
|
|||
customProps(props) { |
|||
for (let key of Object.keys(props)) { |
|||
this._json[key] = props[key] |
|||
} |
|||
return this |
|||
} |
|||
|
|||
json() { |
|||
const structure = cloneDeep(this._json) |
|||
if (this._children.length !== 0) { |
|||
for (let child of this._children) { |
|||
if (this._isScreen) { |
|||
structure.props._children.push(child.json()) |
|||
} else { |
|||
structure._children.push(child.json()) |
|||
} |
|||
} |
|||
} |
|||
return structure |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
import { cloneDeep } from "lodash/fp" |
|||
import { v4 } from "uuid" |
|||
import { BaseStructure } from "./BaseStructure" |
|||
|
|||
export class Component extends BaseStructure { |
|||
constructor(name) { |
|||
super(false) |
|||
this._children = [] |
|||
this._json = { |
|||
_id: v4(), |
|||
_component: name, |
|||
_styles: { |
|||
normal: {}, |
|||
hover: {}, |
|||
active: {}, |
|||
selected: {}, |
|||
}, |
|||
_code: "", |
|||
className: "", |
|||
onLoad: [], |
|||
type: "", |
|||
_instanceName: "", |
|||
_children: [], |
|||
} |
|||
} |
|||
|
|||
type(type) { |
|||
this._json.type = type |
|||
return this |
|||
} |
|||
|
|||
normalStyle(styling) { |
|||
this._json._styles.normal = styling |
|||
return this |
|||
} |
|||
|
|||
hoverStyle(styling) { |
|||
this._json._styles.hover = styling |
|||
return this |
|||
} |
|||
|
|||
text(text) { |
|||
this._json.text = text |
|||
return this |
|||
} |
|||
|
|||
// TODO: do we need this
|
|||
instanceName(name) { |
|||
this._json._instanceName = name |
|||
return this |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
import { BaseStructure } from "./BaseStructure" |
|||
|
|||
export class Screen extends BaseStructure { |
|||
constructor() { |
|||
super(true) |
|||
this._json = { |
|||
props: { |
|||
_id: "", |
|||
_component: "", |
|||
_styles: { |
|||
normal: {}, |
|||
hover: {}, |
|||
active: {}, |
|||
selected: {}, |
|||
}, |
|||
_children: [], |
|||
_instanceName: "", |
|||
}, |
|||
routing: { |
|||
route: "", |
|||
accessLevelId: "", |
|||
}, |
|||
name: "screen-id", |
|||
} |
|||
} |
|||
|
|||
component(name) { |
|||
this._json.props._component = name |
|||
return this |
|||
} |
|||
|
|||
table(tableName) { |
|||
this._json.props.table = tableName |
|||
return this |
|||
} |
|||
|
|||
mainType(type) { |
|||
this._json.type = type |
|||
return this |
|||
} |
|||
|
|||
route(route) { |
|||
this._json.routing.route = route |
|||
return this |
|||
} |
|||
|
|||
name(name) { |
|||
this._json.name = name |
|||
return this |
|||
} |
|||
|
|||
instanceName(name) { |
|||
this._json.props._instanceName = name |
|||
return this |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
import { Component } from "./Component" |
|||
|
|||
export function linkComponent(tableName) { |
|||
return new Component("@budibase/standard-components/link") |
|||
.normalStyle({ |
|||
color: "#757575", |
|||
"text-transform": "capitalize", |
|||
}) |
|||
.hoverStyle({ |
|||
color: "#4285f4", |
|||
}) |
|||
.text(tableName) |
|||
.customProps({ |
|||
url: `/${tableName.toLowerCase()}`, |
|||
openInNewTab: false, |
|||
color: "", |
|||
hoverColor: "", |
|||
underline: false, |
|||
fontSize: "", |
|||
fontFamily: "initial", |
|||
}) |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
const { getRoutingInfo } = require("../../utilities/routing") |
|||
const { AccessController } = require("../../utilities/security/accessLevels") |
|||
|
|||
async function getRoutingStructure(appId) { |
|||
let baseRouting = await getRoutingInfo(appId) |
|||
return baseRouting |
|||
} |
|||
|
|||
exports.fetch = async ctx => { |
|||
ctx.body = await getRoutingStructure(ctx.appId) |
|||
} |
|||
|
|||
exports.clientFetch = async ctx => { |
|||
const routing = getRoutingStructure(ctx.appId) |
|||
// use the access controller to pick which access level is applicable to this user
|
|||
const accessController = new AccessController(ctx.appId) |
|||
} |
|||
@ -1,14 +1,18 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/accesslevel") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/security/permissions") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.post("/api/accesslevels", controller.create) |
|||
.put("/api/accesslevels", controller.update) |
|||
.get("/api/accesslevels", controller.fetch) |
|||
.get("/api/accesslevels/:levelId", controller.find) |
|||
.delete("/api/accesslevels/:levelId/:rev", controller.destroy) |
|||
.patch("/api/accesslevels/:levelId", controller.patch) |
|||
.post("/api/accesslevels", authorized(BUILDER), controller.save) |
|||
.get("/api/accesslevels", authorized(BUILDER), controller.fetch) |
|||
.get("/api/accesslevels/:levelId", authorized(BUILDER), controller.find) |
|||
.delete( |
|||
"/api/accesslevels/:levelId/:rev", |
|||
authorized(BUILDER), |
|||
controller.destroy |
|||
) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
const Router = require("@koa/router") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/security/permissions") |
|||
const controller = require("../controllers/routing") |
|||
|
|||
const router = Router() |
|||
|
|||
// gets the full structure, not just the correct screen ID for your access level
|
|||
router |
|||
.get("/api/routing", authorized(BUILDER), controller.fetch) |
|||
.get("/api/routing/client", controller.clientFetch) |
|||
|
|||
module.exports = router |
|||
@ -1,36 +0,0 @@ |
|||
// Permissions
|
|||
module.exports.READ_TABLE = "read-table" |
|||
module.exports.WRITE_TABLE = "write-table" |
|||
module.exports.READ_VIEW = "read-view" |
|||
module.exports.EXECUTE_AUTOMATION = "execute-automation" |
|||
module.exports.EXECUTE_WEBHOOK = "execute-webhook" |
|||
module.exports.USER_MANAGEMENT = "user-management" |
|||
module.exports.BUILDER = "builder" |
|||
module.exports.LIST_USERS = "list-users" |
|||
// Access Level IDs
|
|||
module.exports.ADMIN_LEVEL_ID = "ADMIN" |
|||
module.exports.POWERUSER_LEVEL_ID = "POWER_USER" |
|||
module.exports.BUILDER_LEVEL_ID = "BUILDER" |
|||
module.exports.ANON_LEVEL_ID = "ANON" |
|||
module.exports.ACCESS_LEVELS = [ |
|||
module.exports.ADMIN_LEVEL_ID, |
|||
module.exports.POWERUSER_LEVEL_ID, |
|||
module.exports.BUILDER_LEVEL_ID, |
|||
module.exports.ANON_LEVEL_ID, |
|||
] |
|||
module.exports.PRETTY_ACCESS_LEVELS = { |
|||
[module.exports.ADMIN_LEVEL_ID]: "Admin", |
|||
[module.exports.POWERUSER_LEVEL_ID]: "Power user", |
|||
[module.exports.BUILDER_LEVEL_ID]: "Builder", |
|||
} |
|||
module.exports.adminPermissions = [ |
|||
{ |
|||
name: module.exports.USER_MANAGEMENT, |
|||
}, |
|||
] |
|||
|
|||
// to avoid circular dependencies this is included later, after exporting all enums
|
|||
const permissions = require("./permissions") |
|||
module.exports.generateAdminPermissions = permissions.generateAdminPermissions |
|||
module.exports.generatePowerUserPermissions = |
|||
permissions.generatePowerUserPermissions |
|||
@ -1,66 +0,0 @@ |
|||
const viewController = require("../api/controllers/view") |
|||
const tableController = require("../api/controllers/table") |
|||
const automationController = require("../api/controllers/automation") |
|||
const accessLevels = require("./accessLevels") |
|||
|
|||
// this has been broken out to reduce risk of circular dependency from utilities, no enums defined here
|
|||
const generateAdminPermissions = async appId => [ |
|||
...accessLevels.adminPermissions, |
|||
...(await generatePowerUserPermissions(appId)), |
|||
] |
|||
|
|||
const generatePowerUserPermissions = async appId => { |
|||
const fetchTablesCtx = { |
|||
user: { |
|||
appId, |
|||
}, |
|||
} |
|||
await tableController.fetch(fetchTablesCtx) |
|||
const tables = fetchTablesCtx.body |
|||
|
|||
const fetchViewsCtx = { |
|||
user: { |
|||
appId, |
|||
}, |
|||
} |
|||
await viewController.fetch(fetchViewsCtx) |
|||
const views = fetchViewsCtx.body |
|||
|
|||
const fetchAutomationsCtx = { |
|||
user: { |
|||
appId, |
|||
}, |
|||
} |
|||
await automationController.fetch(fetchAutomationsCtx) |
|||
const automations = fetchAutomationsCtx.body |
|||
|
|||
const readTablePermissions = tables.map(m => ({ |
|||
itemId: m._id, |
|||
name: accessLevels.READ_TABLE, |
|||
})) |
|||
|
|||
const writeTablePermissions = tables.map(m => ({ |
|||
itemId: m._id, |
|||
name: accessLevels.WRITE_TABLE, |
|||
})) |
|||
|
|||
const viewPermissions = views.map(v => ({ |
|||
itemId: v.name, |
|||
name: accessLevels.READ_VIEW, |
|||
})) |
|||
|
|||
const executeAutomationPermissions = automations.map(w => ({ |
|||
itemId: w._id, |
|||
name: accessLevels.EXECUTE_AUTOMATION, |
|||
})) |
|||
|
|||
return [ |
|||
...readTablePermissions, |
|||
...writeTablePermissions, |
|||
...viewPermissions, |
|||
...executeAutomationPermissions, |
|||
{ name: accessLevels.LIST_USERS }, |
|||
] |
|||
} |
|||
module.exports.generateAdminPermissions = generateAdminPermissions |
|||
module.exports.generatePowerUserPermissions = generatePowerUserPermissions |
|||
@ -0,0 +1,24 @@ |
|||
const CouchDB = require("../../db") |
|||
const { createRoutingView } = require("./routingUtils") |
|||
const { ViewNames, getQueryIndex, UNICODE_MAX } = require("../../db/utils") |
|||
|
|||
exports.getRoutingInfo = async appId => { |
|||
const db = new CouchDB(appId) |
|||
try { |
|||
const allRouting = await db.query(getQueryIndex(ViewNames.ROUTING), { |
|||
startKey: "", |
|||
endKey: UNICODE_MAX, |
|||
}) |
|||
return allRouting.rows.map(row => row.value) |
|||
} catch (err) { |
|||
// check if the view doesn't exist, it should for all new instances
|
|||
if (err != null && err.name === "not_found") { |
|||
await createRoutingView(appId) |
|||
return exports.getRoutingInfo(appId) |
|||
} else { |
|||
throw err |
|||
} |
|||
} |
|||
} |
|||
|
|||
exports.createRoutingView = createRoutingView |
|||
@ -0,0 +1,24 @@ |
|||
const CouchDB = require("../../db") |
|||
const { DocumentTypes, SEPARATOR, ViewNames } = require("../../db/utils") |
|||
const SCREEN_PREFIX = DocumentTypes.SCREEN + SEPARATOR |
|||
|
|||
exports.createRoutingView = async appId => { |
|||
const db = new CouchDB(appId) |
|||
const designDoc = await db.get("_design/database") |
|||
const view = { |
|||
// if using variables in a map function need to inject them before use
|
|||
map: `function(doc) {
|
|||
if (doc._id.startsWith("${SCREEN_PREFIX}")) { |
|||
emit(doc._id, { |
|||
id: doc._id, |
|||
routing: doc.routing, |
|||
}) |
|||
} |
|||
}`,
|
|||
} |
|||
designDoc.views = { |
|||
...designDoc.views, |
|||
[ViewNames.ROUTING]: view, |
|||
} |
|||
await db.put(designDoc) |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
const CouchDB = require("../../db") |
|||
|
|||
const BUILTIN_IDS = { |
|||
ADMIN: "ADMIN", |
|||
POWER: "POWER_USER", |
|||
BASIC: "BASIC", |
|||
ANON: "ANON", |
|||
BUILDER: "BUILDER", |
|||
} |
|||
|
|||
function AccessLevel(id, name, inherits = null) { |
|||
this._id = id |
|||
this.name = name |
|||
if (inherits) { |
|||
this.inherits = inherits |
|||
} |
|||
} |
|||
|
|||
exports.BUILTIN_LEVELS = { |
|||
ADMIN: new AccessLevel(BUILTIN_IDS.ADMIN, "Admin", BUILTIN_IDS.POWER), |
|||
POWER: new AccessLevel(BUILTIN_IDS.POWER, "Admin", BUILTIN_IDS.BASIC), |
|||
BASIC: new AccessLevel(BUILTIN_IDS.BASIC, "Basic", BUILTIN_IDS.ANON), |
|||
ANON: new AccessLevel(BUILTIN_IDS.ANON, "Anonymous"), |
|||
BUILDER: new AccessLevel(BUILTIN_IDS.BUILDER, "Builder"), |
|||
} |
|||
|
|||
exports.BUILTIN_LEVEL_ID_ARRAY = Object.values(exports.BUILTIN_LEVELS).map( |
|||
level => level._id |
|||
) |
|||
|
|||
exports.BUILTIN_LEVEL_NAME_ARRAY = Object.values(exports.BUILTIN_LEVELS).map( |
|||
level => level.name |
|||
) |
|||
|
|||
function isBuiltin(accessLevel) { |
|||
return exports.BUILTIN_LEVEL_ID_ARRAY.indexOf(accessLevel) !== -1 |
|||
} |
|||
|
|||
class AccessController { |
|||
constructor(appId) { |
|||
this.appId = appId |
|||
this.accessLevels = {} |
|||
} |
|||
|
|||
async getAccessLevel(accessLevelId) { |
|||
if (this.accessLevels[accessLevelId]) { |
|||
return this.accessLevels[accessLevelId] |
|||
} |
|||
let accessLevel |
|||
if (isBuiltin(accessLevelId)) { |
|||
accessLevel = Object.values(exports.BUILTIN_LEVELS).find( |
|||
level => level._id === accessLevelId |
|||
) |
|||
} else { |
|||
const db = new CouchDB(this.appId) |
|||
accessLevel = await db.get(accessLevelId) |
|||
} |
|||
this.accessLevels[accessLevelId] = accessLevel |
|||
return accessLevel |
|||
} |
|||
|
|||
async hasAccess(tryingAccessLevelId, userAccessLevelId) { |
|||
// special cases, the screen has no access level, the access levels are the same or the user
|
|||
// is currently in the builder
|
|||
if ( |
|||
tryingAccessLevelId == null || |
|||
tryingAccessLevelId === "" || |
|||
tryingAccessLevelId === userAccessLevelId || |
|||
userAccessLevelId === BUILTIN_IDS.BUILDER |
|||
) { |
|||
return true |
|||
} |
|||
let userAccess = await this.getAccessLevel(userAccessLevelId) |
|||
// check if inherited makes it possible
|
|||
while (userAccess.inherits) { |
|||
if (tryingAccessLevelId === userAccess.inherits) { |
|||
return true |
|||
} |
|||
// go to get the inherited incase it inherits anything
|
|||
userAccess = await this.getAccessLevel(userAccess.inherits) |
|||
} |
|||
return false |
|||
} |
|||
|
|||
async checkScreensAccess(screens, userAccessLevelId) { |
|||
let accessibleScreens = [] |
|||
// don't want to handle this with Promise.all as this would mean all custom access levels would be
|
|||
// retrieved at same time, it is likely a custom levels will be re-used and therefore want
|
|||
// to work in sync for performance save
|
|||
for (let screen of screens) { |
|||
const accessible = await this.checkScreenAccess(screen, userAccessLevelId) |
|||
if (accessible) { |
|||
accessibleScreens.push(accessible) |
|||
} |
|||
} |
|||
return accessibleScreens |
|||
} |
|||
|
|||
async checkScreenAccess(screen, userAccessLevelId) { |
|||
const accessLevelId = |
|||
screen && screen.routing ? screen.routing.accessLevelId : null |
|||
if (await this.hasAccess(accessLevelId, userAccessLevelId)) { |
|||
return screen |
|||
} |
|||
return null |
|||
} |
|||
} |
|||
|
|||
exports.AccessController = AccessController |
|||
exports.BUILTIN_LEVEL_IDS = BUILTIN_IDS |
|||
exports.isBuiltin = isBuiltin |
|||
exports.AccessLevel = AccessLevel |
|||
@ -0,0 +1,113 @@ |
|||
const { flatten } = require("lodash") |
|||
|
|||
const PermissionLevels = { |
|||
READ: "read", |
|||
WRITE: "write", |
|||
EXECUTE: "execute", |
|||
ADMIN: "admin", |
|||
} |
|||
|
|||
const PermissionTypes = { |
|||
TABLE: "table", |
|||
USER: "user", |
|||
AUTOMATION: "automation", |
|||
WEBHOOK: "webhook", |
|||
BUILDER: "builder", |
|||
VIEW: "view", |
|||
} |
|||
|
|||
function Permission(type, level) { |
|||
this.level = level |
|||
this.type = type |
|||
} |
|||
|
|||
/** |
|||
* Given the specified permission level for the user return the levels they are allowed to carry out. |
|||
* @param {string} userPermLevel The permission level of the user. |
|||
* @return {string[]} All the permission levels this user is allowed to carry out. |
|||
*/ |
|||
function getAllowedLevels(userPermLevel) { |
|||
switch (userPermLevel) { |
|||
case PermissionLevels.READ: |
|||
return [PermissionLevels.READ] |
|||
case PermissionLevels.WRITE: |
|||
return [PermissionLevels.READ, PermissionLevels.WRITE] |
|||
case PermissionLevels.EXECUTE: |
|||
return [PermissionLevels.EXECUTE] |
|||
case PermissionLevels.ADMIN: |
|||
return [ |
|||
PermissionLevels.READ, |
|||
PermissionLevels.WRITE, |
|||
PermissionLevels.EXECUTE, |
|||
] |
|||
default: |
|||
return [] |
|||
} |
|||
} |
|||
|
|||
exports.BUILTIN_PERMISSION_NAMES = { |
|||
READ_ONLY: "read_only", |
|||
WRITE: "write", |
|||
ADMIN: "admin", |
|||
POWER: "power", |
|||
} |
|||
|
|||
exports.BUILTIN_PERMISSIONS = { |
|||
READ_ONLY: { |
|||
name: exports.BUILTIN_PERMISSION_NAMES.READ_ONLY, |
|||
permissions: [ |
|||
new Permission(PermissionTypes.TABLE, PermissionLevels.READ), |
|||
new Permission(PermissionTypes.VIEW, PermissionLevels.READ), |
|||
], |
|||
}, |
|||
WRITE: { |
|||
name: exports.BUILTIN_PERMISSION_NAMES.WRITE, |
|||
permissions: [ |
|||
new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE), |
|||
new Permission(PermissionTypes.VIEW, PermissionLevels.READ), |
|||
], |
|||
}, |
|||
POWER: { |
|||
name: exports.BUILTIN_PERMISSION_NAMES.POWER, |
|||
permissions: [ |
|||
new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE), |
|||
new Permission(PermissionTypes.USER, PermissionLevels.READ), |
|||
new Permission(PermissionTypes.AUTOMATION, PermissionLevels.EXECUTE), |
|||
new Permission(PermissionTypes.VIEW, PermissionLevels.READ), |
|||
new Permission(PermissionTypes.WEBHOOK, PermissionLevels.READ), |
|||
], |
|||
}, |
|||
ADMIN: { |
|||
name: exports.BUILTIN_PERMISSION_NAMES.ADMIN, |
|||
permissions: [ |
|||
new Permission(PermissionTypes.TABLE, PermissionLevels.ADMIN), |
|||
new Permission(PermissionTypes.USER, PermissionLevels.ADMIN), |
|||
new Permission(PermissionTypes.AUTOMATION, PermissionLevels.ADMIN), |
|||
new Permission(PermissionTypes.VIEW, PermissionLevels.ADMIN), |
|||
new Permission(PermissionTypes.WEBHOOK, PermissionLevels.READ), |
|||
], |
|||
}, |
|||
} |
|||
|
|||
exports.doesHavePermission = (permType, permLevel, userPermissionNames) => { |
|||
const builtins = Object.values(exports.BUILTIN_PERMISSIONS) |
|||
let permissions = flatten( |
|||
builtins |
|||
.filter(builtin => userPermissionNames.indexOf(builtin.name) !== -1) |
|||
.map(builtin => builtin.permissions) |
|||
) |
|||
for (let permission of permissions) { |
|||
if ( |
|||
permission.type === permType && |
|||
getAllowedLevels(permission.level).indexOf(permLevel) !== -1 |
|||
) { |
|||
return true |
|||
} |
|||
} |
|||
return false |
|||
} |
|||
|
|||
// utility as a lot of things need simply the builder permission
|
|||
exports.BUILDER = PermissionTypes.BUILDER |
|||
exports.PermissionTypes = PermissionTypes |
|||
exports.PermissionLevels = PermissionLevels |
|||
Loading…
Reference in new issue