2021-06-12 05:56:30 +12:00
|
|
|
const validateJs = require("validate.js")
|
|
|
|
const { cloneDeep } = require("lodash/fp")
|
|
|
|
const { InternalTables } = require("../../../db/utils")
|
|
|
|
const userController = require("../user")
|
|
|
|
const { FieldTypes } = require("../../../constants")
|
2021-10-29 07:39:42 +13:00
|
|
|
const { makeExternalQuery } = require("../../../integrations/base/utils")
|
2022-01-28 07:18:31 +13:00
|
|
|
const { getAppDB } = require("@budibase/backend-core/context")
|
2021-06-12 05:56:30 +12:00
|
|
|
|
|
|
|
validateJs.extend(validateJs.validators.datetime, {
|
|
|
|
parse: function (value) {
|
|
|
|
return new Date(value).getTime()
|
|
|
|
},
|
|
|
|
// Input is a unix timestamp
|
|
|
|
format: function (value) {
|
|
|
|
return new Date(value).toISOString()
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2022-01-28 07:18:31 +13:00
|
|
|
exports.getDatasourceAndQuery = async json => {
|
2021-06-15 06:05:39 +12:00
|
|
|
const datasourceId = json.endpoint.datasourceId
|
2022-01-28 07:18:31 +13:00
|
|
|
const db = getAppDB()
|
2021-06-17 02:54:14 +12:00
|
|
|
const datasource = await db.get(datasourceId)
|
2021-10-29 07:39:42 +13:00
|
|
|
return makeExternalQuery(datasource, json)
|
2021-06-15 06:05:39 +12:00
|
|
|
}
|
|
|
|
|
2022-01-28 07:18:31 +13:00
|
|
|
exports.findRow = async (ctx, tableId, rowId) => {
|
|
|
|
const db = getAppDB()
|
2021-06-12 05:56:30 +12:00
|
|
|
let row
|
|
|
|
// TODO remove special user case in future
|
|
|
|
if (tableId === InternalTables.USER_METADATA) {
|
|
|
|
ctx.params = {
|
|
|
|
id: rowId,
|
|
|
|
}
|
|
|
|
await userController.findMetadata(ctx)
|
|
|
|
row = ctx.body
|
|
|
|
} else {
|
|
|
|
row = await db.get(rowId)
|
|
|
|
}
|
|
|
|
if (row.tableId !== tableId) {
|
|
|
|
throw "Supplied tableId does not match the rows tableId"
|
|
|
|
}
|
|
|
|
return row
|
|
|
|
}
|
|
|
|
|
2022-01-28 07:18:31 +13:00
|
|
|
exports.validate = async ({ tableId, row, table }) => {
|
2021-06-12 05:56:30 +12:00
|
|
|
if (!table) {
|
2022-01-28 07:18:31 +13:00
|
|
|
const db = getAppDB()
|
2021-06-12 05:56:30 +12:00
|
|
|
table = await db.get(tableId)
|
|
|
|
}
|
|
|
|
const errors = {}
|
|
|
|
for (let fieldName of Object.keys(table.schema)) {
|
|
|
|
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
2021-11-30 06:54:09 +13:00
|
|
|
const type = table.schema[fieldName].type
|
2022-02-22 04:01:42 +13:00
|
|
|
// formulas shouldn't validated, data will be deleted anyway
|
|
|
|
if (type === FieldTypes.FORMULA) {
|
|
|
|
continue
|
|
|
|
}
|
2021-06-12 05:56:30 +12:00
|
|
|
// special case for options, need to always allow unselected (null)
|
2022-01-19 02:20:28 +13:00
|
|
|
if (type === FieldTypes.OPTIONS && constraints.inclusion) {
|
2021-06-12 05:56:30 +12:00
|
|
|
constraints.inclusion.push(null)
|
|
|
|
}
|
2021-08-20 03:54:44 +12:00
|
|
|
let res
|
|
|
|
|
2021-08-28 01:10:19 +12:00
|
|
|
// Validate.js doesn't seem to handle array
|
2022-01-18 23:38:39 +13:00
|
|
|
if (type === FieldTypes.ARRAY && row[fieldName]) {
|
|
|
|
if (row[fieldName].length) {
|
2022-01-19 02:20:28 +13:00
|
|
|
row[fieldName].map(val => {
|
2022-04-07 22:01:05 +12:00
|
|
|
if (
|
|
|
|
!constraints.inclusion.includes(val) &&
|
|
|
|
constraints.inclusion.length !== 0
|
|
|
|
) {
|
2022-01-18 23:38:39 +13:00
|
|
|
errors[fieldName] = "Field not in list"
|
2022-01-19 02:20:28 +13:00
|
|
|
}
|
|
|
|
})
|
2022-01-18 23:38:39 +13:00
|
|
|
} else if (constraints.presence && row[fieldName].length === 0) {
|
|
|
|
// non required MultiSelect creates an empty array, which should not throw errors
|
|
|
|
errors[fieldName] = [`${fieldName} is required`]
|
2022-01-19 02:20:28 +13:00
|
|
|
}
|
2021-11-30 07:16:44 +13:00
|
|
|
} else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
|
|
|
|
// this should only happen if there is an error
|
|
|
|
try {
|
|
|
|
JSON.parse(row[fieldName])
|
|
|
|
} catch (err) {
|
|
|
|
errors[fieldName] = [`Contains invalid JSON`]
|
|
|
|
}
|
2021-08-20 03:54:44 +12:00
|
|
|
} else {
|
|
|
|
res = validateJs.single(row[fieldName], constraints)
|
|
|
|
}
|
2021-06-12 05:56:30 +12:00
|
|
|
if (res) errors[fieldName] = res
|
|
|
|
}
|
|
|
|
return { valid: Object.keys(errors).length === 0, errors }
|
|
|
|
}
|