mirror of https://github.com/Budibase/budibase.git
41 changed files with 1113 additions and 163 deletions
@ -0,0 +1,108 @@ |
|||
const CouchDB = require("../../db") |
|||
const newid = require("../../db/newid") |
|||
const { |
|||
generateAdminPermissions, |
|||
generatePowerUserPermissions, |
|||
POWERUSER_LEVEL_ID, |
|||
ADMIN_LEVEL_ID, |
|||
} = require("../../utilities/accessLevels") |
|||
|
|||
exports.fetch = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
const body = await db.query("database/by_type", { |
|||
include_docs: true, |
|||
key: ["accesslevel"], |
|||
}) |
|||
const customAccessLevels = body.rows.map(row => row.doc) |
|||
|
|||
const staticAccessLevels = [ |
|||
{ |
|||
_id: ADMIN_LEVEL_ID, |
|||
name: "Admin", |
|||
permissions: await generateAdminPermissions(ctx.params.instanceId), |
|||
}, |
|||
{ |
|||
_id: POWERUSER_LEVEL_ID, |
|||
name: "Power User", |
|||
permissions: await generatePowerUserPermissions(ctx.params.instanceId), |
|||
}, |
|||
] |
|||
|
|||
ctx.body = [...staticAccessLevels, ...customAccessLevels] |
|||
} |
|||
|
|||
exports.find = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
ctx.body = await db.get(ctx.params.levelId) |
|||
} |
|||
|
|||
exports.update = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
const level = await db.get(ctx.params.levelId) |
|||
level.name = ctx.body.name |
|||
level.permissions = ctx.request.body.permissions |
|||
const result = await db.put(level) |
|||
level._rev = result.rev |
|||
ctx.body = level |
|||
ctx.message = `Level ${level.name} updated successfully.` |
|||
} |
|||
|
|||
exports.patch = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
const level = await db.get(ctx.params.levelId) |
|||
const { removedPermissions, addedPermissions, _rev } = ctx.request.body |
|||
|
|||
if (!_rev) throw new Error("Must supply a _rev to update an access level") |
|||
|
|||
level._rev = _rev |
|||
|
|||
if (removedPermissions) { |
|||
level.permissions = level.permissions.filter( |
|||
p => |
|||
!removedPermissions.some( |
|||
rem => rem.name === p.name && rem.itemId === p.itemId |
|||
) |
|||
) |
|||
} |
|||
|
|||
if (addedPermissions) { |
|||
level.permissions = [ |
|||
...level.permissions.filter( |
|||
p => |
|||
!addedPermissions.some( |
|||
add => add.name === p.name && add.itemId === p.itemId |
|||
) |
|||
), |
|||
...addedPermissions, |
|||
] |
|||
} |
|||
|
|||
const result = await db.put(level) |
|||
level._rev = result.rev |
|||
ctx.body = level |
|||
ctx.message = `Access Level ${level.name} updated successfully.` |
|||
} |
|||
|
|||
exports.create = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
|
|||
const level = { |
|||
name: ctx.request.body.name, |
|||
_rev: ctx.request.body._rev, |
|||
permissions: ctx.request.body.permissions || [], |
|||
_id: newid(), |
|||
type: "accesslevel", |
|||
} |
|||
|
|||
const result = await db.put(level) |
|||
level._rev = result.rev |
|||
ctx.body = level |
|||
ctx.message = `Access Level '${level.name}' created successfully.` |
|||
} |
|||
|
|||
exports.destroy = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
await db.remove(ctx.params.levelId, ctx.params.rev) |
|||
ctx.message = `Access Level ${ctx.params.id} deleted successfully` |
|||
ctx.status = 200 |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
const CouchDB = require("../../db") |
|||
const Ajv = require("ajv") |
|||
const newid = require("../../db/newid") |
|||
|
|||
const ajv = new Ajv() |
|||
|
|||
exports.create = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
const workflow = ctx.request.body |
|||
|
|||
workflow._id = newid() |
|||
|
|||
// TODO: Possibly validate the workflow against a schema
|
|||
|
|||
// // validation with ajv
|
|||
// const model = await db.get(record.modelId)
|
|||
// const validate = ajv.compile({
|
|||
// properties: model.schema,
|
|||
// })
|
|||
// const valid = validate(record)
|
|||
|
|||
// if (!valid) {
|
|||
// ctx.status = 400
|
|||
// ctx.body = {
|
|||
// status: 400,
|
|||
// errors: validate.errors,
|
|||
// }
|
|||
// return
|
|||
// }
|
|||
|
|||
|
|||
workflow.type = "workflow" |
|||
const response = await db.post(workflow) |
|||
workflow._rev = response.rev |
|||
|
|||
ctx.status = 200 |
|||
ctx.body = { |
|||
message: "Workflow created successfully", |
|||
workflow: { |
|||
...workflow, |
|||
...response |
|||
} |
|||
}; |
|||
} |
|||
|
|||
exports.update = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
ctx.body = await db.get(ctx.params.recordId) |
|||
} |
|||
|
|||
exports.fetch = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
const response = await db.query(`database/by_type`, { |
|||
type: "workflow", |
|||
include_docs: true, |
|||
}) |
|||
ctx.body = response.rows.map(row => row.doc) |
|||
} |
|||
|
|||
exports.find = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
ctx.body = await db.get(ctx.params.id) |
|||
} |
|||
|
|||
exports.destroy = async function(ctx) { |
|||
const db = new CouchDB(ctx.params.instanceId) |
|||
ctx.body = await db.remove(ctx.params.id, ctx.params.rev) |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/accesslevel") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.post("/api/:instanceId/accesslevels", controller.create) |
|||
.put("/api/:instanceId/accesslevels", controller.update) |
|||
.get("/api/:instanceId/accesslevels", controller.fetch) |
|||
.get("/api/:instanceId/accesslevels/:levelId", controller.find) |
|||
.delete("/api/:instanceId/accesslevels/:levelId/:rev", controller.destroy) |
|||
.patch("/api/:instanceId/accesslevels/:levelId", controller.patch) |
|||
|
|||
module.exports = router |
|||
@ -1,11 +1,17 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/application") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/applications", controller.fetch) |
|||
.get("/api/:applicationId/appPackage", controller.fetchAppPackage) |
|||
.post("/api/applications", controller.create) |
|||
.get("/api/applications", authorized(BUILDER), controller.fetch) |
|||
.get( |
|||
"/api/:applicationId/appPackage", |
|||
authorized(BUILDER), |
|||
controller.fetchAppPackage |
|||
) |
|||
.post("/api/applications", authorized(BUILDER), controller.create) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -1,8 +1,10 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/client") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router.get("/api/client/id", controller.getClientId) |
|||
router.get("/api/client/id", authorized(BUILDER), controller.getClientId) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -1,10 +1,12 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/instance") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.post("/api/:applicationId/instances", controller.create) |
|||
.delete("/api/instances/:instanceId", controller.destroy) |
|||
.post("/api/:applicationId/instances", authorized(BUILDER), controller.create) |
|||
.delete("/api/instances/:instanceId", authorized(BUILDER), controller.destroy) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -1,12 +1,49 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/model") |
|||
const modelController = require("../controllers/model") |
|||
const recordController = require("../controllers/record") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { |
|||
READ_MODEL, |
|||
WRITE_MODEL, |
|||
BUILDER, |
|||
} = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
// records
|
|||
|
|||
router |
|||
.get( |
|||
"/api/:instanceId/:modelId/records", |
|||
authorized(READ_MODEL, ctx => ctx.params.modelId), |
|||
recordController.fetchModel |
|||
) |
|||
.get( |
|||
"/api/:instanceId/:modelId/records/:recordId", |
|||
authorized(READ_MODEL, ctx => ctx.params.modelId), |
|||
recordController.find |
|||
) |
|||
.post( |
|||
"/api/:instanceId/:modelId/records", |
|||
authorized(WRITE_MODEL, ctx => ctx.params.modelId), |
|||
recordController.save |
|||
) |
|||
.delete( |
|||
"/api/:instanceId/:modelId/records/:recordId/:revId", |
|||
authorized(WRITE_MODEL, ctx => ctx.params.modelId), |
|||
recordController.destroy |
|||
) |
|||
|
|||
// models
|
|||
|
|||
router |
|||
.get("/api/:instanceId/models", controller.fetch) |
|||
.post("/api/:instanceId/models", controller.create) |
|||
.get("/api/:instanceId/models", authorized(BUILDER), modelController.fetch) |
|||
.post("/api/:instanceId/models", authorized(BUILDER), modelController.create) |
|||
// .patch("/api/:instanceId/models", controller.update)
|
|||
.delete("/api/:instanceId/models/:modelId/:revId", controller.destroy) |
|||
.delete( |
|||
"/api/:instanceId/models/:modelId/:revId", |
|||
authorized(BUILDER), |
|||
modelController.destroy |
|||
) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -1,12 +0,0 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/record") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/:instanceId/:viewName/records", controller.fetch) |
|||
.get("/api/:instanceId/records/:recordId", controller.find) |
|||
.post("/api/:instanceId/records", controller.save) |
|||
.delete("/api/:instanceId/records/:recordId/:revId", controller.destroy) |
|||
|
|||
module.exports = router |
|||
@ -1,11 +1,17 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/screen") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/:instanceId/screens", controller.fetch) |
|||
.post("/api/:instanceId/screens", controller.save) |
|||
.delete("/api/:instanceId/:screenId/:revId", controller.destroy) |
|||
.get("/api/:instanceId/screens", authorized(BUILDER), controller.fetch) |
|||
.post("/api/:instanceId/screens", authorized(BUILDER), controller.save) |
|||
.delete( |
|||
"/api/:instanceId/:screenId/:revId", |
|||
authorized(BUILDER), |
|||
controller.destroy |
|||
) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -0,0 +1,184 @@ |
|||
const { |
|||
createInstance, |
|||
createClientDatabase, |
|||
createApplication, |
|||
createModel, |
|||
createView, |
|||
supertest, |
|||
defaultHeaders |
|||
} = require("./couchTestUtils") |
|||
const { |
|||
generateAdminPermissions, |
|||
generatePowerUserPermissions, |
|||
POWERUSER_LEVEL_ID, |
|||
ADMIN_LEVEL_ID, |
|||
READ_MODEL, |
|||
WRITE_MODEL, |
|||
} = require("../../../utilities/accessLevels") |
|||
|
|||
describe("/accesslevels", () => { |
|||
let appId |
|||
let server |
|||
let request |
|||
let instanceId |
|||
let model |
|||
let view |
|||
|
|||
beforeAll(async () => { |
|||
({ request, server } = await supertest()) |
|||
await createClientDatabase(request); |
|||
appId = (await createApplication(request))._id |
|||
}); |
|||
|
|||
afterAll(async () => { |
|||
server.close(); |
|||
}) |
|||
|
|||
beforeEach(async () => { |
|||
instanceId = (await createInstance(request, appId))._id |
|||
model = await createModel(request, instanceId) |
|||
view = await createView(request, instanceId) |
|||
}) |
|||
|
|||
describe("create", () => { |
|||
|
|||
it("returns a success message when level is successfully created", async () => { |
|||
const res = await request |
|||
.post(`/api/${instanceId}/accesslevels`) |
|||
.send({ name: "user" }) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.res.statusMessage).toEqual("Access Level 'user' created successfully.") |
|||
expect(res.body._id).toBeDefined() |
|||
expect(res.body._rev).toBeDefined() |
|||
expect(res.body.permissions).toEqual([]) |
|||
}) |
|||
|
|||
}); |
|||
|
|||
describe("fetch", () => { |
|||
|
|||
it("should list custom levels, plus 2 default levels", async () => { |
|||
const createRes = await request |
|||
.post(`/api/${instanceId}/accesslevels`) |
|||
.send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL }] }) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const customLevel = createRes.body |
|||
|
|||
const res = await request |
|||
.get(`/api/${instanceId}/accesslevels`) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.body.length).toBe(3) |
|||
|
|||
const adminLevel = res.body.find(r => r._id === ADMIN_LEVEL_ID) |
|||
expect(adminLevel).toBeDefined() |
|||
expect(adminLevel.permissions).toEqual(await generateAdminPermissions(instanceId)) |
|||
|
|||
const powerUserLevel = res.body.find(r => r._id === POWERUSER_LEVEL_ID) |
|||
expect(powerUserLevel).toBeDefined() |
|||
expect(powerUserLevel.permissions).toEqual(await generatePowerUserPermissions(instanceId)) |
|||
|
|||
const customLevelFetched = res.body.find(r => r._id === customLevel._id) |
|||
expect(customLevelFetched.permissions).toEqual(customLevel.permissions) |
|||
}) |
|||
|
|||
}); |
|||
|
|||
describe("destroy", () => { |
|||
it("should delete custom access level", async () => { |
|||
const createRes = await request |
|||
.post(`/api/${instanceId}/accesslevels`) |
|||
.send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL } ] }) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const customLevel = createRes.body |
|||
|
|||
await request |
|||
.delete(`/api/${instanceId}/accesslevels/${customLevel._id}/${customLevel._rev}`) |
|||
.set(defaultHeaders) |
|||
.expect(200) |
|||
|
|||
await request |
|||
.get(`/api/${instanceId}/accesslevels/${customLevel._id}`) |
|||
.set(defaultHeaders) |
|||
.expect(404) |
|||
}) |
|||
}) |
|||
|
|||
describe("patch", () => { |
|||
it("should add given permissions", async () => { |
|||
const createRes = await request |
|||
.post(`/api/${instanceId}/accesslevels`) |
|||
.send({ name: "user", permissions: [ { itemId: model._id, name: READ_MODEL }] }) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const customLevel = createRes.body |
|||
|
|||
await request |
|||
.patch(`/api/${instanceId}/accesslevels/${customLevel._id}`) |
|||
.send({ |
|||
_rev: customLevel._rev, |
|||
addedPermissions: [ { itemId: model._id, name: WRITE_MODEL } ] |
|||
}) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const finalRes = await request |
|||
.get(`/api/${instanceId}/accesslevels/${customLevel._id}`) |
|||
.set(defaultHeaders) |
|||
.expect(200) |
|||
|
|||
expect(finalRes.body.permissions.length).toBe(2) |
|||
expect(finalRes.body.permissions.some(p => p.name === WRITE_MODEL)).toBe(true) |
|||
expect(finalRes.body.permissions.some(p => p.name === READ_MODEL)).toBe(true) |
|||
}) |
|||
|
|||
it("should remove given permissions", async () => { |
|||
const createRes = await request |
|||
.post(`/api/${instanceId}/accesslevels`) |
|||
.send({ |
|||
name: "user", |
|||
permissions: [ |
|||
{ itemId: model._id, name: READ_MODEL }, |
|||
{ itemId: model._id, name: WRITE_MODEL }, |
|||
] |
|||
}) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const customLevel = createRes.body |
|||
|
|||
await request |
|||
.patch(`/api/${instanceId}/accesslevels/${customLevel._id}`) |
|||
.send({ |
|||
_rev: customLevel._rev, |
|||
removedPermissions: [ { itemId: model._id, name: WRITE_MODEL }] |
|||
}) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
const finalRes = await request |
|||
.get(`/api/${instanceId}/accesslevels/${customLevel._id}`) |
|||
.set(defaultHeaders) |
|||
.expect(200) |
|||
|
|||
expect(finalRes.body.permissions.length).toBe(1) |
|||
expect(finalRes.body.permissions.some(p => p.name === READ_MODEL)).toBe(true) |
|||
}) |
|||
}) |
|||
}); |
|||
@ -0,0 +1,114 @@ |
|||
const { |
|||
createClientDatabase, |
|||
createApplication, |
|||
createInstance, |
|||
defaultHeaders, |
|||
supertest, |
|||
insertDocument, |
|||
destroyDocument |
|||
} = require("./couchTestUtils") |
|||
|
|||
const TEST_WORKFLOW = { |
|||
_id: "Test Workflow", |
|||
name: "My Workflow", |
|||
pageId: "123123123", |
|||
screenId: "kasdkfldsafkl", |
|||
live: true, |
|||
uiTree: { |
|||
|
|||
}, |
|||
definition: { |
|||
triggers: [ |
|||
|
|||
], |
|||
next: { |
|||
actionId: "abc123", |
|||
type: "SERVER", |
|||
conditions: { |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
describe("/workflows", () => { |
|||
let request |
|||
let server |
|||
let app |
|||
let instance |
|||
let workflow |
|||
|
|||
beforeAll(async () => { |
|||
({ request, server } = await supertest()) |
|||
await createClientDatabase(request) |
|||
app = await createApplication(request) |
|||
}) |
|||
|
|||
beforeEach(async () => { |
|||
instance = await createInstance(request, app._id) |
|||
if (workflow) await destroyDocument(workflow.id); |
|||
}) |
|||
|
|||
afterAll(async () => { |
|||
server.close() |
|||
}) |
|||
|
|||
const createWorkflow = async () => { |
|||
workflow = await insertDocument(instance._id, { |
|||
type: "workflow", |
|||
...TEST_WORKFLOW |
|||
}); |
|||
} |
|||
|
|||
describe("create", () => { |
|||
it("returns a success message when the workflow is successfully created", async () => { |
|||
const res = await request |
|||
.post(`/api/${instance._id}/workflows`) |
|||
.set(defaultHeaders) |
|||
.send(TEST_WORKFLOW) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.body.message).toEqual("Workflow created successfully"); |
|||
expect(res.body.workflow.name).toEqual("My Workflow"); |
|||
}) |
|||
}) |
|||
|
|||
describe("fetch", () => { |
|||
it("return all the workflows for an instance", async () => { |
|||
await createWorkflow(); |
|||
const res = await request |
|||
.get(`/api/${instance._id}/workflows`) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.body[0]).toEqual(expect.objectContaining(TEST_WORKFLOW)); |
|||
}) |
|||
}) |
|||
|
|||
describe("find", () => { |
|||
it("returns a workflow when queried by ID", async () => { |
|||
await createWorkflow(); |
|||
const res = await request |
|||
.get(`/api/${instance._id}/workflows/${workflow.id}`) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.body).toEqual(expect.objectContaining(TEST_WORKFLOW)); |
|||
}) |
|||
}) |
|||
|
|||
describe("destroy", () => { |
|||
it("deletes a workflow by its ID", async () => { |
|||
await createWorkflow(); |
|||
const res = await request |
|||
.delete(`/api/${instance._id}/workflows/${workflow.id}/${workflow.rev}`) |
|||
.set(defaultHeaders) |
|||
.expect('Content-Type', /json/) |
|||
.expect(200) |
|||
|
|||
expect(res.body.id).toEqual(TEST_WORKFLOW._id); |
|||
}) |
|||
}) |
|||
}); |
|||
@ -1,12 +1,26 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/user") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { USER_MANAGEMENT, LIST_USERS } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/:instanceId/users", controller.fetch) |
|||
.get("/api/:instanceId/users/:username", controller.find) |
|||
.post("/api/:instanceId/users", controller.create) |
|||
.delete("/api/:instanceId/users/:username", controller.destroy) |
|||
.get("/api/:instanceId/users", authorized(LIST_USERS), controller.fetch) |
|||
.get( |
|||
"/api/:instanceId/users/:username", |
|||
authorized(USER_MANAGEMENT), |
|||
controller.find |
|||
) |
|||
.post( |
|||
"/api/:instanceId/users", |
|||
authorized(USER_MANAGEMENT), |
|||
controller.create |
|||
) |
|||
.delete( |
|||
"/api/:instanceId/users/:username", |
|||
authorized(USER_MANAGEMENT), |
|||
controller.destroy |
|||
) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -1,12 +1,20 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/view") |
|||
const viewController = require("../controllers/view") |
|||
const recordController = require("../controllers/record") |
|||
const authorized = require("../../middleware/authorized") |
|||
const { BUILDER, READ_VIEW } = require("../../utilities/accessLevels") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/:instanceId/views", controller.fetch) |
|||
.get( |
|||
"/api/:instanceId/view/:viewName", |
|||
authorized(READ_VIEW, ctx => ctx.params.viewName), |
|||
recordController.fetchView |
|||
) |
|||
.get("/api/:instanceId/views", authorized(BUILDER), viewController.fetch) |
|||
// .patch("/api/:databaseId/views", controller.update);
|
|||
// .delete("/api/:instanceId/views/:viewId/:revId", controller.destroy);
|
|||
.post("/api/:instanceId/views", controller.create) |
|||
.post("/api/:instanceId/views", authorized(BUILDER), viewController.create) |
|||
|
|||
module.exports = router |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
const Router = require("@koa/router") |
|||
const controller = require("../controllers/workflow") |
|||
|
|||
const router = Router() |
|||
|
|||
router |
|||
.get("/api/:instanceId/workflows", controller.fetch) |
|||
.get("/api/:instanceId/workflows/:id", controller.find) |
|||
.post("/api/:instanceId/workflows", controller.create) |
|||
.put("/api/:instanceId/workflows/:id", controller.update) |
|||
.delete("/api/:instanceId/workflows/:id/:rev", controller.destroy) |
|||
|
|||
module.exports = router |
|||
@ -0,0 +1,58 @@ |
|||
const { |
|||
adminPermissions, |
|||
ADMIN_LEVEL_ID, |
|||
POWERUSER_LEVEL_ID, |
|||
BUILDER, |
|||
} = require("../utilities/accessLevels") |
|||
|
|||
module.exports = (permName, getItemId) => async (ctx, next) => { |
|||
if (!ctx.isAuthenticated) { |
|||
ctx.throw(403, "Session not authenticated") |
|||
} |
|||
|
|||
if (ctx.isBuilder) { |
|||
await next() |
|||
return |
|||
} |
|||
|
|||
if (permName === BUILDER) { |
|||
ctx.throw(403, "Not Authorized") |
|||
return |
|||
} |
|||
|
|||
if (!ctx.user) { |
|||
ctx.throw(403, "User not found") |
|||
} |
|||
|
|||
const permissionId = ({ name, itemId }) => name + (itemId ? `-${itemId}` : "") |
|||
|
|||
if (ctx.user.accessLevel._id === ADMIN_LEVEL_ID) { |
|||
await next() |
|||
return |
|||
} |
|||
|
|||
const thisPermissionId = { |
|||
name: permName, |
|||
itemId: getItemId && getItemId(ctx), |
|||
} |
|||
|
|||
// power user has everything, except the admin specific perms
|
|||
if ( |
|||
ctx.user.accessLevel._id === POWERUSER_LEVEL_ID && |
|||
!adminPermissions.map(permissionId).includes(thisPermissionId) |
|||
) { |
|||
await next() |
|||
return |
|||
} |
|||
|
|||
if ( |
|||
ctx.user.accessLevel.permissions |
|||
.map(permissionId) |
|||
.includes(thisPermissionId) |
|||
) { |
|||
await next() |
|||
return |
|||
} |
|||
|
|||
ctx.throw(403, "Not Authorized") |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
const WORKFLOW_SCHEMA = { |
|||
properties: { |
|||
type: "workflow", |
|||
pageId: { |
|||
type: "string" |
|||
}, |
|||
screenId: { |
|||
type: "string" |
|||
}, |
|||
live: { |
|||
type: "boolean" |
|||
}, |
|||
uiTree: { |
|||
type: "object" |
|||
}, |
|||
definition: { |
|||
type: "object", |
|||
properties: { |
|||
triggers: { type: "array" }, |
|||
next: { |
|||
type: "object", |
|||
properties: { |
|||
type: { type: "string" }, |
|||
actionId: { type: "string" }, |
|||
args: { type: "object" }, |
|||
conditions: { type: "array" }, |
|||
errorHandling: { type: "object" }, |
|||
next: { type: "object" } |
|||
} |
|||
}, |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
module.exports = { |
|||
WORKFLOW_SCHEMA |
|||
}; |
|||
@ -0,0 +1,64 @@ |
|||
const viewController = require("../api/controllers/view") |
|||
const modelController = require("../api/controllers/model") |
|||
|
|||
exports.ADMIN_LEVEL_ID = "ADMIN" |
|||
exports.POWERUSER_LEVEL_ID = "POWER_USER" |
|||
|
|||
exports.READ_MODEL = "read-model" |
|||
exports.WRITE_MODEL = "write-model" |
|||
exports.READ_VIEW = "read-view" |
|||
exports.EXECUTE_WORKFLOW = "execute-workflow" |
|||
exports.USER_MANAGEMENT = "user-management" |
|||
exports.BUILDER = "builder" |
|||
exports.LIST_USERS = "list-users" |
|||
|
|||
exports.adminPermissions = [ |
|||
{ |
|||
name: exports.USER_MANAGEMENT, |
|||
}, |
|||
] |
|||
|
|||
exports.generateAdminPermissions = async instanceId => [ |
|||
...exports.adminPermissions, |
|||
...(await exports.generatePowerUserPermissions(instanceId)), |
|||
] |
|||
|
|||
exports.generatePowerUserPermissions = async instanceId => { |
|||
const fetchModelsCtx = { |
|||
params: { |
|||
instanceId, |
|||
}, |
|||
} |
|||
await modelController.fetch(fetchModelsCtx) |
|||
const models = fetchModelsCtx.body |
|||
|
|||
const fetchViewsCtx = { |
|||
params: { |
|||
instanceId, |
|||
}, |
|||
} |
|||
await viewController.fetch(fetchViewsCtx) |
|||
const views = fetchViewsCtx.body |
|||
|
|||
const readModelPermissions = models.map(m => ({ |
|||
itemId: m._id, |
|||
name: exports.READ_MODEL, |
|||
})) |
|||
|
|||
const writeModelPermissions = models.map(m => ({ |
|||
itemId: m._id, |
|||
name: exports.WRITE_MODEL, |
|||
})) |
|||
|
|||
const viewPermissions = views.map(v => ({ |
|||
itemId: v.name, |
|||
name: exports.READ_VIEW, |
|||
})) |
|||
|
|||
return [ |
|||
...readModelPermissions, |
|||
...writeModelPermissions, |
|||
...viewPermissions, |
|||
{ name: exports.LIST_USERS }, |
|||
] |
|||
} |
|||
@ -0,0 +1 @@ |
|||
dist/ |
|||
@ -0,0 +1,11 @@ |
|||
{ |
|||
"name": "name", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"author": "", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"@budibase/standard-components": "0.x", |
|||
"@budibase/materialdesign-components": "0.x" |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": [], |
|||
"componentLibraries": ["@budibase/standard-components", "@budibase/materialdesign-components"], |
|||
"props" : { |
|||
"_component": "@budibase/standard-components/container", |
|||
"_children": [], |
|||
"_id": 0, |
|||
"type": "div", |
|||
"_styles": { |
|||
"layout": {}, |
|||
"position": {} |
|||
}, |
|||
"_code": "" |
|||
}, |
|||
"_css": "", |
|||
"uiFunctions": "" |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
{ |
|||
"title": "Test App", |
|||
"favicon": "./_shared/favicon.png", |
|||
"stylesheets": [], |
|||
"componentLibraries": ["@budibase/standard-components", "@budibase/materialdesign-components"], |
|||
"props" : { |
|||
"_component": "@budibase/standard-components/container", |
|||
"_children": [], |
|||
"_id": 1, |
|||
"type": "div", |
|||
"_styles": { |
|||
"layout": {}, |
|||
"position": {} |
|||
}, |
|||
"_code": "" |
|||
}, |
|||
"_css": "", |
|||
"uiFunctions": "" |
|||
} |
|||
@ -0,0 +1 @@ |
|||
module.exports = () => ({}) |
|||
Loading…
Reference in new issue