@budibase/server 1.0.26 → 1.0.27-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__mocks__/node-fetch.ts +21 -0
- package/builder/assets/bb-spaceship.8f6e81e1.svg +227 -0
- package/builder/assets/{index.4fb3f887.css → index.0dce895b.css} +1 -1
- package/builder/assets/index.b98dd7ca.js +1348 -0
- package/builder/assets/{vendor.470042a4.js → vendor.f9faf6ab.js} +88 -88
- package/builder/index.html +3 -3
- package/coverage/clover.xml +1364 -1121
- package/coverage/coverage-final.json +37 -36
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.js.html +59 -59
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +22 -10
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +4 -4
- package/coverage/lcov-report/api/controllers/datasource.js.html +170 -68
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +39 -54
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +126 -0
- package/coverage/lcov-report/api/controllers/{query.js.html → query/index.js.html} +225 -114
- package/coverage/lcov-report/api/controllers/query/validation.js.html +206 -0
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +22 -22
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +38 -11
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +7 -4
- package/coverage/lcov-report/api/controllers/row/utils.js.html +29 -20
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +108 -9
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +18 -6
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +5 -5
- package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +9 -9
- package/coverage/lcov-report/api/routes/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +19 -85
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/row.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/static.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +32 -2
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +20 -20
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +31 -7
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +11 -11
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +5 -8
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/automations/utils.js.html +48 -15
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +22 -22
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/client.js.html +18 -18
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +15 -15
- package/coverage/lcov-report/db/index.js.html +3 -3
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +4 -4
- package/coverage/lcov-report/db/utils.js.html +107 -80
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +99 -84
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/authorized.js.html +10 -10
- package/coverage/lcov-report/middleware/builder.js.html +8 -8
- package/coverage/lcov-report/middleware/currentapp.js.html +28 -28
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +11 -11
- package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +31 -31
- package/coverage/lcov-report/threads/index.js.html +12 -12
- package/coverage/lcov-report/threads/query.js.html +396 -69
- package/coverage/lcov-report/threads/utils.js.html +358 -13
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +13 -13
- package/coverage/lcov-report/utilities/index.html +19 -19
- package/coverage/lcov-report/utilities/index.js.html +69 -36
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +19 -19
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +235 -10
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +2 -2
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +19 -19
- package/coverage/lcov.info +2294 -1874
- package/dist/api/controllers/automation.js +7 -5
- package/dist/api/controllers/datasource.js +29 -0
- package/dist/api/controllers/query/import/index.js +79 -0
- package/dist/api/controllers/query/import/sources/base/index.js +64 -0
- package/dist/api/controllers/query/import/sources/base/openapi.js +42 -0
- package/dist/api/controllers/query/import/sources/curl.js +96 -0
- package/dist/api/controllers/query/import/sources/openapi2.js +142 -0
- package/dist/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
- package/dist/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
- package/dist/api/controllers/{query.js → query/index.js} +86 -52
- package/dist/api/controllers/query/validation.js +38 -0
- package/dist/api/controllers/row/internal.js +14 -6
- package/dist/api/controllers/row/internalSearch.js +2 -1
- package/dist/api/controllers/row/utils.js +13 -6
- package/dist/api/controllers/user.js +37 -1
- package/dist/api/controllers/webhook.js +4 -0
- package/dist/api/routes/query.js +5 -33
- package/dist/api/routes/user.js +3 -1
- package/dist/automations/steps/executeQuery.js +8 -1
- package/dist/automations/steps/outgoingWebhook.js +2 -3
- package/dist/automations/utils.js +10 -0
- package/dist/db/utils.js +8 -0
- package/dist/definitions/datasource.js +6 -1
- package/dist/integrations/base/sqlTable.js +1 -1
- package/dist/integrations/rest.js +207 -117
- package/dist/package.json +11 -4
- package/dist/tests/utilities/TestConfiguration.js +47 -0
- package/dist/threads/query.js +148 -40
- package/dist/threads/utils.js +105 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/fileSystem/utilities.js +2 -1
- package/dist/utilities/index.js +10 -0
- package/dist/utilities/rowProcessor/index.js +76 -0
- package/package.json +12 -5
- package/src/api/controllers/automation.js +8 -4
- package/src/api/controllers/datasource.js +34 -0
- package/src/api/controllers/query/import/index.ts +85 -0
- package/src/api/controllers/query/import/sources/base/index.ts +87 -0
- package/src/api/controllers/query/import/sources/base/openapi.ts +24 -0
- package/src/api/controllers/query/import/sources/curl.ts +102 -0
- package/src/api/controllers/query/import/sources/openapi2.ts +163 -0
- package/src/api/controllers/query/import/sources/tests/curl/curl.spec.js +103 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/delete.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/empty-body.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/get.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/headers.txt +3 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/patch.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/path.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/post.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/put.txt +2 -0
- package/src/api/controllers/query/import/sources/tests/curl/data/query.txt +1 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.json +253 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/crud/crud.yaml +160 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.json +1054 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/data/petstore/petstore.yaml +711 -0
- package/src/api/controllers/query/import/sources/tests/openapi2/openapi2.spec.js +238 -0
- package/src/api/controllers/query/import/tests/index.spec.js +109 -0
- package/src/api/controllers/query/index.js +195 -0
- package/src/api/controllers/query/validation.js +42 -0
- package/src/api/controllers/row/internal.js +14 -5
- package/src/api/controllers/row/internalSearch.js +2 -1
- package/src/api/controllers/row/utils.js +11 -8
- package/src/api/controllers/user.js +33 -0
- package/src/api/controllers/webhook.js +4 -0
- package/src/api/routes/query.js +13 -35
- package/src/api/routes/tests/datasource.spec.js +45 -0
- package/src/api/routes/tests/query.spec.js +69 -0
- package/src/api/routes/user.js +10 -0
- package/src/automations/steps/executeQuery.js +9 -1
- package/src/automations/steps/outgoingWebhook.js +2 -3
- package/src/automations/utils.js +11 -0
- package/src/db/utils.js +9 -0
- package/src/definitions/common.ts +2 -16
- package/src/definitions/datasource.ts +83 -1
- package/src/integrations/base/IntegrationBase.ts +4 -4
- package/src/integrations/base/sqlTable.ts +1 -1
- package/src/integrations/oracle.ts +1 -1
- package/src/integrations/rest.ts +230 -137
- package/src/integrations/tests/rest.spec.js +167 -19
- package/src/tests/utilities/TestConfiguration.js +57 -0
- package/src/threads/query.js +149 -40
- package/src/threads/utils.js +115 -0
- package/src/utilities/fileSystem/utilities.js +2 -0
- package/src/utilities/index.js +11 -0
- package/src/utilities/rowProcessor/index.js +75 -0
- package/builder/assets/index.8adef83f.js +0 -1316
- package/src/api/controllers/query.js +0 -158
|
@@ -50,10 +50,10 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
|
|
50
50
|
const errors = {}
|
|
51
51
|
for (let fieldName of Object.keys(table.schema)) {
|
|
52
52
|
const constraints = cloneDeep(table.schema[fieldName].constraints)
|
|
53
|
+
const type = table.schema[fieldName].type
|
|
53
54
|
// special case for options, need to always allow unselected (null)
|
|
54
55
|
if (
|
|
55
|
-
|
|
56
|
-
(FieldTypes.OPTIONS || FieldTypes.ARRAY) &&
|
|
56
|
+
(type === FieldTypes.OPTIONS || type === FieldTypes.ARRAY) &&
|
|
57
57
|
constraints.inclusion
|
|
58
58
|
) {
|
|
59
59
|
constraints.inclusion.push(null)
|
|
@@ -61,17 +61,20 @@ exports.validate = async ({ appId, tableId, row, table }) => {
|
|
|
61
61
|
let res
|
|
62
62
|
|
|
63
63
|
// Validate.js doesn't seem to handle array
|
|
64
|
-
if (
|
|
65
|
-
table.schema[fieldName].type === FieldTypes.ARRAY &&
|
|
66
|
-
row[fieldName] &&
|
|
67
|
-
row[fieldName].length
|
|
68
|
-
) {
|
|
64
|
+
if (type === FieldTypes.ARRAY && row[fieldName] && row[fieldName].length) {
|
|
69
65
|
row[fieldName].map(val => {
|
|
70
66
|
if (!constraints.inclusion.includes(val)) {
|
|
71
67
|
errors[fieldName] = "Field not in list"
|
|
72
68
|
}
|
|
73
69
|
})
|
|
74
|
-
} else if (
|
|
70
|
+
} else if (type === FieldTypes.JSON && typeof row[fieldName] === "string") {
|
|
71
|
+
// this should only happen if there is an error
|
|
72
|
+
try {
|
|
73
|
+
JSON.parse(row[fieldName])
|
|
74
|
+
} catch (err) {
|
|
75
|
+
errors[fieldName] = [`Contains invalid JSON`]
|
|
76
|
+
}
|
|
77
|
+
} else if (type === FieldTypes.FORMULA) {
|
|
75
78
|
res = validateJs.single(
|
|
76
79
|
processStringSync(table.schema[fieldName].formula, row),
|
|
77
80
|
constraints
|
|
@@ -2,6 +2,7 @@ const CouchDB = require("../../db")
|
|
|
2
2
|
const {
|
|
3
3
|
generateUserMetadataID,
|
|
4
4
|
getUserMetadataParams,
|
|
5
|
+
generateUserFlagID,
|
|
5
6
|
} = require("../../db/utils")
|
|
6
7
|
const { InternalTables } = require("../../db/utils")
|
|
7
8
|
const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
|
|
@@ -195,3 +196,35 @@ exports.destroyMetadata = async function (ctx) {
|
|
|
195
196
|
exports.findMetadata = async function (ctx) {
|
|
196
197
|
ctx.body = await getFullUser(ctx, ctx.params.id)
|
|
197
198
|
}
|
|
199
|
+
|
|
200
|
+
exports.setFlag = async function (ctx) {
|
|
201
|
+
const userId = ctx.user._id
|
|
202
|
+
const { flag, value } = ctx.request.body
|
|
203
|
+
if (!flag) {
|
|
204
|
+
ctx.throw(400, "Must supply a 'flag' field in request body.")
|
|
205
|
+
}
|
|
206
|
+
const flagDocId = generateUserFlagID(userId)
|
|
207
|
+
const db = new CouchDB(ctx.appId)
|
|
208
|
+
let doc
|
|
209
|
+
try {
|
|
210
|
+
doc = await db.get(flagDocId)
|
|
211
|
+
} catch (err) {
|
|
212
|
+
doc = { _id: flagDocId }
|
|
213
|
+
}
|
|
214
|
+
doc[flag] = value || true
|
|
215
|
+
await db.put(doc)
|
|
216
|
+
ctx.body = { message: "Flag set successfully" }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
exports.getFlags = async function (ctx) {
|
|
220
|
+
const userId = ctx.user._id
|
|
221
|
+
const docId = generateUserFlagID(userId)
|
|
222
|
+
const db = new CouchDB(ctx.appId)
|
|
223
|
+
let doc
|
|
224
|
+
try {
|
|
225
|
+
doc = await db.get(docId)
|
|
226
|
+
} catch (err) {
|
|
227
|
+
doc = { _id: docId }
|
|
228
|
+
}
|
|
229
|
+
ctx.body = doc
|
|
230
|
+
}
|
|
@@ -65,6 +65,10 @@ exports.buildSchema = async ctx => {
|
|
|
65
65
|
let automation = await db.get(webhook.action.target)
|
|
66
66
|
const autoOutputs = automation.definition.trigger.schema.outputs
|
|
67
67
|
let properties = webhook.bodySchema.properties
|
|
68
|
+
// reset webhook outputs
|
|
69
|
+
autoOutputs.properties = {
|
|
70
|
+
body: autoOutputs.properties.body,
|
|
71
|
+
}
|
|
68
72
|
for (let prop of Object.keys(properties)) {
|
|
69
73
|
autoOutputs.properties[prop] = {
|
|
70
74
|
type: properties[prop].type,
|
package/src/api/routes/query.js
CHANGED
|
@@ -1,53 +1,23 @@
|
|
|
1
1
|
const Router = require("@koa/router")
|
|
2
2
|
const queryController = require("../controllers/query")
|
|
3
3
|
const authorized = require("../../middleware/authorized")
|
|
4
|
-
const Joi = require("joi")
|
|
5
4
|
const {
|
|
6
5
|
PermissionLevels,
|
|
7
6
|
PermissionTypes,
|
|
8
7
|
BUILDER,
|
|
9
8
|
} = require("@budibase/auth/permissions")
|
|
10
|
-
const joiValidator = require("../../middleware/joi-validator")
|
|
11
9
|
const {
|
|
12
10
|
bodyResource,
|
|
13
11
|
bodySubResource,
|
|
14
12
|
paramResource,
|
|
15
13
|
} = require("../../middleware/resourceId")
|
|
14
|
+
const {
|
|
15
|
+
generateQueryPreviewValidation,
|
|
16
|
+
generateQueryValidation,
|
|
17
|
+
} = require("../controllers/query/validation")
|
|
16
18
|
|
|
17
19
|
const router = Router()
|
|
18
20
|
|
|
19
|
-
function generateQueryValidation() {
|
|
20
|
-
// prettier-ignore
|
|
21
|
-
return joiValidator.body(Joi.object({
|
|
22
|
-
_id: Joi.string(),
|
|
23
|
-
_rev: Joi.string(),
|
|
24
|
-
name: Joi.string().required(),
|
|
25
|
-
fields: Joi.object().required(),
|
|
26
|
-
datasourceId: Joi.string().required(),
|
|
27
|
-
readable: Joi.boolean(),
|
|
28
|
-
parameters: Joi.array().items(Joi.object({
|
|
29
|
-
name: Joi.string(),
|
|
30
|
-
default: Joi.string().allow(""),
|
|
31
|
-
})),
|
|
32
|
-
queryVerb: Joi.string().allow().required(),
|
|
33
|
-
extra: Joi.object().optional(),
|
|
34
|
-
schema: Joi.object({}).required().unknown(true),
|
|
35
|
-
transformer: Joi.string().optional(),
|
|
36
|
-
}))
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function generateQueryPreviewValidation() {
|
|
40
|
-
// prettier-ignore
|
|
41
|
-
return joiValidator.body(Joi.object({
|
|
42
|
-
fields: Joi.object().required(),
|
|
43
|
-
queryVerb: Joi.string().allow().required(),
|
|
44
|
-
extra: Joi.object().optional(),
|
|
45
|
-
datasourceId: Joi.string().required(),
|
|
46
|
-
transformer: Joi.string().optional(),
|
|
47
|
-
parameters: Joi.object({}).required().unknown(true)
|
|
48
|
-
}))
|
|
49
|
-
}
|
|
50
|
-
|
|
51
21
|
router
|
|
52
22
|
.get("/api/queries", authorized(BUILDER), queryController.fetch)
|
|
53
23
|
.post(
|
|
@@ -57,6 +27,7 @@ router
|
|
|
57
27
|
generateQueryValidation(),
|
|
58
28
|
queryController.save
|
|
59
29
|
)
|
|
30
|
+
.post("/api/queries/import", authorized(BUILDER), queryController.import)
|
|
60
31
|
.post(
|
|
61
32
|
"/api/queries/preview",
|
|
62
33
|
bodyResource("datasourceId"),
|
|
@@ -70,11 +41,18 @@ router
|
|
|
70
41
|
authorized(PermissionTypes.QUERY, PermissionLevels.READ),
|
|
71
42
|
queryController.find
|
|
72
43
|
)
|
|
44
|
+
// DEPRECATED - use new query endpoint for future work
|
|
73
45
|
.post(
|
|
74
46
|
"/api/queries/:queryId",
|
|
75
47
|
paramResource("queryId"),
|
|
76
48
|
authorized(PermissionTypes.QUERY, PermissionLevels.WRITE),
|
|
77
|
-
queryController.
|
|
49
|
+
queryController.executeV1
|
|
50
|
+
)
|
|
51
|
+
.post(
|
|
52
|
+
"/api/v2/queries/:queryId",
|
|
53
|
+
paramResource("queryId"),
|
|
54
|
+
authorized(PermissionTypes.QUERY, PermissionLevels.WRITE),
|
|
55
|
+
queryController.executeV2
|
|
78
56
|
)
|
|
79
57
|
.delete(
|
|
80
58
|
"/api/queries/:queryId/:revId",
|
|
@@ -4,6 +4,7 @@ let setup = require("./utilities")
|
|
|
4
4
|
let { basicDatasource } = setup.structures
|
|
5
5
|
let { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
|
6
6
|
const pg = require("pg")
|
|
7
|
+
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
|
|
7
8
|
|
|
8
9
|
describe("/datasources", () => {
|
|
9
10
|
let request = setup.getRequest()
|
|
@@ -31,6 +32,50 @@ describe("/datasources", () => {
|
|
|
31
32
|
})
|
|
32
33
|
})
|
|
33
34
|
|
|
35
|
+
describe("update", () => {
|
|
36
|
+
it("should update an existing datasource", async () => {
|
|
37
|
+
datasource.name = "Updated Test"
|
|
38
|
+
const res = await request
|
|
39
|
+
.put(`/api/datasources/${datasource._id}`)
|
|
40
|
+
.send(datasource)
|
|
41
|
+
.set(config.defaultHeaders())
|
|
42
|
+
.expect('Content-Type', /json/)
|
|
43
|
+
.expect(200)
|
|
44
|
+
|
|
45
|
+
expect(res.body.datasource.name).toEqual("Updated Test")
|
|
46
|
+
expect(res.body.errors).toBeUndefined()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe("dynamic variables", () => {
|
|
50
|
+
async function preview(datasource, fields) {
|
|
51
|
+
return config.previewQuery(request, config, datasource, fields)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
it("should invalidate changed or removed variables", async () => {
|
|
55
|
+
const { datasource, query } = await config.dynamicVariableDatasource()
|
|
56
|
+
// preview once to cache variables
|
|
57
|
+
await preview(datasource, { path: "www.test.com", queryString: "test={{ variable3 }}" })
|
|
58
|
+
// check variables in cache
|
|
59
|
+
let contents = await checkCacheForDynamicVariable(query._id, "variable3")
|
|
60
|
+
expect(contents.rows.length).toEqual(1)
|
|
61
|
+
|
|
62
|
+
// update the datasource to remove the variables
|
|
63
|
+
datasource.config.dynamicVariables = []
|
|
64
|
+
const res = await request
|
|
65
|
+
.put(`/api/datasources/${datasource._id}`)
|
|
66
|
+
.send(datasource)
|
|
67
|
+
.set(config.defaultHeaders())
|
|
68
|
+
.expect('Content-Type', /json/)
|
|
69
|
+
.expect(200)
|
|
70
|
+
expect(res.body.errors).toBeUndefined()
|
|
71
|
+
|
|
72
|
+
// check variables no longer in cache
|
|
73
|
+
contents = await checkCacheForDynamicVariable(query._id, "variable3")
|
|
74
|
+
expect(contents).toBe(null)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
34
79
|
describe("fetch", () => {
|
|
35
80
|
it("returns all the datasources from the server", async () => {
|
|
36
81
|
const res = await request
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Mock out postgres for this
|
|
2
2
|
jest.mock("pg")
|
|
3
|
+
jest.mock("node-fetch")
|
|
3
4
|
|
|
4
5
|
// Mock isProdAppID to we can later mock the implementation and pretend we are
|
|
5
6
|
// using prod app IDs
|
|
@@ -10,6 +11,7 @@ authDb.isProdAppID = mockIsProdAppID
|
|
|
10
11
|
|
|
11
12
|
const setup = require("./utilities")
|
|
12
13
|
const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
|
14
|
+
const { checkCacheForDynamicVariable } = require("../../../threads/utils")
|
|
13
15
|
const { basicQuery, basicDatasource } = setup.structures
|
|
14
16
|
|
|
15
17
|
describe("/queries", () => {
|
|
@@ -226,4 +228,71 @@ describe("/queries", () => {
|
|
|
226
228
|
.expect(400)
|
|
227
229
|
})
|
|
228
230
|
})
|
|
231
|
+
|
|
232
|
+
describe("variables", () => {
|
|
233
|
+
|
|
234
|
+
async function preview(datasource, fields) {
|
|
235
|
+
return config.previewQuery(request, config, datasource, fields)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
it("should work with static variables", async () => {
|
|
239
|
+
const datasource = await config.restDatasource({
|
|
240
|
+
staticVariables: {
|
|
241
|
+
variable: "google",
|
|
242
|
+
variable2: "1",
|
|
243
|
+
},
|
|
244
|
+
})
|
|
245
|
+
const res = await preview(datasource, {
|
|
246
|
+
path: "www.{{ variable }}.com",
|
|
247
|
+
queryString: "test={{ variable2 }}",
|
|
248
|
+
})
|
|
249
|
+
// these responses come from the mock
|
|
250
|
+
expect(res.body.schemaFields).toEqual(["url", "opts", "value"])
|
|
251
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?test=1")
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
it("should work with dynamic variables", async () => {
|
|
255
|
+
const { datasource } = await config.dynamicVariableDatasource()
|
|
256
|
+
const res = await preview(datasource, {
|
|
257
|
+
path: "www.google.com",
|
|
258
|
+
queryString: "test={{ variable3 }}",
|
|
259
|
+
})
|
|
260
|
+
expect(res.body.schemaFields).toEqual(["url", "opts", "value"])
|
|
261
|
+
expect(res.body.rows[0].url).toContain("doctype html")
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it("check that it automatically retries on fail with cached dynamics", async () => {
|
|
265
|
+
const { datasource, query: base } = await config.dynamicVariableDatasource()
|
|
266
|
+
// preview once to cache
|
|
267
|
+
await preview(datasource, { path: "www.google.com", queryString: "test={{ variable3 }}" })
|
|
268
|
+
// check its in cache
|
|
269
|
+
const contents = await checkCacheForDynamicVariable(base._id, "variable3")
|
|
270
|
+
expect(contents.rows.length).toEqual(1)
|
|
271
|
+
const res = await preview(datasource, {
|
|
272
|
+
path: "www.failonce.com",
|
|
273
|
+
queryString: "test={{ variable3 }}",
|
|
274
|
+
})
|
|
275
|
+
expect(res.body.schemaFields).toEqual(["fails", "url", "opts"])
|
|
276
|
+
expect(res.body.rows[0].fails).toEqual(1)
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it("deletes variables when linked query is deleted", async () => {
|
|
280
|
+
const { datasource, query: base } = await config.dynamicVariableDatasource()
|
|
281
|
+
// preview once to cache
|
|
282
|
+
await preview(datasource, { path: "www.google.com", queryString: "test={{ variable3 }}" })
|
|
283
|
+
// check its in cache
|
|
284
|
+
let contents = await checkCacheForDynamicVariable(base._id, "variable3")
|
|
285
|
+
expect(contents.rows.length).toEqual(1)
|
|
286
|
+
|
|
287
|
+
// delete the query
|
|
288
|
+
await request
|
|
289
|
+
.delete(`/api/queries/${base._id}/${base._rev}`)
|
|
290
|
+
.set(config.defaultHeaders())
|
|
291
|
+
.expect(200)
|
|
292
|
+
|
|
293
|
+
// check variables no longer in cache
|
|
294
|
+
contents = await checkCacheForDynamicVariable(base._id, "variable3")
|
|
295
|
+
expect(contents).toBe(null)
|
|
296
|
+
})
|
|
297
|
+
})
|
|
229
298
|
})
|
package/src/api/routes/user.js
CHANGED
|
@@ -39,5 +39,15 @@ router
|
|
|
39
39
|
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
|
40
40
|
controller.syncUser
|
|
41
41
|
)
|
|
42
|
+
.post(
|
|
43
|
+
"/api/users/flags",
|
|
44
|
+
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
|
45
|
+
controller.setFlag
|
|
46
|
+
)
|
|
47
|
+
.get(
|
|
48
|
+
"/api/users/flags",
|
|
49
|
+
authorized(PermissionTypes.USER, PermissionLevels.READ),
|
|
50
|
+
controller.getFlags
|
|
51
|
+
)
|
|
42
52
|
|
|
43
53
|
module.exports = router
|
|
@@ -35,6 +35,11 @@ exports.definition = {
|
|
|
35
35
|
type: "object",
|
|
36
36
|
description: "The response from the datasource execution",
|
|
37
37
|
},
|
|
38
|
+
info: {
|
|
39
|
+
type: "object",
|
|
40
|
+
description:
|
|
41
|
+
"Some query types may return extra data, like headers from a REST query",
|
|
42
|
+
},
|
|
38
43
|
success: {
|
|
39
44
|
type: "boolean",
|
|
40
45
|
description: "Whether the action was successful",
|
|
@@ -68,13 +73,16 @@ exports.run = async function ({ inputs, appId, emitter }) {
|
|
|
68
73
|
|
|
69
74
|
try {
|
|
70
75
|
await queryController.execute(ctx)
|
|
76
|
+
const { data, ...rest } = ctx.body
|
|
71
77
|
return {
|
|
72
|
-
response:
|
|
78
|
+
response: data,
|
|
79
|
+
info: rest,
|
|
73
80
|
success: true,
|
|
74
81
|
}
|
|
75
82
|
} catch (err) {
|
|
76
83
|
return {
|
|
77
84
|
success: false,
|
|
85
|
+
info: {},
|
|
78
86
|
response: automationUtils.getError(err),
|
|
79
87
|
}
|
|
80
88
|
}
|
|
@@ -13,12 +13,11 @@ const RequestType = {
|
|
|
13
13
|
const BODY_REQUESTS = [RequestType.POST, RequestType.PUT, RequestType.PATCH]
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* is complex and maybe better to be opinionated here.
|
|
18
|
-
* GET/DELETE requests cannot handle body elements so they will not be sent if configured.
|
|
16
|
+
* NOTE: this functionality is deprecated - it no longer should be used.
|
|
19
17
|
*/
|
|
20
18
|
|
|
21
19
|
exports.definition = {
|
|
20
|
+
deprecated: true,
|
|
22
21
|
name: "Outgoing webhook",
|
|
23
22
|
tagline: "Send a {{inputs.requestMethod}} request",
|
|
24
23
|
icon: "Send",
|
package/src/automations/utils.js
CHANGED
|
@@ -7,6 +7,7 @@ const newid = require("../db/newid")
|
|
|
7
7
|
const { updateEntityMetadata } = require("../utilities")
|
|
8
8
|
const { MetadataTypes } = require("../constants")
|
|
9
9
|
const { getDeployedAppID } = require("@budibase/auth/db")
|
|
10
|
+
const { cloneDeep } = require("lodash/fp")
|
|
10
11
|
|
|
11
12
|
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
|
12
13
|
const CRON_STEP_ID = definitions.CRON.stepId
|
|
@@ -42,6 +43,16 @@ exports.updateTestHistory = async (appId, automation, history) => {
|
|
|
42
43
|
)
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
exports.removeDeprecated = definitions => {
|
|
47
|
+
const base = cloneDeep(definitions)
|
|
48
|
+
for (let key of Object.keys(base)) {
|
|
49
|
+
if (base[key].deprecated) {
|
|
50
|
+
delete base[key]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return base
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
// end the repetition and the job itself
|
|
46
57
|
exports.disableAllCrons = async appId => {
|
|
47
58
|
const promises = []
|
package/src/db/utils.js
CHANGED
|
@@ -40,6 +40,7 @@ const DocumentTypes = {
|
|
|
40
40
|
DEPLOYMENTS: "deployments",
|
|
41
41
|
METADATA: "metadata",
|
|
42
42
|
MEM_VIEW: "view",
|
|
43
|
+
USER_FLAG: "flag",
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
const ViewNames = {
|
|
@@ -339,6 +340,14 @@ exports.getQueryParams = (datasourceId = null, otherProps = {}) => {
|
|
|
339
340
|
)
|
|
340
341
|
}
|
|
341
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Generates a new flag document ID.
|
|
345
|
+
* @returns {string} The ID of the flag document that was generated.
|
|
346
|
+
*/
|
|
347
|
+
exports.generateUserFlagID = userId => {
|
|
348
|
+
return `${DocumentTypes.USER_FLAG}${SEPARATOR}${userId}`
|
|
349
|
+
}
|
|
350
|
+
|
|
342
351
|
exports.generateMetadataID = (type, entityId) => {
|
|
343
352
|
return `${DocumentTypes.METADATA}${SEPARATOR}${type}${SEPARATOR}${entityId}`
|
|
344
353
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
export { Query, Datasource } from "./datasource"
|
|
2
2
|
|
|
3
|
-
interface Base {
|
|
3
|
+
export interface Base {
|
|
4
4
|
_id?: string
|
|
5
5
|
_rev?: string
|
|
6
6
|
}
|
|
@@ -93,17 +93,3 @@ export interface Automation extends Base {
|
|
|
93
93
|
trigger?: AutomationStep
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
export interface Datasource extends Base {
|
|
98
|
-
type: string
|
|
99
|
-
name: string
|
|
100
|
-
source: SourceNames
|
|
101
|
-
// the config is defined by the schema
|
|
102
|
-
config: {
|
|
103
|
-
[key: string]: string | number | boolean
|
|
104
|
-
}
|
|
105
|
-
plus: boolean
|
|
106
|
-
entities?: {
|
|
107
|
-
[key: string]: Table
|
|
108
|
-
}
|
|
109
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Row, Table } from "./common"
|
|
1
|
+
import { Row, Table, Base } from "./common"
|
|
2
2
|
|
|
3
3
|
export enum Operation {
|
|
4
4
|
CREATE = "CREATE",
|
|
@@ -181,3 +181,85 @@ export interface SqlQuery {
|
|
|
181
181
|
export interface QueryOptions {
|
|
182
182
|
disableReturning?: boolean
|
|
183
183
|
}
|
|
184
|
+
|
|
185
|
+
export interface Datasource extends Base {
|
|
186
|
+
type: string
|
|
187
|
+
name: string
|
|
188
|
+
source: SourceNames
|
|
189
|
+
// the config is defined by the schema
|
|
190
|
+
config: {
|
|
191
|
+
[key: string]: string | number | boolean
|
|
192
|
+
}
|
|
193
|
+
plus: boolean
|
|
194
|
+
entities?: {
|
|
195
|
+
[key: string]: Table
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export enum AuthType {
|
|
200
|
+
BASIC = "basic",
|
|
201
|
+
BEARER = "bearer",
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
interface AuthConfig {
|
|
205
|
+
_id: string
|
|
206
|
+
name: string
|
|
207
|
+
type: AuthType
|
|
208
|
+
config: BasicAuthConfig | BearerAuthConfig
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface BasicAuthConfig {
|
|
212
|
+
username: string
|
|
213
|
+
password: string
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface BearerAuthConfig {
|
|
217
|
+
token: string
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface QueryParameter {
|
|
221
|
+
name: string
|
|
222
|
+
default: string
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export interface RestQueryFields {
|
|
226
|
+
path: string
|
|
227
|
+
queryString?: string
|
|
228
|
+
headers: { [key: string]: any }
|
|
229
|
+
disabledHeaders: { [key: string]: any }
|
|
230
|
+
requestBody: any
|
|
231
|
+
bodyType: string
|
|
232
|
+
json: object
|
|
233
|
+
method: string
|
|
234
|
+
authConfigId: string
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface RestConfig {
|
|
238
|
+
url: string
|
|
239
|
+
defaultHeaders: {
|
|
240
|
+
[key: string]: any
|
|
241
|
+
}
|
|
242
|
+
authConfigs: AuthConfig[]
|
|
243
|
+
staticVariables: {
|
|
244
|
+
[key: string]: string
|
|
245
|
+
}
|
|
246
|
+
dynamicVariables: [
|
|
247
|
+
{
|
|
248
|
+
name: string
|
|
249
|
+
queryId: string
|
|
250
|
+
value: string
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface Query {
|
|
256
|
+
_id?: string
|
|
257
|
+
datasourceId: string
|
|
258
|
+
name: string
|
|
259
|
+
parameters: QueryParameter[]
|
|
260
|
+
fields: RestQueryFields | any
|
|
261
|
+
transformer: string | null
|
|
262
|
+
schema: any
|
|
263
|
+
readable: boolean
|
|
264
|
+
queryVerb: string
|
|
265
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface IntegrationBase {
|
|
2
|
-
create?(query: any): Promise<any[]>
|
|
3
|
-
read?(query: any): Promise<any[]>
|
|
4
|
-
update?(query: any): Promise<any[]>
|
|
5
|
-
delete?(query: any): Promise<any[]>
|
|
2
|
+
create?(query: any): Promise<any[] | any>
|
|
3
|
+
read?(query: any): Promise<any[] | any>
|
|
4
|
+
update?(query: any): Promise<any[] | any>
|
|
5
|
+
delete?(query: any): Promise<any[] | any>
|
|
6
6
|
}
|