@budibase/server 0.9.167-alpha.0 → 0.9.167-alpha.12
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/builder/assets/{index.32c8bc7d.js → index.bb938864.js} +34 -34
- package/builder/assets/{index.18ad7651.css → index.bcacf476.css} +2 -2
- package/builder/assets/{vendor.60887453.js → vendor.a3855e3d.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +416 -369
- package/coverage/coverage-final.json +17 -16
- 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 +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- 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 +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
- package/coverage/lcov-report/api/controllers/dev.js.html +41 -17
- package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +43 -43
- 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.js.html +129 -24
- 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 +1 -1
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +12 -57
- package/coverage/lcov-report/api/controllers/table/index.html +20 -20
- package/coverage/lcov-report/api/controllers/table/index.js.html +17 -8
- package/coverage/lcov-report/api/controllers/table/utils.js.html +8 -38
- package/coverage/lcov-report/api/controllers/templates.js.html +49 -13
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- 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 +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +1 -1
- 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 +26 -11
- 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 +9 -3
- 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 +1 -1
- 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 +31 -10
- 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 +19 -19
- 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 +1 -1
- 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 +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- 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/thread.js.html +54 -12
- 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 +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +5 -2
- 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 +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +12 -12
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +9 -9
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +1 -1
- package/coverage/lcov-report/db/utils.js.html +1 -1
- 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 +53 -53
- 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 +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +2 -2
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- 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 +2 -2
- package/coverage/lcov-report/utilities/index.html +22 -7
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- 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 +14 -14
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +38 -8
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/scriptRunner.js.html +143 -0
- package/coverage/lcov-report/utilities/security.js.html +1 -1
- 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 +1 -1
- package/coverage/lcov.info +700 -608
- package/dist/api/controllers/dev.js +17 -11
- package/dist/api/controllers/query.js +26 -8
- package/dist/api/controllers/script.js +4 -16
- package/dist/api/controllers/table/index.js +3 -0
- package/dist/api/controllers/table/utils.js +2 -10
- package/dist/api/controllers/templates.js +18 -3
- package/dist/api/routes/dev.js +8 -4
- package/dist/api/routes/query.js +3 -1
- package/dist/automations/actions.js +9 -3
- package/dist/automations/thread.js +14 -3
- package/dist/constants/index.js +1 -0
- package/dist/integrations/base/sql.js +4 -4
- package/dist/middleware/currentapp.js +1 -1
- package/dist/package.json +5 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/global.js +1 -1
- package/dist/utilities/rowProcessor/index.js +8 -0
- package/dist/utilities/scriptRunner.js +19 -0
- package/package.json +6 -5
- package/src/api/controllers/dev.js +16 -8
- package/src/api/controllers/query.js +46 -11
- package/src/api/controllers/script.js +4 -19
- package/src/api/controllers/table/index.js +3 -0
- package/src/api/controllers/table/utils.js +2 -12
- package/src/api/controllers/templates.js +17 -5
- package/src/api/routes/dev.js +9 -4
- package/src/api/routes/query.js +3 -1
- package/src/automations/actions.js +10 -3
- package/src/automations/thread.js +17 -3
- package/src/constants/index.js +1 -0
- package/src/integrations/base/sql.ts +5 -3
- package/src/integrations/tests/mongo.spec.js +10 -6
- package/src/middleware/currentapp.js +1 -1
- package/src/middleware/tests/currentapp.spec.js +3 -3
- package/src/utilities/global.js +1 -1
- package/src/utilities/rowProcessor/index.js +10 -0
- package/src/utilities/scriptRunner.js +21 -0
package/dist/utilities/global.js
CHANGED
|
@@ -149,6 +149,10 @@ exports.processAutoColumn = processAutoColumn;
|
|
|
149
149
|
* @returns {object} The coerced value
|
|
150
150
|
*/
|
|
151
151
|
exports.coerce = (row, type) => {
|
|
152
|
+
// no coercion specified for type, skip it
|
|
153
|
+
if (!TYPE_TRANSFORM_MAP[type]) {
|
|
154
|
+
return row;
|
|
155
|
+
}
|
|
152
156
|
// eslint-disable-next-line no-prototype-builtins
|
|
153
157
|
if (TYPE_TRANSFORM_MAP[type].hasOwnProperty(row)) {
|
|
154
158
|
return TYPE_TRANSFORM_MAP[type][row];
|
|
@@ -190,6 +194,10 @@ exports.inputProcessing = (user = {}, table, row, opts = { noAutoRelationships:
|
|
|
190
194
|
clonedRow[key] = exports.coerce(value, field.type);
|
|
191
195
|
}
|
|
192
196
|
}
|
|
197
|
+
if (!clonedRow._id || !clonedRow._rev) {
|
|
198
|
+
clonedRow._id = row._id;
|
|
199
|
+
clonedRow._rev = row._rev;
|
|
200
|
+
}
|
|
193
201
|
// handle auto columns - this returns an object like {table, row}
|
|
194
202
|
return processAutoColumn(user, copiedTable, clonedRow, opts);
|
|
195
203
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fetch = require("node-fetch");
|
|
3
|
+
const { VM, VMScript } = require("vm2");
|
|
4
|
+
class ScriptRunner {
|
|
5
|
+
constructor(script, context) {
|
|
6
|
+
const code = `let fn = () => {\n${script}\n}; results.out = fn();`;
|
|
7
|
+
this.vm = new VM();
|
|
8
|
+
this.results = { out: "" };
|
|
9
|
+
this.vm.setGlobals(context);
|
|
10
|
+
this.vm.setGlobal("fetch", fetch);
|
|
11
|
+
this.vm.setGlobal("results", this.results);
|
|
12
|
+
this.script = new VMScript(code);
|
|
13
|
+
}
|
|
14
|
+
execute() {
|
|
15
|
+
this.vm.run(this.script);
|
|
16
|
+
return this.results.out;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
module.exports = ScriptRunner;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "0.9.167-alpha.
|
|
4
|
+
"version": "0.9.167-alpha.12",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"repository": {
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"author": "Budibase",
|
|
69
69
|
"license": "AGPL-3.0-or-later",
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@budibase/auth": "^0.9.167-alpha.
|
|
72
|
-
"@budibase/client": "^0.9.167-alpha.
|
|
73
|
-
"@budibase/string-templates": "^0.9.167-alpha.
|
|
71
|
+
"@budibase/auth": "^0.9.167-alpha.12",
|
|
72
|
+
"@budibase/client": "^0.9.167-alpha.12",
|
|
73
|
+
"@budibase/string-templates": "^0.9.167-alpha.12",
|
|
74
74
|
"@elastic/elasticsearch": "7.10.0",
|
|
75
75
|
"@koa/router": "8.0.0",
|
|
76
76
|
"@sendgrid/mail": "7.1.1",
|
|
@@ -119,6 +119,7 @@
|
|
|
119
119
|
"to-json-schema": "0.2.5",
|
|
120
120
|
"uuid": "3.3.2",
|
|
121
121
|
"validate.js": "0.13.1",
|
|
122
|
+
"vm2": "^3.9.3",
|
|
122
123
|
"yargs": "13.2.4",
|
|
123
124
|
"zlib": "1.0.5"
|
|
124
125
|
},
|
|
@@ -148,5 +149,5 @@
|
|
|
148
149
|
"typescript": "^4.3.5",
|
|
149
150
|
"update-dotenv": "^1.1.1"
|
|
150
151
|
},
|
|
151
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "eed61105f0b7a018bd4be19f655fc7f1020252be"
|
|
152
153
|
}
|
|
@@ -7,11 +7,13 @@ const { clearLock } = require("../../utilities/redis")
|
|
|
7
7
|
const { Replication } = require("@budibase/auth").db
|
|
8
8
|
const { DocumentTypes } = require("../../db/utils")
|
|
9
9
|
|
|
10
|
-
async function redirect(ctx, method) {
|
|
10
|
+
async function redirect(ctx, method, path = "global") {
|
|
11
11
|
const { devPath } = ctx.params
|
|
12
12
|
const queryString = ctx.originalUrl.split("?")[1] || ""
|
|
13
13
|
const response = await fetch(
|
|
14
|
-
checkSlashesInUrl(
|
|
14
|
+
checkSlashesInUrl(
|
|
15
|
+
`${env.WORKER_URL}/api/${path}/${devPath}?${queryString}`
|
|
16
|
+
),
|
|
15
17
|
request(
|
|
16
18
|
ctx,
|
|
17
19
|
{
|
|
@@ -41,16 +43,22 @@ async function redirect(ctx, method) {
|
|
|
41
43
|
ctx.cookies
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
exports.
|
|
45
|
-
|
|
46
|
+
exports.buildRedirectGet = path => {
|
|
47
|
+
return async ctx => {
|
|
48
|
+
await redirect(ctx, "GET", path)
|
|
49
|
+
}
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
exports.
|
|
49
|
-
|
|
52
|
+
exports.buildRedirectPost = path => {
|
|
53
|
+
return async ctx => {
|
|
54
|
+
await redirect(ctx, "POST", path)
|
|
55
|
+
}
|
|
50
56
|
}
|
|
51
57
|
|
|
52
|
-
exports.
|
|
53
|
-
|
|
58
|
+
exports.buildRedirectDelete = path => {
|
|
59
|
+
return async ctx => {
|
|
60
|
+
await redirect(ctx, "DELETE", path)
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
exports.clearLock = async ctx => {
|
|
@@ -4,6 +4,7 @@ const { generateQueryID, getQueryParams } = require("../../db/utils")
|
|
|
4
4
|
const { integrations } = require("../../integrations")
|
|
5
5
|
const { BaseQueryVerbs } = require("../../constants")
|
|
6
6
|
const env = require("../../environment")
|
|
7
|
+
const ScriptRunner = require("../../utilities/scriptRunner")
|
|
7
8
|
|
|
8
9
|
// simple function to append "readable" to all read queries
|
|
9
10
|
function enrichQueries(input) {
|
|
@@ -28,12 +29,39 @@ function formatResponse(resp) {
|
|
|
28
29
|
resp = { response: resp }
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
|
-
if (!Array.isArray(resp)) {
|
|
32
|
-
resp = [resp]
|
|
33
|
-
}
|
|
34
32
|
return resp
|
|
35
33
|
}
|
|
36
34
|
|
|
35
|
+
async function runAndTransform(
|
|
36
|
+
integration,
|
|
37
|
+
queryVerb,
|
|
38
|
+
enrichedQuery,
|
|
39
|
+
transformer
|
|
40
|
+
) {
|
|
41
|
+
let rows = formatResponse(await integration[queryVerb](enrichedQuery))
|
|
42
|
+
|
|
43
|
+
// transform as required
|
|
44
|
+
if (transformer) {
|
|
45
|
+
const runner = new ScriptRunner(transformer, { data: rows })
|
|
46
|
+
rows = runner.execute()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// needs to an array for next step
|
|
50
|
+
if (!Array.isArray(rows)) {
|
|
51
|
+
rows = [rows]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// map into JSON if just raw primitive here
|
|
55
|
+
if (rows.find(row => typeof row !== "object")) {
|
|
56
|
+
rows = rows.map(value => ({ value }))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// get all the potential fields in the schema
|
|
60
|
+
let keys = rows.flatMap(Object.keys)
|
|
61
|
+
|
|
62
|
+
return { rows, keys }
|
|
63
|
+
}
|
|
64
|
+
|
|
37
65
|
exports.fetch = async function (ctx) {
|
|
38
66
|
const db = new CouchDB(ctx.appId)
|
|
39
67
|
|
|
@@ -122,15 +150,16 @@ exports.preview = async function (ctx) {
|
|
|
122
150
|
ctx.throw(400, "Integration type does not exist.")
|
|
123
151
|
}
|
|
124
152
|
|
|
125
|
-
const { fields, parameters, queryVerb } = ctx.request.body
|
|
126
|
-
|
|
153
|
+
const { fields, parameters, queryVerb, transformer } = ctx.request.body
|
|
127
154
|
const enrichedQuery = await enrichQueryFields(fields, parameters)
|
|
128
|
-
|
|
129
155
|
const integration = new Integration(datasource.config)
|
|
130
|
-
const rows = formatResponse(await integration[queryVerb](enrichedQuery))
|
|
131
156
|
|
|
132
|
-
|
|
133
|
-
|
|
157
|
+
const { rows, keys } = await runAndTransform(
|
|
158
|
+
integration,
|
|
159
|
+
queryVerb,
|
|
160
|
+
enrichedQuery,
|
|
161
|
+
transformer
|
|
162
|
+
)
|
|
134
163
|
|
|
135
164
|
ctx.body = {
|
|
136
165
|
rows,
|
|
@@ -158,10 +187,16 @@ exports.execute = async function (ctx) {
|
|
|
158
187
|
query.fields,
|
|
159
188
|
ctx.request.body.parameters
|
|
160
189
|
)
|
|
161
|
-
|
|
162
190
|
const integration = new Integration(datasource.config)
|
|
191
|
+
|
|
163
192
|
// call the relevant CRUD method on the integration class
|
|
164
|
-
|
|
193
|
+
const { rows } = await runAndTransform(
|
|
194
|
+
integration,
|
|
195
|
+
query.queryVerb,
|
|
196
|
+
enrichedQuery,
|
|
197
|
+
query.transformer
|
|
198
|
+
)
|
|
199
|
+
ctx.body = rows
|
|
165
200
|
// cleanup
|
|
166
201
|
if (integration.end) {
|
|
167
202
|
integration.end()
|
|
@@ -1,24 +1,9 @@
|
|
|
1
|
-
const
|
|
2
|
-
const vm = require("vm")
|
|
3
|
-
|
|
4
|
-
class ScriptExecutor {
|
|
5
|
-
constructor(body) {
|
|
6
|
-
const code = `let fn = () => {\n${body.script}\n}; out = fn();`
|
|
7
|
-
this.script = new vm.Script(code)
|
|
8
|
-
this.context = vm.createContext(body.context)
|
|
9
|
-
this.context.fetch = fetch
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
execute() {
|
|
13
|
-
this.script.runInContext(this.context)
|
|
14
|
-
return this.context.out
|
|
15
|
-
}
|
|
16
|
-
}
|
|
1
|
+
const ScriptRunner = require("../../utilities/scriptRunner")
|
|
17
2
|
|
|
18
3
|
exports.execute = async function (ctx) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
ctx.body =
|
|
4
|
+
const { script, context } = ctx.request.body
|
|
5
|
+
const runner = new ScriptRunner(script, context)
|
|
6
|
+
ctx.body = runner.execute()
|
|
22
7
|
}
|
|
23
8
|
|
|
24
9
|
exports.save = async function (ctx) {
|
|
@@ -91,6 +91,9 @@ exports.save = async function (ctx) {
|
|
|
91
91
|
for (let propKey of Object.keys(tableToSave.schema)) {
|
|
92
92
|
let column = tableToSave.schema[propKey]
|
|
93
93
|
let oldColumn = oldTable.schema[propKey]
|
|
94
|
+
if (oldColumn && oldColumn.type === "internal") {
|
|
95
|
+
oldColumn.type = "auto"
|
|
96
|
+
}
|
|
94
97
|
if (oldColumn && oldColumn.type !== column.type) {
|
|
95
98
|
ctx.throw(400, "Cannot change the type of a column")
|
|
96
99
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const CouchDB = require("../../../db")
|
|
2
|
-
const linkRows = require("../../../db/linkedRows")
|
|
3
2
|
const csvParser = require("../../../utilities/csvParser")
|
|
4
3
|
const {
|
|
5
4
|
getRowParams,
|
|
@@ -93,19 +92,10 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
finalData.push(
|
|
98
|
-
linkRows.updateLinks({
|
|
99
|
-
appId,
|
|
100
|
-
eventType: linkRows.EventType.ROW_SAVE,
|
|
101
|
-
row,
|
|
102
|
-
tableId: row.tableId,
|
|
103
|
-
table,
|
|
104
|
-
})
|
|
105
|
-
)
|
|
95
|
+
finalData.push(row)
|
|
106
96
|
}
|
|
107
97
|
|
|
108
|
-
await db.bulkDocs(
|
|
98
|
+
await db.bulkDocs(finalData)
|
|
109
99
|
let response = await db.put(table)
|
|
110
100
|
table._rev = response._rev
|
|
111
101
|
}
|
|
@@ -7,11 +7,23 @@ const DEFAULT_TEMPLATES_BUCKET =
|
|
|
7
7
|
|
|
8
8
|
exports.fetch = async function (ctx) {
|
|
9
9
|
const { type = "app" } = ctx.query
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
let response,
|
|
11
|
+
error = false
|
|
12
|
+
try {
|
|
13
|
+
response = await fetch(`https://${DEFAULT_TEMPLATES_BUCKET}/manifest.json`)
|
|
14
|
+
if (response.status !== 200) {
|
|
15
|
+
error = true
|
|
16
|
+
}
|
|
17
|
+
} catch (err) {
|
|
18
|
+
error = true
|
|
19
|
+
}
|
|
20
|
+
// if there is an error, simply return no templates
|
|
21
|
+
if (!error && response) {
|
|
22
|
+
const json = await response.json()
|
|
23
|
+
ctx.body = Object.values(json.templates[type])
|
|
24
|
+
} else {
|
|
25
|
+
ctx.body = []
|
|
26
|
+
}
|
|
15
27
|
}
|
|
16
28
|
|
|
17
29
|
// can't currently test this, have to ignore from coverage
|
package/src/api/routes/dev.js
CHANGED
|
@@ -6,11 +6,16 @@ const { BUILDER } = require("@budibase/auth/permissions")
|
|
|
6
6
|
|
|
7
7
|
const router = Router()
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
function redirectPath(path) {
|
|
10
10
|
router
|
|
11
|
-
.get(
|
|
12
|
-
.post(
|
|
13
|
-
.delete(
|
|
11
|
+
.get(`/api/${path}/:devPath(.*)`, controller.buildRedirectGet(path))
|
|
12
|
+
.post(`/api/${path}/:devPath(.*)`, controller.buildRedirectPost(path))
|
|
13
|
+
.delete(`/api/${path}/:devPath(.*)`, controller.buildRedirectDelete(path))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (env.isDev() || env.isTest()) {
|
|
17
|
+
redirectPath("global")
|
|
18
|
+
redirectPath("system")
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
router
|
package/src/api/routes/query.js
CHANGED
|
@@ -31,7 +31,8 @@ function generateQueryValidation() {
|
|
|
31
31
|
})),
|
|
32
32
|
queryVerb: Joi.string().allow().required(),
|
|
33
33
|
extra: Joi.object().optional(),
|
|
34
|
-
schema: Joi.object({}).required().unknown(true)
|
|
34
|
+
schema: Joi.object({}).required().unknown(true),
|
|
35
|
+
transformer: Joi.string().optional(),
|
|
35
36
|
}))
|
|
36
37
|
}
|
|
37
38
|
|
|
@@ -42,6 +43,7 @@ function generateQueryPreviewValidation() {
|
|
|
42
43
|
queryVerb: Joi.string().allow().required(),
|
|
43
44
|
extra: Joi.object().optional(),
|
|
44
45
|
datasourceId: Joi.string().required(),
|
|
46
|
+
transformer: Joi.string().optional(),
|
|
45
47
|
parameters: Joi.object({}).required().unknown(true)
|
|
46
48
|
}))
|
|
47
49
|
}
|
|
@@ -3,7 +3,6 @@ const createRow = require("./steps/createRow")
|
|
|
3
3
|
const updateRow = require("./steps/updateRow")
|
|
4
4
|
const deleteRow = require("./steps/deleteRow")
|
|
5
5
|
const executeScript = require("./steps/executeScript")
|
|
6
|
-
const bash = require("./steps/bash")
|
|
7
6
|
const executeQuery = require("./steps/executeQuery")
|
|
8
7
|
const outgoingWebhook = require("./steps/outgoingWebhook")
|
|
9
8
|
const serverLog = require("./steps/serverLog")
|
|
@@ -14,6 +13,7 @@ const integromat = require("./steps/integromat")
|
|
|
14
13
|
let filter = require("./steps/filter")
|
|
15
14
|
let delay = require("./steps/delay")
|
|
16
15
|
let queryRow = require("./steps/queryRows")
|
|
16
|
+
const env = require("../environment")
|
|
17
17
|
|
|
18
18
|
const ACTION_IMPLS = {
|
|
19
19
|
SEND_EMAIL_SMTP: sendSmtpEmail.run,
|
|
@@ -22,7 +22,6 @@ const ACTION_IMPLS = {
|
|
|
22
22
|
DELETE_ROW: deleteRow.run,
|
|
23
23
|
OUTGOING_WEBHOOK: outgoingWebhook.run,
|
|
24
24
|
EXECUTE_SCRIPT: executeScript.run,
|
|
25
|
-
EXECUTE_BASH: bash.run,
|
|
26
25
|
EXECUTE_QUERY: executeQuery.run,
|
|
27
26
|
SERVER_LOG: serverLog.run,
|
|
28
27
|
DELAY: delay.run,
|
|
@@ -42,7 +41,6 @@ const ACTION_DEFINITIONS = {
|
|
|
42
41
|
OUTGOING_WEBHOOK: outgoingWebhook.definition,
|
|
43
42
|
EXECUTE_SCRIPT: executeScript.definition,
|
|
44
43
|
EXECUTE_QUERY: executeQuery.definition,
|
|
45
|
-
EXECUTE_BASH: bash.definition,
|
|
46
44
|
SERVER_LOG: serverLog.definition,
|
|
47
45
|
DELAY: delay.definition,
|
|
48
46
|
FILTER: filter.definition,
|
|
@@ -54,6 +52,15 @@ const ACTION_DEFINITIONS = {
|
|
|
54
52
|
integromat: integromat.definition,
|
|
55
53
|
}
|
|
56
54
|
|
|
55
|
+
// don't add the bash script/definitions unless in self host
|
|
56
|
+
// the fact this isn't included in any definitions means it cannot be
|
|
57
|
+
// ran at all
|
|
58
|
+
if (env.SELF_HOSTED) {
|
|
59
|
+
const bash = require("./steps/bash")
|
|
60
|
+
ACTION_IMPLS["EXECUTE_BASH"] = bash.run
|
|
61
|
+
ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
/* istanbul ignore next */
|
|
58
65
|
exports.getAction = async function (actionName) {
|
|
59
66
|
if (ACTION_IMPLS[actionName] != null) {
|
|
@@ -10,6 +10,7 @@ const env = require("../environment")
|
|
|
10
10
|
const usage = require("../utilities/usageQuota")
|
|
11
11
|
|
|
12
12
|
const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId
|
|
13
|
+
const STOPPED_STATUS = { success: false, status: "STOPPED" }
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The automation orchestrator is a class responsible for executing automations.
|
|
@@ -68,7 +69,13 @@ class Orchestrator {
|
|
|
68
69
|
async execute() {
|
|
69
70
|
let automation = this._automation
|
|
70
71
|
const app = await this.getApp()
|
|
72
|
+
let stopped = false
|
|
71
73
|
for (let step of automation.definition.steps) {
|
|
74
|
+
// execution stopped, record state for that
|
|
75
|
+
if (stopped) {
|
|
76
|
+
this.updateExecutionOutput(step.id, step.stepId, {}, STOPPED_STATUS)
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
72
79
|
let stepFn = await this.getStepFunctionality(step.stepId)
|
|
73
80
|
step.inputs = await processObject(step.inputs, this._context)
|
|
74
81
|
step.inputs = automationUtils.cleanInputValues(
|
|
@@ -86,10 +93,17 @@ class Orchestrator {
|
|
|
86
93
|
context: this._context,
|
|
87
94
|
})
|
|
88
95
|
})
|
|
96
|
+
this._context.steps.push(outputs)
|
|
97
|
+
// if filter causes us to stop execution don't break the loop, set a var
|
|
98
|
+
// so that we can finish iterating through the steps and record that it stopped
|
|
89
99
|
if (step.stepId === FILTER_STEP_ID && !outputs.success) {
|
|
90
|
-
|
|
100
|
+
stopped = true
|
|
101
|
+
this.updateExecutionOutput(step.id, step.stepId, step.inputs, {
|
|
102
|
+
...outputs,
|
|
103
|
+
...STOPPED_STATUS,
|
|
104
|
+
})
|
|
105
|
+
continue
|
|
91
106
|
}
|
|
92
|
-
this._context.steps.push(outputs)
|
|
93
107
|
this.updateExecutionOutput(step.id, step.stepId, step.inputs, outputs)
|
|
94
108
|
} catch (err) {
|
|
95
109
|
console.error(`Automation error - ${step.stepId} - ${err}`)
|
|
@@ -99,7 +113,7 @@ class Orchestrator {
|
|
|
99
113
|
|
|
100
114
|
// Increment quota for automation runs
|
|
101
115
|
if (!env.SELF_HOSTED && !isDevAppID(this._appId)) {
|
|
102
|
-
usage.update(usage.Properties.AUTOMATION, 1)
|
|
116
|
+
await usage.update(usage.Properties.AUTOMATION, 1)
|
|
103
117
|
}
|
|
104
118
|
return this.executionOutput
|
|
105
119
|
}
|
package/src/constants/index.js
CHANGED
|
@@ -98,7 +98,9 @@ function addFilters(
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
function addRelationships(
|
|
101
|
+
knex: Knex,
|
|
101
102
|
query: KnexQuery,
|
|
103
|
+
fields: string | string[],
|
|
102
104
|
fromTable: string,
|
|
103
105
|
relationships: RelationshipsJson[] | undefined
|
|
104
106
|
): KnexQuery {
|
|
@@ -114,7 +116,7 @@ function addRelationships(
|
|
|
114
116
|
query = query.leftJoin(
|
|
115
117
|
toTable,
|
|
116
118
|
`${fromTable}.${from}`,
|
|
117
|
-
`${
|
|
119
|
+
`${toTable}.${to}`
|
|
118
120
|
)
|
|
119
121
|
} else {
|
|
120
122
|
const throughTable = relationship.through
|
|
@@ -130,7 +132,7 @@ function addRelationships(
|
|
|
130
132
|
.leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`)
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
|
-
return query
|
|
135
|
+
return query.limit(BASE_LIMIT)
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
function buildCreate(
|
|
@@ -199,7 +201,7 @@ function buildRead(knex: Knex, json: QueryJson, limit: number): KnexQuery {
|
|
|
199
201
|
[tableName]: query,
|
|
200
202
|
}).select(selectStatement)
|
|
201
203
|
// handle joins
|
|
202
|
-
return addRelationships(preQuery, tableName, relationships)
|
|
204
|
+
return addRelationships(knex, preQuery, selectStatement, tableName, relationships)
|
|
203
205
|
}
|
|
204
206
|
|
|
205
207
|
function buildUpdate(
|
|
@@ -27,7 +27,7 @@ describe("MongoDB Integration", () => {
|
|
|
27
27
|
const body = {
|
|
28
28
|
name: "Hello"
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
await config.integration.create({
|
|
31
31
|
index: indexName,
|
|
32
32
|
json: body,
|
|
33
33
|
extra: { collection: 'testCollection', actionTypes: 'insertOne'}
|
|
@@ -54,7 +54,7 @@ describe("MongoDB Integration", () => {
|
|
|
54
54
|
},
|
|
55
55
|
extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
|
|
56
56
|
}
|
|
57
|
-
|
|
57
|
+
await config.integration.delete(query)
|
|
58
58
|
expect(config.integration.client.deleteOne).toHaveBeenCalledWith(query.json)
|
|
59
59
|
})
|
|
60
60
|
|
|
@@ -65,7 +65,7 @@ describe("MongoDB Integration", () => {
|
|
|
65
65
|
},
|
|
66
66
|
extra: { collection: 'testCollection', actionTypes: 'updateOne'}
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
await config.integration.update(query)
|
|
69
69
|
expect(config.integration.client.updateOne).toHaveBeenCalledWith(query.json)
|
|
70
70
|
})
|
|
71
71
|
|
|
@@ -75,10 +75,14 @@ describe("MongoDB Integration", () => {
|
|
|
75
75
|
const query = {
|
|
76
76
|
extra: { collection: 'testCollection', actionTypes: 'deleteOne'}
|
|
77
77
|
}
|
|
78
|
-
// Weird, need to do an IIFE for jest to recognize that it throws
|
|
79
|
-
expect(() => config.integration.read(query)()).toThrow(expect.any(Object))
|
|
80
78
|
|
|
79
|
+
let error = null
|
|
80
|
+
try {
|
|
81
|
+
await config.integration.read(query)
|
|
82
|
+
} catch (err) {
|
|
83
|
+
error = err
|
|
84
|
+
}
|
|
85
|
+
expect(error).toBeDefined()
|
|
81
86
|
restore()
|
|
82
87
|
})
|
|
83
|
-
|
|
84
88
|
})
|
|
@@ -45,7 +45,7 @@ module.exports = async (ctx, next) => {
|
|
|
45
45
|
const globalUser = await getCachedSelf(ctx, requestAppId)
|
|
46
46
|
appId = requestAppId
|
|
47
47
|
// retrieving global user gets the right role
|
|
48
|
-
roleId = globalUser.roleId ||
|
|
48
|
+
roleId = globalUser.roleId || roleId
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// nothing more to do
|
|
@@ -127,8 +127,8 @@ describe("Current app middleware", () => {
|
|
|
127
127
|
} else {
|
|
128
128
|
expect(cookieFn).not.toHaveBeenCalled()
|
|
129
129
|
}
|
|
130
|
-
expect(config.ctx.roleId).toEqual("
|
|
131
|
-
expect(config.ctx.user.role._id).toEqual("
|
|
130
|
+
expect(config.ctx.roleId).toEqual("PUBLIC")
|
|
131
|
+
expect(config.ctx.user.role._id).toEqual("PUBLIC")
|
|
132
132
|
expect(config.ctx.appId).toEqual("app_test")
|
|
133
133
|
expect(config.next).toHaveBeenCalled()
|
|
134
134
|
}
|
|
@@ -163,7 +163,7 @@ describe("Current app middleware", () => {
|
|
|
163
163
|
return "app_test"
|
|
164
164
|
},
|
|
165
165
|
setCookie: jest.fn(),
|
|
166
|
-
getCookie: () => ({appId: "app_test", roleId: "
|
|
166
|
+
getCookie: () => ({appId: "app_test", roleId: "PUBLIC"}),
|
|
167
167
|
},
|
|
168
168
|
constants: { Cookies: {} },
|
|
169
169
|
}))
|
package/src/utilities/global.js
CHANGED
|
@@ -26,7 +26,7 @@ exports.updateAppRole = (appId, user) => {
|
|
|
26
26
|
if (!user.roleId && user.builder && user.builder.global) {
|
|
27
27
|
user.roleId = BUILTIN_ROLE_IDS.ADMIN
|
|
28
28
|
} else if (!user.roleId) {
|
|
29
|
-
user.roleId = BUILTIN_ROLE_IDS.
|
|
29
|
+
user.roleId = BUILTIN_ROLE_IDS.PUBLIC
|
|
30
30
|
}
|
|
31
31
|
delete user.roles
|
|
32
32
|
return user
|
|
@@ -150,6 +150,10 @@ exports.processAutoColumn = processAutoColumn
|
|
|
150
150
|
* @returns {object} The coerced value
|
|
151
151
|
*/
|
|
152
152
|
exports.coerce = (row, type) => {
|
|
153
|
+
// no coercion specified for type, skip it
|
|
154
|
+
if (!TYPE_TRANSFORM_MAP[type]) {
|
|
155
|
+
return row
|
|
156
|
+
}
|
|
153
157
|
// eslint-disable-next-line no-prototype-builtins
|
|
154
158
|
if (TYPE_TRANSFORM_MAP[type].hasOwnProperty(row)) {
|
|
155
159
|
return TYPE_TRANSFORM_MAP[type][row]
|
|
@@ -196,6 +200,12 @@ exports.inputProcessing = (
|
|
|
196
200
|
clonedRow[key] = exports.coerce(value, field.type)
|
|
197
201
|
}
|
|
198
202
|
}
|
|
203
|
+
|
|
204
|
+
if (!clonedRow._id || !clonedRow._rev) {
|
|
205
|
+
clonedRow._id = row._id
|
|
206
|
+
clonedRow._rev = row._rev
|
|
207
|
+
}
|
|
208
|
+
|
|
199
209
|
// handle auto columns - this returns an object like {table, row}
|
|
200
210
|
return processAutoColumn(user, copiedTable, clonedRow, opts)
|
|
201
211
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const fetch = require("node-fetch")
|
|
2
|
+
const { VM, VMScript } = require("vm2")
|
|
3
|
+
|
|
4
|
+
class ScriptRunner {
|
|
5
|
+
constructor(script, context) {
|
|
6
|
+
const code = `let fn = () => {\n${script}\n}; results.out = fn();`
|
|
7
|
+
this.vm = new VM()
|
|
8
|
+
this.results = { out: "" }
|
|
9
|
+
this.vm.setGlobals(context)
|
|
10
|
+
this.vm.setGlobal("fetch", fetch)
|
|
11
|
+
this.vm.setGlobal("results", this.results)
|
|
12
|
+
this.script = new VMScript(code)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
execute() {
|
|
16
|
+
this.vm.run(this.script)
|
|
17
|
+
return this.results.out
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = ScriptRunner
|