@budibase/server 1.1.32 → 1.1.33-alpha.0
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.192adf4c.css → index.4d57d3d4.css} +2 -2
- package/builder/assets/index.f51f2e5c.js +977 -0
- package/builder/assets/{vendor.162098da.js → vendor.6bcafa60.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +381 -696
- package/coverage/coverage-final.json +13 -16
- package/coverage/lcov-report/api/controllers/apikeys.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 +1 -1
- package/coverage/lcov-report/api/controllers/index.html +1 -1
- 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/migrations.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +4 -4
- 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 +18 -18
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +94 -49
- package/coverage/lcov-report/api/controllers/row/staticFormula.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 +1 -1
- package/coverage/lcov-report/api/controllers/table/bulkFormula.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/templates.js.html +1 -1
- 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 +15 -15
- 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/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/index.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/migrations.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- 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/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.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/utils/index.html +1 -1
- package/coverage/lcov-report/api/routes/utils/validators.js.html +2 -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 +17 -17
- package/coverage/lcov-report/automations/index.html +1 -1
- 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/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +5 -2
- 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/loop.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/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 +18 -18
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +5 -14
- 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/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +19 -19
- package/coverage/lcov-report/db/index.js.html +1 -1
- 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 +1 -1
- package/coverage/lcov-report/db/utils.js.html +61 -13
- 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 +57 -72
- 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/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +21 -21
- package/coverage/lcov-report/middleware/joi-validator.js.html +43 -43
- package/coverage/lcov-report/middleware/publicApi.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/utils.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 +68 -14
- package/coverage/lcov-report/utilities/index.html +19 -19
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +26 -14
- package/coverage/lcov-report/utilities/queue/index.html +17 -17
- 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 +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
- 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/usageQuota/index.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.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 +695 -1214
- package/dist/api/controllers/deploy/index.js +1 -0
- package/dist/api/controllers/query/index.js +1 -1
- package/dist/api/controllers/query/validation.js +3 -3
- package/dist/api/controllers/row/internalSearch.js +30 -16
- package/dist/api/routes/utils/validators.js +1 -1
- package/dist/automations/utils.js +47 -1
- package/dist/constants/index.js +1 -4
- package/dist/db/utils.js +14 -1
- package/dist/definitions/automations.js +8 -0
- package/dist/integrations/base/sql.js +43 -14
- package/dist/package.json +8 -8
- package/dist/threads/automation.js +147 -54
- package/dist/threads/definitions.js +2 -0
- package/dist/threads/index.js +27 -20
- package/dist/threads/query.js +23 -15
- package/dist/threads/utils.js +47 -24
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/global.js +24 -5
- package/dist/utilities/queue/inMemoryQueue.js +5 -0
- package/package.json +9 -9
- package/src/api/controllers/deploy/index.ts +6 -1
- package/src/api/controllers/query/index.ts +1 -1
- package/src/api/controllers/query/validation.js +3 -3
- package/src/api/controllers/row/internalSearch.js +35 -20
- package/src/api/routes/tests/user.spec.js +2 -0
- package/src/api/routes/utils/validators.js +1 -1
- package/src/automations/steps/executeQuery.js +1 -0
- package/src/automations/tests/automation.spec.js +2 -2
- package/src/automations/utils.ts +54 -1
- package/src/constants/index.js +2 -5
- package/src/db/utils.js +16 -0
- package/src/definitions/automations.ts +49 -0
- package/src/definitions/datasource.ts +3 -0
- package/src/integrations/base/sql.ts +44 -13
- package/src/integrations/tests/sql.spec.js +50 -4
- package/src/middleware/tests/currentapp.spec.js +11 -0
- package/src/threads/{automation.js → automation.ts} +172 -48
- package/src/threads/definitions.ts +18 -0
- package/src/threads/index.ts +31 -23
- package/src/threads/{query.js → query.ts} +32 -12
- package/src/threads/{utils.js → utils.ts} +31 -12
- package/src/utilities/global.js +21 -3
- package/src/utilities/queue/inMemoryQueue.js +4 -0
- package/builder/assets/index.133db51f.js +0 -978
- package/coverage/lcov-report/threads/automation.js.html +0 -1114
- package/coverage/lcov-report/threads/index.html +0 -146
- package/coverage/lcov-report/threads/query.js.html +0 -916
- package/coverage/lcov-report/threads/utils.js.html +0 -319
package/dist/utilities/global.js
CHANGED
|
@@ -16,7 +16,9 @@ const { user: userCache } = require("@budibase/backend-core/cache");
|
|
|
16
16
|
const { getGlobalDB, isUserInAppTenant, } = require("@budibase/backend-core/tenancy");
|
|
17
17
|
const env = require("../environment");
|
|
18
18
|
const { getAppId } = require("@budibase/backend-core/context");
|
|
19
|
+
const { groups } = require("@budibase/pro");
|
|
19
20
|
exports.updateAppRole = (user, { appId } = {}) => {
|
|
21
|
+
var _a, _b;
|
|
20
22
|
appId = appId || getAppId();
|
|
21
23
|
if (!user || !user.roles) {
|
|
22
24
|
return user;
|
|
@@ -34,17 +36,34 @@ exports.updateAppRole = (user, { appId } = {}) => {
|
|
|
34
36
|
if (!user.roleId && user.builder && user.builder.global) {
|
|
35
37
|
user.roleId = BUILTIN_ROLE_IDS.ADMIN;
|
|
36
38
|
}
|
|
37
|
-
else if (!user.roleId) {
|
|
39
|
+
else if (!user.roleId && !((_a = user === null || user === void 0 ? void 0 : user.userGroups) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
38
40
|
user.roleId = BUILTIN_ROLE_IDS.PUBLIC;
|
|
39
41
|
}
|
|
42
|
+
else if ((_b = user === null || user === void 0 ? void 0 : user.userGroups) === null || _b === void 0 ? void 0 : _b.length) {
|
|
43
|
+
user.roleId = null;
|
|
44
|
+
}
|
|
40
45
|
delete user.roles;
|
|
41
46
|
return user;
|
|
42
47
|
};
|
|
48
|
+
function checkGroupRoles(user, { appId } = {}) {
|
|
49
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
let roleId = yield groups.getGroupRoleId(user, appId);
|
|
51
|
+
user.roleId = roleId;
|
|
52
|
+
return user;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
43
55
|
function processUser(user, { appId } = {}) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
var _a;
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
if (user) {
|
|
59
|
+
delete user.password;
|
|
60
|
+
}
|
|
61
|
+
user = yield exports.updateAppRole(user, { appId });
|
|
62
|
+
if (!user.roleId && ((_a = user === null || user === void 0 ? void 0 : user.userGroups) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
63
|
+
user = yield checkGroupRoles(user, { appId });
|
|
64
|
+
}
|
|
65
|
+
return user;
|
|
66
|
+
});
|
|
48
67
|
}
|
|
49
68
|
exports.getCachedSelf = (ctx, appId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
69
|
// this has to be tenant aware, can't depend on the context to find it out
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.33-alpha.0",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -77,11 +77,11 @@
|
|
|
77
77
|
"license": "GPL-3.0",
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
80
|
-
"@budibase/backend-core": "
|
|
81
|
-
"@budibase/client": "
|
|
82
|
-
"@budibase/pro": "1.1.
|
|
83
|
-
"@budibase/string-templates": "
|
|
84
|
-
"@budibase/types": "
|
|
80
|
+
"@budibase/backend-core": "1.1.33-alpha.0",
|
|
81
|
+
"@budibase/client": "1.1.33-alpha.0",
|
|
82
|
+
"@budibase/pro": "1.1.32",
|
|
83
|
+
"@budibase/string-templates": "1.1.33-alpha.0",
|
|
84
|
+
"@budibase/types": "1.1.33-alpha.0",
|
|
85
85
|
"@bull-board/api": "3.7.0",
|
|
86
86
|
"@bull-board/koa": "3.9.4",
|
|
87
87
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"koa-send": "5.0.0",
|
|
119
119
|
"koa-session": "5.12.0",
|
|
120
120
|
"koa-static": "5.0.0",
|
|
121
|
-
"koa2-ratelimit": "1.1.
|
|
121
|
+
"koa2-ratelimit": "1.1.1",
|
|
122
122
|
"lodash": "4.17.21",
|
|
123
123
|
"memorystream": "0.3.1",
|
|
124
124
|
"mongodb": "3.6.3",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"redis": "4",
|
|
138
138
|
"server-destroy": "1.0.1",
|
|
139
139
|
"snowflake-promise": "^4.5.0",
|
|
140
|
-
"svelte": "3.
|
|
140
|
+
"svelte": "3.49.0",
|
|
141
141
|
"swagger-parser": "10.0.3",
|
|
142
142
|
"to-json-schema": "0.2.5",
|
|
143
143
|
"uuid": "3.3.2",
|
|
@@ -195,5 +195,5 @@
|
|
|
195
195
|
"optionalDependencies": {
|
|
196
196
|
"oracledb": "5.3.0"
|
|
197
197
|
},
|
|
198
|
-
"gitHead": "
|
|
198
|
+
"gitHead": "b57c4e5e740dafe0a44c035602d121eff65c70e2"
|
|
199
199
|
}
|
|
@@ -5,7 +5,11 @@ import {
|
|
|
5
5
|
getDevelopmentAppID,
|
|
6
6
|
} from "@budibase/backend-core/db"
|
|
7
7
|
import { DocumentTypes, getAutomationParams } from "../../../db/utils"
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
disableAllCrons,
|
|
10
|
+
enableCronTrigger,
|
|
11
|
+
clearMetadata,
|
|
12
|
+
} from "../../../automations/utils"
|
|
9
13
|
import { app as appCache } from "@budibase/backend-core/cache"
|
|
10
14
|
import {
|
|
11
15
|
getAppId,
|
|
@@ -80,6 +84,7 @@ async function initDeployedApp(prodAppId: any) {
|
|
|
80
84
|
})
|
|
81
85
|
)
|
|
82
86
|
).rows.map((row: any) => row.doc)
|
|
87
|
+
await clearMetadata()
|
|
83
88
|
console.log("You have " + automations.length + " automations")
|
|
84
89
|
const promises = []
|
|
85
90
|
console.log("Disabling prod crons..")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const joiValidator = require("
|
|
1
|
+
const { joiValidator } = require("@budibase/backend-core/auth")
|
|
2
2
|
const Joi = require("joi")
|
|
3
3
|
|
|
4
4
|
const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("")
|
|
@@ -22,7 +22,7 @@ exports.queryValidation = () => {
|
|
|
22
22
|
schema: Joi.object({}).required().unknown(true),
|
|
23
23
|
transformer: OPTIONAL_STRING,
|
|
24
24
|
flags: Joi.object().optional(),
|
|
25
|
-
})
|
|
25
|
+
}).unknown(true)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
exports.generateQueryValidation = () => {
|
|
@@ -46,5 +46,5 @@ exports.generateQueryPreviewValidation = () => {
|
|
|
46
46
|
transformer: OPTIONAL_STRING,
|
|
47
47
|
parameters: Joi.object({}).required().unknown(true),
|
|
48
48
|
queryId: OPTIONAL_STRING,
|
|
49
|
-
}))
|
|
49
|
+
}).unknown(true))
|
|
50
50
|
}
|
|
@@ -19,6 +19,7 @@ class QueryBuilder {
|
|
|
19
19
|
empty: {},
|
|
20
20
|
notEmpty: {},
|
|
21
21
|
oneOf: {},
|
|
22
|
+
contains: {},
|
|
22
23
|
...base,
|
|
23
24
|
}
|
|
24
25
|
this.limit = 50
|
|
@@ -119,6 +120,11 @@ class QueryBuilder {
|
|
|
119
120
|
return this
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
addContains(key, value) {
|
|
124
|
+
this.query.contains[key] = value
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
122
128
|
/**
|
|
123
129
|
* Preprocesses a value before going into a lucene search.
|
|
124
130
|
* Transforms strings to lowercase and wraps strings and bools in quotes.
|
|
@@ -164,6 +170,31 @@ class QueryBuilder {
|
|
|
164
170
|
return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
const contains = (key, value) => {
|
|
174
|
+
if (!value && value !== 0) {
|
|
175
|
+
return null
|
|
176
|
+
}
|
|
177
|
+
return `${key}:${builder.preprocess(value, { escape: true })}`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const oneOf = (key, value) => {
|
|
181
|
+
if (!Array.isArray(value)) {
|
|
182
|
+
if (typeof value === "string") {
|
|
183
|
+
value = value.split(",")
|
|
184
|
+
} else {
|
|
185
|
+
return ""
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
let orStatement = `${builder.preprocess(value[0], allPreProcessingOpts)}`
|
|
189
|
+
for (let i = 1; i < value.length; i++) {
|
|
190
|
+
orStatement += ` OR ${builder.preprocess(
|
|
191
|
+
value[i],
|
|
192
|
+
allPreProcessingOpts
|
|
193
|
+
)}`
|
|
194
|
+
}
|
|
195
|
+
return `${key}:(${orStatement})`
|
|
196
|
+
}
|
|
197
|
+
|
|
167
198
|
function build(structure, queryFn) {
|
|
168
199
|
for (let [key, value] of Object.entries(structure)) {
|
|
169
200
|
key = builder.preprocess(key.replace(/ /g, "_"), {
|
|
@@ -239,26 +270,10 @@ class QueryBuilder {
|
|
|
239
270
|
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
|
240
271
|
}
|
|
241
272
|
if (this.query.oneOf) {
|
|
242
|
-
build(this.query.oneOf,
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
} else {
|
|
247
|
-
return ""
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
let orStatement = `${builder.preprocess(
|
|
251
|
-
value[0],
|
|
252
|
-
allPreProcessingOpts
|
|
253
|
-
)}`
|
|
254
|
-
for (let i = 1; i < value.length; i++) {
|
|
255
|
-
orStatement += ` OR ${builder.preprocess(
|
|
256
|
-
value[i],
|
|
257
|
-
allPreProcessingOpts
|
|
258
|
-
)}`
|
|
259
|
-
}
|
|
260
|
-
return `${key}:(${orStatement})`
|
|
261
|
-
})
|
|
273
|
+
build(this.query.oneOf, oneOf)
|
|
274
|
+
}
|
|
275
|
+
if (this.query.contains) {
|
|
276
|
+
build(this.query.contains, contains)
|
|
262
277
|
}
|
|
263
278
|
// make sure table ID is always added as an AND
|
|
264
279
|
if (tableId) {
|
|
@@ -23,6 +23,7 @@ describe("/users", () => {
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
describe("fetch", () => {
|
|
26
|
+
|
|
26
27
|
it("returns a list of users from an instance db", async () => {
|
|
27
28
|
await config.createUser("uuidx")
|
|
28
29
|
await config.createUser("uuidy")
|
|
@@ -37,6 +38,7 @@ describe("/users", () => {
|
|
|
37
38
|
expect(res.body.find(u => u._id === `ro_ta_users_us_uuidy`)).toBeDefined()
|
|
38
39
|
})
|
|
39
40
|
|
|
41
|
+
|
|
40
42
|
it("should apply authorization to endpoint", async () => {
|
|
41
43
|
await config.createUser()
|
|
42
44
|
await checkPermissionsEndpoint({
|
|
@@ -31,7 +31,7 @@ describe("Run through some parts of the automations system", () => {
|
|
|
31
31
|
it("should be able to init in builder", async () => {
|
|
32
32
|
await triggers.externalTrigger(basicAutomation(), { a: 1 })
|
|
33
33
|
await wait(100)
|
|
34
|
-
expect(thread).toHaveBeenCalled()
|
|
34
|
+
expect(thread.execute).toHaveBeenCalled()
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
it("should be able to init in prod", async () => {
|
|
@@ -52,7 +52,7 @@ describe("Run through some parts of the automations system", () => {
|
|
|
52
52
|
}
|
|
53
53
|
})
|
|
54
54
|
await wait(100)
|
|
55
|
-
expect(thread).toHaveBeenCalledWith(makePartial({
|
|
55
|
+
expect(thread.execute).toHaveBeenCalledWith(makePartial({
|
|
56
56
|
data: {
|
|
57
57
|
event: {
|
|
58
58
|
fields: {
|
package/src/automations/utils.ts
CHANGED
|
@@ -6,10 +6,16 @@ import newid from "../db/newid"
|
|
|
6
6
|
import { updateEntityMetadata } from "../utilities"
|
|
7
7
|
import { MetadataTypes, WebhookType } from "../constants"
|
|
8
8
|
import { getProdAppID, doWithDB } from "@budibase/backend-core/db"
|
|
9
|
+
import { getAutomationMetadataParams } from "../db/utils"
|
|
9
10
|
import { cloneDeep } from "lodash/fp"
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getAppDB,
|
|
13
|
+
getAppId,
|
|
14
|
+
getProdAppDB,
|
|
15
|
+
} from "@budibase/backend-core/context"
|
|
11
16
|
import { tenancy } from "@budibase/backend-core"
|
|
12
17
|
import { quotas } from "@budibase/pro"
|
|
18
|
+
import { Automation } from "@budibase/types"
|
|
13
19
|
|
|
14
20
|
const WH_STEP_ID = definitions.WEBHOOK.stepId
|
|
15
21
|
const CRON_STEP_ID = definitions.CRON.stepId
|
|
@@ -82,6 +88,26 @@ export async function disableAllCrons(appId: any) {
|
|
|
82
88
|
return Promise.all(promises)
|
|
83
89
|
}
|
|
84
90
|
|
|
91
|
+
export async function disableCron(jobId: string, jobKey: string) {
|
|
92
|
+
await queue.removeRepeatableByKey(jobKey)
|
|
93
|
+
await queue.removeJobs(jobId)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function clearMetadata() {
|
|
97
|
+
const db = getProdAppDB()
|
|
98
|
+
const automationMetadata = (
|
|
99
|
+
await db.allDocs(
|
|
100
|
+
getAutomationMetadataParams({
|
|
101
|
+
include_docs: true,
|
|
102
|
+
})
|
|
103
|
+
)
|
|
104
|
+
).rows.map((row: any) => row.doc)
|
|
105
|
+
for (let metadata of automationMetadata) {
|
|
106
|
+
metadata._deleted = true
|
|
107
|
+
}
|
|
108
|
+
await db.bulkDocs(automationMetadata)
|
|
109
|
+
}
|
|
110
|
+
|
|
85
111
|
/**
|
|
86
112
|
* This function handles checking of any cron jobs that need to be enabled/updated.
|
|
87
113
|
* @param {string} appId The ID of the app in which we are checking for webhooks
|
|
@@ -204,3 +230,30 @@ export async function checkForWebhooks({ oldAuto, newAuto }: any) {
|
|
|
204
230
|
export async function cleanupAutomations(appId: any) {
|
|
205
231
|
await disableAllCrons(appId)
|
|
206
232
|
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Checks if the supplied automation is of a recurring type.
|
|
236
|
+
* @param automation The automation to check.
|
|
237
|
+
* @return {boolean} if it is recurring (cron).
|
|
238
|
+
*/
|
|
239
|
+
export function isRecurring(automation: Automation) {
|
|
240
|
+
return automation.definition.trigger.stepId === definitions.CRON.stepId
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export function isErrorInOutput(output: {
|
|
244
|
+
steps: { outputs?: { success: boolean } }[]
|
|
245
|
+
}) {
|
|
246
|
+
let first = true,
|
|
247
|
+
error = false
|
|
248
|
+
for (let step of output.steps) {
|
|
249
|
+
// skip the trigger, its always successful if automation ran
|
|
250
|
+
if (first) {
|
|
251
|
+
first = false
|
|
252
|
+
continue
|
|
253
|
+
}
|
|
254
|
+
if (!step.outputs?.success) {
|
|
255
|
+
error = true
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return error
|
|
259
|
+
}
|
package/src/constants/index.js
CHANGED
|
@@ -208,10 +208,7 @@ exports.AutomationErrors = {
|
|
|
208
208
|
FAILURE_CONDITION: "FAILURE_CONDITION_MET",
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
exports.LoopStepTypes = {
|
|
212
|
-
ARRAY: "Array",
|
|
213
|
-
STRING: "String",
|
|
214
|
-
}
|
|
215
|
-
|
|
216
211
|
// pass through the list from the auth/core lib
|
|
217
212
|
exports.ObjectStoreBuckets = ObjectStoreBuckets
|
|
213
|
+
|
|
214
|
+
exports.MAX_AUTOMATION_RECURRING_ERRORS = 5
|
package/src/db/utils.js
CHANGED
|
@@ -41,6 +41,7 @@ const DocumentTypes = {
|
|
|
41
41
|
METADATA: "metadata",
|
|
42
42
|
MEM_VIEW: "view",
|
|
43
43
|
USER_FLAG: "flag",
|
|
44
|
+
AUTOMATION_METADATA: "meta_au",
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
const InternalTables = {
|
|
@@ -311,6 +312,21 @@ exports.generateQueryID = datasourceId => {
|
|
|
311
312
|
}${SEPARATOR}${datasourceId}${SEPARATOR}${newid()}`
|
|
312
313
|
}
|
|
313
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Generates a metadata ID for automations, used to track errors in recurring
|
|
317
|
+
* automations etc.
|
|
318
|
+
*/
|
|
319
|
+
exports.generateAutomationMetadataID = automationId => {
|
|
320
|
+
return `${DocumentTypes.AUTOMATION_METADATA}${SEPARATOR}${automationId}`
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Retrieve all automation metadata in an app database.
|
|
325
|
+
*/
|
|
326
|
+
exports.getAutomationMetadataParams = (otherProps = {}) => {
|
|
327
|
+
return getDocParams(DocumentTypes.AUTOMATION_METADATA, null, otherProps)
|
|
328
|
+
}
|
|
329
|
+
|
|
314
330
|
/**
|
|
315
331
|
* Gets parameters for retrieving a query, this is a utility function for the getDocParams function.
|
|
316
332
|
*/
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Automation,
|
|
3
|
+
AutomationResults,
|
|
4
|
+
AutomationStep,
|
|
5
|
+
Document,
|
|
6
|
+
} from "@budibase/types"
|
|
7
|
+
|
|
8
|
+
export enum LoopStepTypes {
|
|
9
|
+
ARRAY = "Array",
|
|
10
|
+
STRING = "String",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface LoopStep extends AutomationStep {
|
|
14
|
+
inputs: {
|
|
15
|
+
option: LoopStepTypes
|
|
16
|
+
[key: string]: any
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LoopInput {
|
|
21
|
+
binding: string[] | string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface TriggerOutput {
|
|
25
|
+
metadata?: any
|
|
26
|
+
appId?: string
|
|
27
|
+
timestamp?: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface AutomationEvent {
|
|
31
|
+
data: {
|
|
32
|
+
automation: Automation
|
|
33
|
+
event: any
|
|
34
|
+
}
|
|
35
|
+
opts?: {
|
|
36
|
+
repeat?: {
|
|
37
|
+
jobId: string
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface AutomationContext extends AutomationResults {
|
|
43
|
+
steps: any[]
|
|
44
|
+
trigger: any
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface AutomationMetadata extends Document {
|
|
48
|
+
errorCount?: number
|
|
49
|
+
}
|
|
@@ -142,6 +142,21 @@ class InternalBuilder {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
|
|
146
|
+
const like = (key: string, value: any) => {
|
|
147
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
148
|
+
// postgres supports ilike, nothing else does
|
|
149
|
+
if (this.client === SqlClients.POSTGRES) {
|
|
150
|
+
query = query[fnc](key, "ilike", `%${value}%`)
|
|
151
|
+
} else {
|
|
152
|
+
const rawFnc = `${fnc}Raw`
|
|
153
|
+
// @ts-ignore
|
|
154
|
+
query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [
|
|
155
|
+
`%${value}%`,
|
|
156
|
+
])
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
145
160
|
if (!filters) {
|
|
146
161
|
return query
|
|
147
162
|
}
|
|
@@ -168,19 +183,7 @@ class InternalBuilder {
|
|
|
168
183
|
})
|
|
169
184
|
}
|
|
170
185
|
if (filters.fuzzy) {
|
|
171
|
-
iterate(filters.fuzzy,
|
|
172
|
-
const fnc = allOr ? "orWhere" : "where"
|
|
173
|
-
// postgres supports ilike, nothing else does
|
|
174
|
-
if (this.client === SqlClients.POSTGRES) {
|
|
175
|
-
query = query[fnc](key, "ilike", `%${value}%`)
|
|
176
|
-
} else {
|
|
177
|
-
const rawFnc = `${fnc}Raw`
|
|
178
|
-
// @ts-ignore
|
|
179
|
-
query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [
|
|
180
|
-
`%${value}%`,
|
|
181
|
-
])
|
|
182
|
-
}
|
|
183
|
-
})
|
|
186
|
+
iterate(filters.fuzzy, like)
|
|
184
187
|
}
|
|
185
188
|
if (filters.range) {
|
|
186
189
|
iterate(filters.range, (key, value) => {
|
|
@@ -223,6 +226,34 @@ class InternalBuilder {
|
|
|
223
226
|
query = query[fnc](key)
|
|
224
227
|
})
|
|
225
228
|
}
|
|
229
|
+
if (filters.contains) {
|
|
230
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
231
|
+
const rawFnc = `${fnc}Raw`
|
|
232
|
+
if (this.client === SqlClients.POSTGRES) {
|
|
233
|
+
iterate(filters.contains, (key: string, value: any) => {
|
|
234
|
+
const fieldNames = key.split(/\./g)
|
|
235
|
+
const tableName = fieldNames[0]
|
|
236
|
+
const columnName = fieldNames[1]
|
|
237
|
+
if (typeof value === "string") {
|
|
238
|
+
value = `"${value}"`
|
|
239
|
+
}
|
|
240
|
+
// @ts-ignore
|
|
241
|
+
query = query[rawFnc](
|
|
242
|
+
`"${tableName}"."${columnName}"::jsonb @> '[${value}]'`
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
} else if (this.client === SqlClients.MY_SQL) {
|
|
246
|
+
iterate(filters.contains, (key: string, value: any) => {
|
|
247
|
+
if (typeof value === "string") {
|
|
248
|
+
value = `"${value}"`
|
|
249
|
+
}
|
|
250
|
+
// @ts-ignore
|
|
251
|
+
query = query[rawFnc](`JSON_CONTAINS(${key}, '${value}')`)
|
|
252
|
+
})
|
|
253
|
+
} else {
|
|
254
|
+
iterate(filters.contains, like)
|
|
255
|
+
}
|
|
256
|
+
}
|
|
226
257
|
return query
|
|
227
258
|
}
|
|
228
259
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const Sql = require("../base/sql")
|
|
2
|
+
const { SqlClients } = require("../utils")
|
|
2
3
|
|
|
3
4
|
const TABLE_NAME = "test"
|
|
4
5
|
|
|
@@ -46,7 +47,7 @@ function generateDeleteJson(table = TABLE_NAME, filters = {}) {
|
|
|
46
47
|
|
|
47
48
|
describe("SQL query builder", () => {
|
|
48
49
|
const limit = 500
|
|
49
|
-
const client =
|
|
50
|
+
const client = SqlClients.POSTGRES
|
|
50
51
|
let sql
|
|
51
52
|
|
|
52
53
|
beforeEach(() => {
|
|
@@ -173,15 +174,15 @@ describe("SQL query builder", () => {
|
|
|
173
174
|
})
|
|
174
175
|
|
|
175
176
|
it("should work with MS-SQL", () => {
|
|
176
|
-
const query = new Sql(
|
|
177
|
+
const query = new Sql(SqlClients.MS_SQL, 10)._query(generateReadJson())
|
|
177
178
|
expect(query).toEqual({
|
|
178
179
|
bindings: [10],
|
|
179
180
|
sql: `select * from (select top (@p0) * from [${TABLE_NAME}]) as [${TABLE_NAME}]`
|
|
180
181
|
})
|
|
181
182
|
})
|
|
182
183
|
|
|
183
|
-
it("should work with
|
|
184
|
-
const query = new Sql(
|
|
184
|
+
it("should work with MySQL", () => {
|
|
185
|
+
const query = new Sql(SqlClients.MY_SQL, 10)._query(generateReadJson())
|
|
185
186
|
expect(query).toEqual({
|
|
186
187
|
bindings: [10],
|
|
187
188
|
sql: `select * from (select * from \`${TABLE_NAME}\` limit ?) as \`${TABLE_NAME}\``
|
|
@@ -238,4 +239,49 @@ describe("SQL query builder", () => {
|
|
|
238
239
|
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"`
|
|
239
240
|
})
|
|
240
241
|
})
|
|
242
|
+
|
|
243
|
+
it("should use like expression for MS-SQL when filter is contains", () => {
|
|
244
|
+
const query = new Sql(SqlClients.MS_SQL, 10)._query(generateReadJson({
|
|
245
|
+
filters: {
|
|
246
|
+
contains: {
|
|
247
|
+
age: 20,
|
|
248
|
+
name: "John"
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}))
|
|
252
|
+
expect(query).toEqual({
|
|
253
|
+
bindings: [10, "%20%", "%John%"],
|
|
254
|
+
sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where LOWER(${TABLE_NAME}.age) LIKE @p1 and LOWER(${TABLE_NAME}.name) LIKE @p2) as [${TABLE_NAME}]`
|
|
255
|
+
})
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it("should use JSON_CONTAINS expression for MySQL when filter is contains", () => {
|
|
259
|
+
const query = new Sql(SqlClients.MY_SQL, 10)._query(generateReadJson({
|
|
260
|
+
filters: {
|
|
261
|
+
contains: {
|
|
262
|
+
age: 20,
|
|
263
|
+
name: "John"
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}))
|
|
267
|
+
expect(query).toEqual({
|
|
268
|
+
bindings: [10],
|
|
269
|
+
sql: `select * from (select * from \`${TABLE_NAME}\` where JSON_CONTAINS(${TABLE_NAME}.age, '20') and JSON_CONTAINS(${TABLE_NAME}.name, '"John"') limit ?) as \`${TABLE_NAME}\``
|
|
270
|
+
})
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it("should use jsonb operator expression for PostgreSQL when filter is contains", () => {
|
|
274
|
+
const query = new Sql(SqlClients.POSTGRES, 10)._query(generateReadJson({
|
|
275
|
+
filters: {
|
|
276
|
+
contains: {
|
|
277
|
+
age: 20,
|
|
278
|
+
name: "John"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}))
|
|
282
|
+
expect(query).toEqual({
|
|
283
|
+
bindings: [10],
|
|
284
|
+
sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"age\"::jsonb @> '[20]' and \"${TABLE_NAME}\".\"name\"::jsonb @> '["John"]' limit $1) as \"${TABLE_NAME}\"`
|
|
285
|
+
})
|
|
286
|
+
})
|
|
241
287
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
mockAuthWithNoCookie()
|
|
2
2
|
mockWorker()
|
|
3
|
+
mockUserGroups()
|
|
3
4
|
|
|
4
5
|
jest.mock("@budibase/backend-core/db", () => {
|
|
5
6
|
const coreDb = jest.requireActual("@budibase/backend-core/db")
|
|
@@ -29,6 +30,16 @@ function mockReset() {
|
|
|
29
30
|
mockWorker()
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
function mockUserGroups() {
|
|
34
|
+
jest.mock("@budibase/pro", () => ({
|
|
35
|
+
groups: {
|
|
36
|
+
getGroupRoleId: () => {
|
|
37
|
+
return "BASIC"
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
}))
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
function mockAuthWithNoCookie() {
|
|
33
44
|
jest.resetModules()
|
|
34
45
|
mockWorker()
|