Adding administration roles API.
This commit is contained in:
parent
2d0122f7d6
commit
c45fdefb48
|
@ -7,3 +7,7 @@ module.exports.setDB = pouch => {
|
||||||
module.exports.getDB = dbName => {
|
module.exports.getDB = dbName => {
|
||||||
return new Pouch(dbName)
|
return new Pouch(dbName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.getCouch = () => {
|
||||||
|
return Pouch
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const { newid } = require("../hashing")
|
const { newid } = require("../hashing")
|
||||||
const Replication = require("./Replication")
|
const Replication = require("./Replication")
|
||||||
|
const { getCouch } = require("./index")
|
||||||
|
|
||||||
const UNICODE_MAX = "\ufff0"
|
const UNICODE_MAX = "\ufff0"
|
||||||
const SEPARATOR = "_"
|
const SEPARATOR = "_"
|
||||||
|
@ -136,6 +137,34 @@ exports.getRoleParams = (roleId = null, otherProps = {}) => {
|
||||||
return getDocParams(DocumentTypes.ROLE, roleId, otherProps)
|
return getDocParams(DocumentTypes.ROLE, roleId, otherProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lots of different points in the system need to find the full list of apps, this will
|
||||||
|
* enumerate the entire CouchDB cluster and get the list of databases (every app).
|
||||||
|
* NOTE: this operation is fine in self hosting, but cannot be used when hosting many
|
||||||
|
* different users/companies apps as there is no security around it - all apps are returned.
|
||||||
|
* @return {Promise<object[]>} returns the app information document stored in each app database.
|
||||||
|
*/
|
||||||
|
exports.getAllApps = async (devApps = false) => {
|
||||||
|
const CouchDB = getCouch()
|
||||||
|
let allDbs = await CouchDB.allDbs()
|
||||||
|
const appDbNames = allDbs.filter(dbName => dbName.startsWith(exports.APP_PREFIX))
|
||||||
|
const appPromises = appDbNames.map(db => new CouchDB(db).get(db))
|
||||||
|
if (appPromises.length === 0) {
|
||||||
|
return []
|
||||||
|
} else {
|
||||||
|
const response = await Promise.allSettled(appPromises)
|
||||||
|
const apps = response
|
||||||
|
.filter(result => result.status === "fulfilled")
|
||||||
|
.map(({ value }) => value)
|
||||||
|
return apps.filter(app => {
|
||||||
|
if (devApps) {
|
||||||
|
return app._id.startsWith(exports.APP_DEV_PREFIX)
|
||||||
|
}
|
||||||
|
return !app._id.startsWith(exports.APP_DEV_PREFIX)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new configuration ID.
|
* Generates a new configuration ID.
|
||||||
* @returns {string} The new configuration ID which the config doc can be stored under.
|
* @returns {string} The new configuration ID which the config doc can be stored under.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const { getDB } = require("../db")
|
const { getDB } = require("../db")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
const { BUILTIN_PERMISSION_IDS, higherPermission } = require("./permissions")
|
const { BUILTIN_PERMISSION_IDS, higherPermission } = require("./permissions")
|
||||||
const { generateRoleID, DocumentTypes, SEPARATOR } = require("../db/utils")
|
const { generateRoleID, getRoleParams, DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||||
|
|
||||||
const BUILTIN_IDS = {
|
const BUILTIN_IDS = {
|
||||||
ADMIN: "ADMIN",
|
ADMIN: "ADMIN",
|
||||||
|
@ -11,6 +11,14 @@ const BUILTIN_IDS = {
|
||||||
BUILDER: "BUILDER",
|
BUILDER: "BUILDER",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exclude internal roles like builder
|
||||||
|
const EXTERNAL_BUILTIN_ROLE_IDS = [
|
||||||
|
BUILTIN_IDS.ADMIN,
|
||||||
|
BUILTIN_IDS.POWER,
|
||||||
|
BUILTIN_IDS.BASIC,
|
||||||
|
BUILTIN_IDS.PUBLIC,
|
||||||
|
]
|
||||||
|
|
||||||
function Role(id, name) {
|
function Role(id, name) {
|
||||||
this._id = id
|
this._id = id
|
||||||
this.name = name
|
this.name = name
|
||||||
|
@ -192,6 +200,39 @@ exports.getUserPermissions = async (appId, userRoleId) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an app ID this will retrieve all of the roles that are currently within that app.
|
||||||
|
* @param {string} appId The ID of the app to retrieve the roles from.
|
||||||
|
* @return {Promise<object[]>} An array of the role objects that were found.
|
||||||
|
*/
|
||||||
|
exports.getAllRoles = async appId => {
|
||||||
|
const db = getDB(appId)
|
||||||
|
const body = await db.allDocs(
|
||||||
|
getRoleParams(null, {
|
||||||
|
include_docs: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
let roles = body.rows.map(row => row.doc)
|
||||||
|
const builtinRoles = exports.getBuiltinRoles()
|
||||||
|
|
||||||
|
// need to combine builtin with any DB record of them (for sake of permissions)
|
||||||
|
for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
|
||||||
|
const builtinRole = builtinRoles[builtinRoleId]
|
||||||
|
const dbBuiltin = roles.filter(
|
||||||
|
dbRole => exports.getExternalRoleID(dbRole._id) === builtinRoleId
|
||||||
|
)[0]
|
||||||
|
if (dbBuiltin == null) {
|
||||||
|
roles.push(builtinRole)
|
||||||
|
} else {
|
||||||
|
// remove role and all back after combining with the builtin
|
||||||
|
roles = roles.filter(role => role._id !== dbBuiltin._id)
|
||||||
|
dbBuiltin._id = exports.getExternalRoleID(dbBuiltin._id)
|
||||||
|
roles.push(Object.assign(builtinRole, dbBuiltin))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roles
|
||||||
|
}
|
||||||
|
|
||||||
class AccessController {
|
class AccessController {
|
||||||
constructor(appId) {
|
constructor(appId) {
|
||||||
this.appId = appId
|
this.appId = appId
|
||||||
|
|
|
@ -121,15 +121,8 @@ async function createInstance(template) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
exports.fetch = async function (ctx) {
|
||||||
let apps = await getAllApps()
|
|
||||||
|
|
||||||
const isDev = ctx.query && ctx.query.status === AppStatus.DEV
|
const isDev = ctx.query && ctx.query.status === AppStatus.DEV
|
||||||
apps = apps.filter(app => {
|
const apps = await getAllApps(isDev)
|
||||||
if (isDev) {
|
|
||||||
return app._id.startsWith(DocumentTypes.APP_DEV)
|
|
||||||
}
|
|
||||||
return !app._id.startsWith(DocumentTypes.APP_DEV)
|
|
||||||
})
|
|
||||||
|
|
||||||
// get the locks for all the dev apps
|
// get the locks for all the dev apps
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const {
|
const {
|
||||||
getBuiltinRoles,
|
getBuiltinRoles,
|
||||||
BUILTIN_ROLE_IDS,
|
|
||||||
Role,
|
Role,
|
||||||
getRole,
|
getRole,
|
||||||
isBuiltin,
|
isBuiltin,
|
||||||
getExternalRoleID,
|
getExternalRoleID,
|
||||||
|
getAllRoles,
|
||||||
} = require("@budibase/auth/roles")
|
} = require("@budibase/auth/roles")
|
||||||
const {
|
const {
|
||||||
generateRoleID,
|
generateRoleID,
|
||||||
|
@ -19,14 +19,6 @@ const UpdateRolesOptions = {
|
||||||
REMOVED: "removed",
|
REMOVED: "removed",
|
||||||
}
|
}
|
||||||
|
|
||||||
// exclude internal roles like builder
|
|
||||||
const EXTERNAL_BUILTIN_ROLE_IDS = [
|
|
||||||
BUILTIN_ROLE_IDS.ADMIN,
|
|
||||||
BUILTIN_ROLE_IDS.POWER,
|
|
||||||
BUILTIN_ROLE_IDS.BASIC,
|
|
||||||
BUILTIN_ROLE_IDS.PUBLIC,
|
|
||||||
]
|
|
||||||
|
|
||||||
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
async function updateRolesOnUserTable(db, roleId, updateOption) {
|
||||||
const table = await db.get(InternalTables.USER_METADATA)
|
const table = await db.get(InternalTables.USER_METADATA)
|
||||||
const schema = table.schema
|
const schema = table.schema
|
||||||
|
@ -51,31 +43,7 @@ async function updateRolesOnUserTable(db, roleId, updateOption) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetch = async function (ctx) {
|
exports.fetch = async function (ctx) {
|
||||||
const db = new CouchDB(ctx.appId)
|
ctx.body = await getAllRoles(ctx.appId)
|
||||||
const body = await db.allDocs(
|
|
||||||
getRoleParams(null, {
|
|
||||||
include_docs: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
let roles = body.rows.map(row => row.doc)
|
|
||||||
const builtinRoles = getBuiltinRoles()
|
|
||||||
|
|
||||||
// need to combine builtin with any DB record of them (for sake of permissions)
|
|
||||||
for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
|
|
||||||
const builtinRole = builtinRoles[builtinRoleId]
|
|
||||||
const dbBuiltin = roles.filter(
|
|
||||||
dbRole => getExternalRoleID(dbRole._id) === builtinRoleId
|
|
||||||
)[0]
|
|
||||||
if (dbBuiltin == null) {
|
|
||||||
roles.push(builtinRole)
|
|
||||||
} else {
|
|
||||||
// remove role and all back after combining with the builtin
|
|
||||||
roles = roles.filter(role => role._id !== dbBuiltin._id)
|
|
||||||
dbBuiltin._id = getExternalRoleID(dbBuiltin._id)
|
|
||||||
roles.push(Object.assign(builtinRole, dbBuiltin))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.body = roles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.find = async function (ctx) {
|
exports.find = async function (ctx) {
|
||||||
|
|
|
@ -2,33 +2,14 @@ const env = require("../environment")
|
||||||
const { APP_PREFIX } = require("../db/utils")
|
const { APP_PREFIX } = require("../db/utils")
|
||||||
const CouchDB = require("../db")
|
const CouchDB = require("../db")
|
||||||
const { OBJ_STORE_DIRECTORY, ObjectStoreBuckets } = require("../constants")
|
const { OBJ_STORE_DIRECTORY, ObjectStoreBuckets } = require("../constants")
|
||||||
|
const { getAllApps } = require("@budibase/auth/db")
|
||||||
|
|
||||||
const BB_CDN = "https://cdn.app.budi.live/assets"
|
const BB_CDN = "https://cdn.app.budi.live/assets"
|
||||||
|
|
||||||
exports.wait = ms => new Promise(resolve => setTimeout(resolve, ms))
|
exports.wait = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
|
||||||
exports.isDev = env.isDev
|
exports.isDev = env.isDev
|
||||||
|
exports.getAllApps = getAllApps
|
||||||
/**
|
|
||||||
* Lots of different points in the app need to find the full list of apps, this will
|
|
||||||
* enumerate the entire CouchDB cluster and get the list of databases (every app).
|
|
||||||
* NOTE: this operation is fine in self hosting, but cannot be used when hosting many
|
|
||||||
* different users/companies apps as there is no security around it - all apps are returned.
|
|
||||||
* @return {Promise<object[]>} returns the app information document stored in each app database.
|
|
||||||
*/
|
|
||||||
exports.getAllApps = async () => {
|
|
||||||
let allDbs = await CouchDB.allDbs()
|
|
||||||
const appDbNames = allDbs.filter(dbName => dbName.startsWith(APP_PREFIX))
|
|
||||||
const appPromises = appDbNames.map(db => new CouchDB(db).get(db))
|
|
||||||
if (appPromises.length === 0) {
|
|
||||||
return []
|
|
||||||
} else {
|
|
||||||
const response = await Promise.allSettled(appPromises)
|
|
||||||
return response
|
|
||||||
.filter(result => result.status === "fulfilled")
|
|
||||||
.map(({ value }) => value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure that a URL has the correct number of slashes, while maintaining the
|
* Makes sure that a URL has the correct number of slashes, while maintaining the
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
const { getAllRoles } = require("@budibase/auth/roles")
|
||||||
|
const { getAllApps } = require("@budibase/auth/db")
|
||||||
|
|
||||||
|
exports.fetch = async ctx => {
|
||||||
|
// always use the dev apps as they'll be most up to date (true)
|
||||||
|
const apps = await getAllApps(true)
|
||||||
|
const promises = []
|
||||||
|
for (let app of apps) {
|
||||||
|
promises.push(getAllRoles(app._id))
|
||||||
|
}
|
||||||
|
const roles = await Promise.all(promises)
|
||||||
|
const response = {}
|
||||||
|
for (let app of apps) {
|
||||||
|
response[app._id] = roles.shift()
|
||||||
|
}
|
||||||
|
ctx.body = response
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.find = async ctx => {
|
||||||
|
const appId = ctx.params.appId
|
||||||
|
ctx.body = {
|
||||||
|
roles: await getAllRoles(appId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
const Router = require("@koa/router")
|
||||||
|
const controller = require("../../controllers/admin/roles")
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
router
|
||||||
|
.get("/api/admin/roles", controller.fetch)
|
||||||
|
.get("/api/admin/roles/:appId", controller.find)
|
||||||
|
|
||||||
|
module.exports = router
|
|
@ -45,6 +45,7 @@ router
|
||||||
.post("/api/admin/users/init", controller.adminUser)
|
.post("/api/admin/users/init", controller.adminUser)
|
||||||
.delete("/api/admin/users/:id", controller.destroy)
|
.delete("/api/admin/users/:id", controller.destroy)
|
||||||
.get("/api/admin/users/:id", controller.find)
|
.get("/api/admin/users/:id", controller.find)
|
||||||
|
.get("/api/admin/roles/:appId")
|
||||||
.post("/api/admin/users/invite", buildInviteValidation(), controller.invite)
|
.post("/api/admin/users/invite", buildInviteValidation(), controller.invite)
|
||||||
.post(
|
.post(
|
||||||
"/api/admin/users/invite/accept",
|
"/api/admin/users/invite/accept",
|
||||||
|
|
Loading…
Reference in New Issue