Moving validators to a single location, simplify route files and all re-usability.

This commit is contained in:
mike12345567 2022-02-24 11:39:38 +00:00
parent 88e0f67f42
commit bc87e2b562
11 changed files with 205 additions and 197 deletions

View File

@ -18,10 +18,6 @@ function Webhook(name, type, target) {
exports.Webhook = Webhook
exports.WebhookType = {
AUTOMATION: "automation",
}
exports.fetch = async ctx => {
const db = getAppDB()
const response = await db.allDocs(

View File

@ -1,50 +1,20 @@
const Router = require("@koa/router")
const controller = require("../controllers/automation")
const authorized = require("../../middleware/authorized")
const joiValidator = require("../../middleware/joi-validator")
const {
BUILDER,
PermissionLevels,
PermissionTypes,
} = require("@budibase/backend-core/permissions")
const Joi = require("joi")
const { bodyResource, paramResource } = require("../../middleware/resourceId")
const {
middleware: appInfoMiddleware,
AppType,
} = require("../../middleware/appInfo")
const { automationValidator } = require("./utils/validators")
const router = Router()
// prettier-ignore
function generateStepSchema(allowStepTypes) {
return Joi.object({
stepId: Joi.string().required(),
id: Joi.string().required(),
description: Joi.string().required(),
name: Joi.string().required(),
tagline: Joi.string().required(),
icon: Joi.string().required(),
params: Joi.object(),
args: Joi.object(),
type: Joi.string().required().valid(...allowStepTypes),
}).unknown(true)
}
function generateValidator(existing = false) {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: existing ? Joi.string().required() : Joi.string(),
_rev: existing ? Joi.string().required() : Joi.string(),
name: Joi.string().required(),
type: Joi.string().valid("automation").required(),
definition: Joi.object({
steps: Joi.array().required().items(generateStepSchema(["ACTION", "LOGIC"])),
trigger: generateStepSchema(["TRIGGER"]).allow(null),
}).required().unknown(true),
}).unknown(true))
}
router
.get(
"/api/automations/trigger/list",
@ -72,13 +42,13 @@ router
"/api/automations",
bodyResource("_id"),
authorized(BUILDER),
generateValidator(true),
automationValidator(true),
controller.update
)
.post(
"/api/automations",
authorized(BUILDER),
generateValidator(false),
automationValidator(false),
controller.create
)
.delete(

View File

@ -1,64 +1,18 @@
const Router = require("@koa/router")
const datasourceController = require("../controllers/datasource")
const authorized = require("../../middleware/authorized")
const joiValidator = require("../../middleware/joi-validator")
const {
BUILDER,
PermissionLevels,
PermissionTypes,
} = require("@budibase/backend-core/permissions")
const Joi = require("joi")
const { DataSourceOperation } = require("../../constants")
const {
datasourceValidator,
datasourceQueryValidator,
} = require("./utils/validators")
const router = Router()
function generateDatasourceSchema() {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string(),
_rev: Joi.string(),
// source: Joi.string().valid("POSTGRES_PLUS"),
type: Joi.string().allow("datasource_plus"),
relationships: Joi.array().items(Joi.object({
from: Joi.string().required(),
to: Joi.string().required(),
cardinality: Joi.valid("1:N", "1:1", "N:N").required()
})),
// entities: Joi.array().items(Joi.object({
// type: Joi.string().valid(...Object.values(FieldTypes)).required(),
// name: Joi.string().required(),
// })),
}).unknown(true))
}
function generateQueryDatasourceSchema() {
// prettier-ignore
return joiValidator.body(Joi.object({
endpoint: Joi.object({
datasourceId: Joi.string().required(),
operation: Joi.string().required().valid(...Object.values(DataSourceOperation)),
entityId: Joi.string().required(),
}).required(),
resource: Joi.object({
fields: Joi.array().items(Joi.string()).optional(),
}).optional(),
body: Joi.object().optional(),
sort: Joi.object().optional(),
filters: Joi.object({
string: Joi.object().optional(),
range: Joi.object().optional(),
equal: Joi.object().optional(),
notEqual: Joi.object().optional(),
empty: Joi.object().optional(),
notEmpty: Joi.object().optional(),
}).optional(),
paginate: Joi.object({
page: Joi.string().alphanum().optional(),
limit: Joi.number().optional(),
}).optional(),
}))
}
router
.get("/api/datasources", authorized(BUILDER), datasourceController.fetch)
.get(
@ -74,7 +28,7 @@ router
.post(
"/api/datasources/query",
authorized(PermissionTypes.TABLE, PermissionLevels.READ),
generateQueryDatasourceSchema(),
datasourceQueryValidator(),
datasourceController.query
)
.post(
@ -85,7 +39,7 @@ router
.post(
"/api/datasources",
authorized(BUILDER),
generateDatasourceSchema(),
datasourceValidator(),
datasourceController.save
)
.delete(

View File

@ -1,25 +1,11 @@
const Router = require("@koa/router")
const controller = require("../controllers/permission")
const authorized = require("../../middleware/authorized")
const {
BUILDER,
PermissionLevels,
} = require("@budibase/backend-core/permissions")
const Joi = require("joi")
const joiValidator = require("../../middleware/joi-validator")
const { BUILDER } = require("@budibase/backend-core/permissions")
const { permissionValidator } = require("./utils/validators")
const router = Router()
function generateValidator() {
const permLevelArray = Object.values(PermissionLevels)
// prettier-ignore
return joiValidator.params(Joi.object({
level: Joi.string().valid(...permLevelArray).required(),
resourceId: Joi.string(),
roleId: Joi.string(),
}).unknown(true))
}
router
.get("/api/permission/builtin", authorized(BUILDER), controller.fetchBuiltin)
.get("/api/permission/levels", authorized(BUILDER), controller.fetchLevels)
@ -33,14 +19,14 @@ router
.post(
"/api/permission/:roleId/:resourceId/:level",
authorized(BUILDER),
generateValidator(),
permissionValidator(),
controller.addPermission
)
// deleting the level defaults it back the underlying access control for the resource
.delete(
"/api/permission/:roleId/:resourceId/:level",
authorized(BUILDER),
generateValidator(),
permissionValidator(),
controller.removePermission
)

View File

@ -1,5 +1,6 @@
const controller = require("../../controllers/public/tables")
const Endpoint = require("./utils/Endpoint")
const { tableValidator } = require("../utils/validators")
const read = [],
write = []
@ -66,7 +67,11 @@ read.push(new Endpoint("post", "/tables/search", controller.search))
* table:
* $ref: '#/components/examples/table'
*/
write.push(new Endpoint("post", "/tables", controller.create))
write.push(
new Endpoint("post", "/tables", controller.create).addMiddleware(
tableValidator()
)
)
/**
* @openapi
@ -97,7 +102,11 @@ write.push(new Endpoint("post", "/tables", controller.create))
* table:
* $ref: '#/components/examples/table'
*/
write.push(new Endpoint("put", "/tables/:tableId", controller.update))
write.push(
new Endpoint("put", "/tables/:tableId", controller.update).addMiddleware(
tableValidator()
)
)
/**
* @openapi

View File

@ -1,34 +1,13 @@
const Router = require("@koa/router")
const controller = require("../controllers/role")
const authorized = require("../../middleware/authorized")
const Joi = require("joi")
const joiValidator = require("../../middleware/joi-validator")
const {
BUILTIN_PERMISSION_IDS,
BUILDER,
PermissionLevels,
} = require("@budibase/backend-core/permissions")
const { BUILDER } = require("@budibase/backend-core/permissions")
const { roleValidator } = require("./utils/validators")
const router = Router()
function generateValidator() {
const permLevelArray = Object.values(PermissionLevels)
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string().optional(),
_rev: Joi.string().optional(),
name: Joi.string().required(),
// this is the base permission ID (for now a built in)
permissionId: Joi.string().valid(...Object.values(BUILTIN_PERMISSION_IDS)).required(),
permissions: Joi.object()
.pattern(/.*/, [Joi.string().valid(...permLevelArray)])
.optional(),
inherits: Joi.string().optional(),
}).unknown(true))
}
router
.post("/api/roles", authorized(BUILDER), generateValidator(), controller.save)
.post("/api/roles", authorized(BUILDER), roleValidator(), controller.save)
.get("/api/roles", authorized(BUILDER), controller.fetch)
.get("/api/roles/:roleId", authorized(BUILDER), controller.find)
.delete("/api/roles/:roleId/:rev", authorized(BUILDER), controller.destroy)

View File

@ -2,40 +2,13 @@ const Router = require("@koa/router")
const controller = require("../controllers/screen")
const authorized = require("../../middleware/authorized")
const { BUILDER } = require("@budibase/backend-core/permissions")
const joiValidator = require("../../middleware/joi-validator")
const Joi = require("joi")
const { screenValidator } = require("./utils/validators")
const router = Router()
function generateSaveValidation() {
// prettier-ignore
return joiValidator.body(Joi.object({
name: Joi.string().required(),
routing: Joi.object({
route: Joi.string().required(),
roleId: Joi.string().required().allow(""),
}).required().unknown(true),
props: Joi.object({
_id: Joi.string().required(),
_component: Joi.string().required(),
_children: Joi.array().required(),
_instanceName: Joi.string().required(),
_styles: Joi.object().required(),
type: Joi.string().optional(),
table: Joi.string().optional(),
layoutId: Joi.string().optional(),
}).required().unknown(true),
}).unknown(true))
}
router
.get("/api/screens", authorized(BUILDER), controller.fetch)
.post(
"/api/screens",
authorized(BUILDER),
generateSaveValidation(),
controller.save
)
.post("/api/screens", authorized(BUILDER), screenValidator(), controller.save)
.delete(
"/api/screens/:screenId/:screenRev",
authorized(BUILDER),

View File

@ -7,25 +7,10 @@ const {
PermissionLevels,
PermissionTypes,
} = require("@budibase/backend-core/permissions")
const joiValidator = require("../../middleware/joi-validator")
const Joi = require("joi")
const { tableValidator } = require("./utils/validators")
const router = Router()
function generateSaveValidator() {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string(),
_rev: Joi.string(),
type: Joi.string().valid("table", "internal", "external"),
primaryDisplay: Joi.string(),
schema: Joi.object().required(),
name: Joi.string().required(),
views: Joi.object(),
dataImport: Joi.object(),
}).unknown(true))
}
router
/**
* @api {get} /api/tables Fetch all tables
@ -136,7 +121,7 @@ router
// allows control over updating a table
bodyResource("_id"),
authorized(BUILDER),
generateSaveValidator(),
tableValidator(),
tableController.save
)
/**

View File

@ -0,0 +1,168 @@
const joiValidator = require("../../../middleware/joi-validator")
const { DataSourceOperation } = require("../../../constants")
const { WebhookType } = require("../../../constants")
const {
BUILTIN_PERMISSION_IDS,
PermissionLevels,
} = require("@budibase/backend-core/permissions")
const Joi = require("joi")
exports.tableValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string(),
_rev: Joi.string(),
type: Joi.string().valid("table", "internal", "external"),
primaryDisplay: Joi.string(),
schema: Joi.object().required(),
name: Joi.string().required(),
views: Joi.object(),
dataImport: Joi.object(),
}).unknown(true))
}
exports.nameValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
name: Joi.string(),
}))
}
exports.datasourceValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string(),
_rev: Joi.string(),
// source: Joi.string().valid("POSTGRES_PLUS"),
type: Joi.string().allow("datasource_plus"),
relationships: Joi.array().items(Joi.object({
from: Joi.string().required(),
to: Joi.string().required(),
cardinality: Joi.valid("1:N", "1:1", "N:N").required()
})),
// entities: Joi.array().items(Joi.object({
// type: Joi.string().valid(...Object.values(FieldTypes)).required(),
// name: Joi.string().required(),
// })),
}).unknown(true))
}
exports.datasourceQueryValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
endpoint: Joi.object({
datasourceId: Joi.string().required(),
operation: Joi.string().required().valid(...Object.values(DataSourceOperation)),
entityId: Joi.string().required(),
}).required(),
resource: Joi.object({
fields: Joi.array().items(Joi.string()).optional(),
}).optional(),
body: Joi.object().optional(),
sort: Joi.object().optional(),
filters: Joi.object({
string: Joi.object().optional(),
range: Joi.object().optional(),
equal: Joi.object().optional(),
notEqual: Joi.object().optional(),
empty: Joi.object().optional(),
notEmpty: Joi.object().optional(),
}).optional(),
paginate: Joi.object({
page: Joi.string().alphanum().optional(),
limit: Joi.number().optional(),
}).optional(),
}))
}
exports.webhookValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
live: Joi.bool(),
_id: Joi.string().optional(),
_rev: Joi.string().optional(),
name: Joi.string().required(),
bodySchema: Joi.object().optional(),
action: Joi.object({
type: Joi.string().required().valid(WebhookType.AUTOMATION),
target: Joi.string().required(),
}).required(),
}).unknown(true))
}
exports.roleValidator = () => {
const permLevelArray = Object.values(PermissionLevels)
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string().optional(),
_rev: Joi.string().optional(),
name: Joi.string().required(),
// this is the base permission ID (for now a built in)
permissionId: Joi.string().valid(...Object.values(BUILTIN_PERMISSION_IDS)).required(),
permissions: Joi.object()
.pattern(/.*/, [Joi.string().valid(...permLevelArray)])
.optional(),
inherits: Joi.string().optional(),
}).unknown(true))
}
exports.permissionValidator = () => {
const permLevelArray = Object.values(PermissionLevels)
// prettier-ignore
return joiValidator.params(Joi.object({
level: Joi.string().valid(...permLevelArray).required(),
resourceId: Joi.string(),
roleId: Joi.string(),
}).unknown(true))
}
exports.screenValidator = () => {
// prettier-ignore
return joiValidator.body(Joi.object({
name: Joi.string().required(),
routing: Joi.object({
route: Joi.string().required(),
roleId: Joi.string().required().allow(""),
}).required().unknown(true),
props: Joi.object({
_id: Joi.string().required(),
_component: Joi.string().required(),
_children: Joi.array().required(),
_instanceName: Joi.string().required(),
_styles: Joi.object().required(),
type: Joi.string().optional(),
table: Joi.string().optional(),
layoutId: Joi.string().optional(),
}).required().unknown(true),
}).unknown(true))
}
function generateStepSchema(allowStepTypes) {
// prettier-ignore
return Joi.object({
stepId: Joi.string().required(),
id: Joi.string().required(),
description: Joi.string().required(),
name: Joi.string().required(),
tagline: Joi.string().required(),
icon: Joi.string().required(),
params: Joi.object(),
args: Joi.object(),
type: Joi.string().required().valid(...allowStepTypes),
}).unknown(true)
}
exports.automationValidator = (existing = false) => {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: existing ? Joi.string().required() : Joi.string(),
_rev: existing ? Joi.string().required() : Joi.string(),
name: Joi.string().required(),
type: Joi.string().valid("automation").required(),
definition: Joi.object({
steps: Joi.array().required().items(generateStepSchema(["ACTION", "LOGIC"])),
trigger: generateStepSchema(["TRIGGER"]).allow(null),
}).required().unknown(true),
}).unknown(true))
}

View File

@ -1,33 +1,17 @@
const Router = require("@koa/router")
const controller = require("../controllers/webhook")
const authorized = require("../../middleware/authorized")
const joiValidator = require("../../middleware/joi-validator")
const { BUILDER } = require("@budibase/backend-core/permissions")
const Joi = require("joi")
const { webhookValidator } = require("./utils/validators")
const router = Router()
function generateSaveValidator() {
// prettier-ignore
return joiValidator.body(Joi.object({
live: Joi.bool(),
_id: Joi.string().optional(),
_rev: Joi.string().optional(),
name: Joi.string().required(),
bodySchema: Joi.object().optional(),
action: Joi.object({
type: Joi.string().required().valid(controller.WebhookType.AUTOMATION),
target: Joi.string().required(),
}).required(),
}).unknown(true))
}
router
.get("/api/webhooks", authorized(BUILDER), controller.fetch)
.put(
"/api/webhooks",
authorized(BUILDER),
generateSaveValidator(),
webhookValidator(),
controller.save
)
.delete("/api/webhooks/:id/:rev", authorized(BUILDER), controller.destroy)

View File

@ -186,5 +186,9 @@ exports.BuildSchemaErrors = {
INVALID_COLUMN: "invalid_column",
}
exports.WebhookType = {
AUTOMATION: "automation",
}
// pass through the list from the auth/core lib
exports.ObjectStoreBuckets = ObjectStoreBuckets