@budibase/server 1.0.219 → 1.0.220-alpha.2
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/.yarnrc +1 -0
- package/__mocks__/node-fetch.ts +9 -0
- package/builder/assets/index.7786f497.css +6 -0
- package/builder/assets/index.e1885c5f.js +974 -0
- package/builder/assets/{vendor.9bf2fcb4.js → vendor.001dcf8c.js} +163 -163
- package/builder/index.html +3 -3
- package/coverage/clover.xml +1018 -950
- package/coverage/coverage-final.json +31 -31
- 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 +111 -12
- package/coverage/lcov-report/api/controllers/backup.js.html +9 -6
- 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 +16 -16
- package/coverage/lcov-report/api/controllers/dev.js.html +13 -166
- package/coverage/lcov-report/api/controllers/index.html +32 -32
- 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 +1 -1
- 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 +47 -17
- package/coverage/lcov-report/api/controllers/row/index.html +33 -33
- package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +159 -21
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +17 -8
- 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 +1 -1
- package/coverage/lcov-report/api/index.html +15 -15
- package/coverage/lcov-report/api/index.js.html +22 -13
- 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 +32 -2
- 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 +2 -5
- 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 +5 -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 +57 -12
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +17 -17
- 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 +2 -2
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +58 -34
- 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/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 +4 -4
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- 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 +14 -14
- 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 +13 -13
- package/coverage/lcov-report/db/linkedRows/index.js.html +10 -7
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +2 -2
- package/coverage/lcov-report/db/utils.js.html +27 -51
- 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 +83 -83
- 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 +12 -12
- package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +10 -10
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +2 -2
- package/coverage/lcov-report/threads/automation.js.html +18 -9
- package/coverage/lcov-report/threads/index.html +25 -25
- package/coverage/lcov-report/threads/query.js.html +301 -79
- package/coverage/lcov-report/threads/utils.js.html +4 -4
- 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 +14 -14
- package/coverage/lcov-report/utilities/index.html +26 -26
- package/coverage/lcov-report/utilities/index.js.html +17 -32
- 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 +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 +57 -9
- package/coverage/lcov.info +1789 -1665
- package/dist/api/controllers/application.js +19 -16
- package/dist/api/controllers/automation.js +28 -2
- package/dist/api/controllers/backup.js +3 -2
- package/dist/api/controllers/dev.js +2 -40
- package/dist/api/controllers/public/applications.js +1 -1
- package/dist/api/controllers/public/utils.js +8 -1
- package/dist/api/controllers/query/index.js +31 -3
- package/dist/api/controllers/row/external.js +19 -7
- package/dist/api/controllers/row/internalSearch.js +47 -10
- package/dist/api/controllers/row/utils.js +3 -0
- package/dist/api/controllers/static/index.js +1 -5
- package/dist/api/index.js +4 -1
- package/dist/api/routes/automation.js +2 -0
- package/dist/api/routes/dev.js +1 -2
- package/dist/api/routes/public/rows.js +7 -2
- package/dist/api/routes/utils/validators.js +1 -0
- package/dist/app.js +20 -0
- package/dist/automations/automationUtils.js +16 -4
- package/dist/automations/logging/index.js +70 -0
- package/dist/automations/steps/executeQuery.js +1 -1
- package/dist/automations/steps/filter.js +38 -29
- package/dist/automations/triggers.js +1 -1
- package/dist/db/linkedRows/index.js +1 -0
- package/dist/db/utils.js +4 -31
- package/dist/definitions/datasource.js +1 -0
- package/dist/environment.js +3 -0
- package/dist/integrations/airtable.js +1 -0
- package/dist/integrations/arangodb.js +1 -0
- package/dist/integrations/base/sql.js +22 -3
- package/dist/integrations/couchdb.js +1 -0
- package/dist/integrations/dynamodb.js +1 -0
- package/dist/integrations/elasticsearch.js +1 -0
- package/dist/integrations/firebase.js +1 -0
- package/dist/integrations/googlesheets.js +1 -0
- package/dist/integrations/index.js +4 -0
- package/dist/integrations/microsoftSqlServer.js +2 -1
- package/dist/integrations/mongodb.js +1 -0
- package/dist/integrations/mysql.js +2 -1
- package/dist/integrations/oracle.js +1 -0
- package/dist/integrations/postgres.js +2 -1
- package/dist/integrations/queries/sql.js +3 -0
- package/dist/integrations/redis.js +1 -0
- package/dist/integrations/rest.js +2 -1
- package/dist/integrations/s3.js +1 -0
- package/dist/integrations/snowflake.js +102 -0
- package/dist/package.json +7 -6
- package/dist/tests/utilities/TestConfiguration.js +19 -6
- package/dist/threads/automation.js +6 -3
- package/dist/threads/index.js +15 -1
- package/dist/threads/query.js +65 -12
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utilities/fileSystem/index.js +16 -6
- package/dist/utilities/index.js +1 -5
- package/dist/utilities/workerRequests.js +8 -0
- package/package.json +8 -7
- package/scripts/dev/manage.js +2 -0
- package/scripts/integrations/oracle/instantclient/linux/arm64/basiclite-19.10.zip +0 -0
- package/scripts/integrations/oracle/instantclient/linux/arm64/install.sh +23 -0
- package/scripts/integrations/oracle/instantclient/linux/install.sh +10 -0
- package/specs/openapi.json +9 -5
- package/specs/openapi.yaml +10 -4
- package/src/api/controllers/application.ts +19 -19
- package/src/api/controllers/automation.js +35 -2
- package/src/api/controllers/backup.js +3 -2
- package/src/api/controllers/dev.js +2 -53
- package/src/api/controllers/public/applications.ts +2 -2
- package/src/api/controllers/public/utils.ts +8 -1
- package/src/api/controllers/query/index.ts +40 -4
- package/src/api/controllers/row/external.js +19 -9
- package/src/api/controllers/row/internalSearch.js +55 -9
- package/src/api/controllers/row/utils.js +3 -0
- package/src/api/controllers/static/index.js +1 -6
- package/src/api/index.js +4 -1
- package/src/api/routes/automation.js +10 -0
- package/src/api/routes/dev.js +0 -1
- package/src/api/routes/public/rows.ts +7 -2
- package/src/api/routes/tests/query.spec.js +166 -1
- package/src/api/routes/utils/validators.js +1 -0
- package/src/app.ts +30 -1
- package/src/automations/automationUtils.js +19 -4
- package/src/automations/logging/index.ts +35 -0
- package/src/automations/steps/executeQuery.js +1 -1
- package/src/automations/steps/filter.js +36 -28
- package/src/automations/tests/filter.spec.js +2 -1
- package/src/automations/triggers.js +1 -1
- package/src/db/linkedRows/index.js +1 -0
- package/src/db/utils.js +5 -13
- package/src/definitions/common.ts +1 -0
- package/src/definitions/datasource.ts +2 -0
- package/src/definitions/openapi.ts +471 -469
- package/src/environment.js +3 -0
- package/src/integrations/airtable.ts +1 -0
- package/src/integrations/arangodb.ts +1 -0
- package/src/integrations/base/sql.ts +29 -11
- package/src/integrations/couchdb.ts +1 -0
- package/src/integrations/dynamodb.ts +1 -0
- package/src/integrations/elasticsearch.ts +1 -0
- package/src/integrations/firebase.ts +1 -0
- package/src/integrations/googlesheets.ts +1 -0
- package/src/integrations/index.ts +4 -0
- package/src/integrations/microsoftSqlServer.ts +2 -0
- package/src/integrations/mongodb.ts +1 -0
- package/src/integrations/mysql.ts +2 -0
- package/src/integrations/oracle.ts +1 -0
- package/src/integrations/postgres.ts +2 -0
- package/src/integrations/queries/sql.ts +3 -1
- package/src/integrations/redis.ts +1 -0
- package/src/integrations/rest.ts +2 -1
- package/src/integrations/s3.ts +1 -0
- package/src/integrations/snowflake.ts +99 -0
- package/src/integrations/tests/rest.spec.js +16 -1
- package/src/migrations/tests/index.spec.ts +18 -2
- package/src/module.d.ts +2 -0
- package/src/tests/utilities/TestConfiguration.js +22 -3
- package/src/threads/automation.js +6 -3
- package/src/threads/index.ts +5 -1
- package/src/threads/query.js +88 -14
- package/src/utilities/fileSystem/index.js +22 -8
- package/src/utilities/index.js +1 -6
- package/src/utilities/workerRequests.js +16 -0
- package/builder/assets/index.1c640a53.js +0 -1316
- package/builder/assets/index.24307ca0.css +0 -6
|
@@ -10,6 +10,7 @@ const { getAppId } = require("@budibase/backend-core/context")
|
|
|
10
10
|
class QueryBuilder {
|
|
11
11
|
constructor(base) {
|
|
12
12
|
this.query = {
|
|
13
|
+
allOr: false,
|
|
13
14
|
string: {},
|
|
14
15
|
fuzzy: {},
|
|
15
16
|
range: {},
|
|
@@ -17,6 +18,7 @@ class QueryBuilder {
|
|
|
17
18
|
notEqual: {},
|
|
18
19
|
empty: {},
|
|
19
20
|
notEmpty: {},
|
|
21
|
+
oneOf: {},
|
|
20
22
|
...base,
|
|
21
23
|
}
|
|
22
24
|
this.limit = 50
|
|
@@ -112,6 +114,11 @@ class QueryBuilder {
|
|
|
112
114
|
return this
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
addOneOf(key, value) {
|
|
118
|
+
this.query.oneOf[key] = value
|
|
119
|
+
return this
|
|
120
|
+
}
|
|
121
|
+
|
|
115
122
|
/**
|
|
116
123
|
* Preprocesses a value before going into a lucene search.
|
|
117
124
|
* Transforms strings to lowercase and wraps strings and bools in quotes.
|
|
@@ -140,8 +147,22 @@ class QueryBuilder {
|
|
|
140
147
|
|
|
141
148
|
buildSearchQuery() {
|
|
142
149
|
const builder = this
|
|
143
|
-
let
|
|
150
|
+
let allOr = this.query && this.query.allOr
|
|
151
|
+
let query = allOr ? "" : "*:*"
|
|
144
152
|
const allPreProcessingOpts = { escape: true, lowercase: true, wrap: true }
|
|
153
|
+
let tableId
|
|
154
|
+
if (this.query.equal.tableId) {
|
|
155
|
+
tableId = this.query.equal.tableId
|
|
156
|
+
delete this.query.equal.tableId
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const equal = (key, value) => {
|
|
160
|
+
// 0 evaluates to false, which means we would return all rows if we don't check it
|
|
161
|
+
if (!value && value !== 0) {
|
|
162
|
+
return null
|
|
163
|
+
}
|
|
164
|
+
return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
|
165
|
+
}
|
|
145
166
|
|
|
146
167
|
function build(structure, queryFn) {
|
|
147
168
|
for (let [key, value] of Object.entries(structure)) {
|
|
@@ -152,7 +173,10 @@ class QueryBuilder {
|
|
|
152
173
|
if (expression == null) {
|
|
153
174
|
continue
|
|
154
175
|
}
|
|
155
|
-
query
|
|
176
|
+
if (query.length > 0) {
|
|
177
|
+
query += ` ${allOr ? "OR" : "AND"} `
|
|
178
|
+
}
|
|
179
|
+
query += expression
|
|
156
180
|
}
|
|
157
181
|
}
|
|
158
182
|
|
|
@@ -198,13 +222,7 @@ class QueryBuilder {
|
|
|
198
222
|
})
|
|
199
223
|
}
|
|
200
224
|
if (this.query.equal) {
|
|
201
|
-
build(this.query.equal,
|
|
202
|
-
// 0 evaluates to false, which means we would return all rows if we don't check it
|
|
203
|
-
if (!value && value !== 0) {
|
|
204
|
-
return null
|
|
205
|
-
}
|
|
206
|
-
return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
|
|
207
|
-
})
|
|
225
|
+
build(this.query.equal, equal)
|
|
208
226
|
}
|
|
209
227
|
if (this.query.notEqual) {
|
|
210
228
|
build(this.query.notEqual, (key, value) => {
|
|
@@ -220,6 +238,34 @@ class QueryBuilder {
|
|
|
220
238
|
if (this.query.notEmpty) {
|
|
221
239
|
build(this.query.notEmpty, key => `${key}:["" TO *]`)
|
|
222
240
|
}
|
|
241
|
+
if (this.query.oneOf) {
|
|
242
|
+
build(this.query.oneOf, (key, value) => {
|
|
243
|
+
if (!Array.isArray(value)) {
|
|
244
|
+
if (typeof value === "string") {
|
|
245
|
+
value = value.split(",")
|
|
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
|
+
})
|
|
262
|
+
}
|
|
263
|
+
// make sure table ID is always added as an AND
|
|
264
|
+
if (tableId) {
|
|
265
|
+
query = `(${query})`
|
|
266
|
+
allOr = false
|
|
267
|
+
build({ tableId }, equal)
|
|
268
|
+
}
|
|
223
269
|
return query
|
|
224
270
|
}
|
|
225
271
|
|
|
@@ -64,6 +64,9 @@ exports.validate = async ({ tableId, row, table }) => {
|
|
|
64
64
|
// Validate.js doesn't seem to handle array
|
|
65
65
|
if (type === FieldTypes.ARRAY && row[fieldName]) {
|
|
66
66
|
if (row[fieldName].length) {
|
|
67
|
+
if (!Array.isArray(row[fieldName])) {
|
|
68
|
+
row[fieldName] = row[fieldName].split(",")
|
|
69
|
+
}
|
|
67
70
|
row[fieldName].map(val => {
|
|
68
71
|
if (
|
|
69
72
|
!constraints.inclusion.includes(val) &&
|
|
@@ -73,12 +73,7 @@ exports.toggleBetaUiFeature = async function (ctx) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
exports.serveBuilder = async function (ctx) {
|
|
76
|
-
|
|
77
|
-
const designUiCookie = ctx.cookies.get("beta:design_ui")
|
|
78
|
-
// TODO: get this from the tmp Dir that we downloaded from MinIO
|
|
79
|
-
const uiPath = designUiCookie ? "new_design_ui" : "builder"
|
|
80
|
-
|
|
81
|
-
let builderPath = resolve(TOP_LEVEL_PATH, uiPath)
|
|
76
|
+
const builderPath = resolve(TOP_LEVEL_PATH, "builder")
|
|
82
77
|
await send(ctx, ctx.file, { root: builderPath })
|
|
83
78
|
if (!ctx.file.includes("assets/")) {
|
|
84
79
|
await events.serve.servedBuilder()
|
package/src/api/index.js
CHANGED
|
@@ -51,6 +51,16 @@ router
|
|
|
51
51
|
automationValidator(false),
|
|
52
52
|
controller.create
|
|
53
53
|
)
|
|
54
|
+
.post(
|
|
55
|
+
"/api/automations/logs/search",
|
|
56
|
+
authorized(BUILDER),
|
|
57
|
+
controller.logSearch
|
|
58
|
+
)
|
|
59
|
+
.delete(
|
|
60
|
+
"/api/automations/logs",
|
|
61
|
+
authorized(BUILDER),
|
|
62
|
+
controller.clearLogError
|
|
63
|
+
)
|
|
54
64
|
.delete(
|
|
55
65
|
"/api/automations/:id/:rev",
|
|
56
66
|
paramResource("id"),
|
package/src/api/routes/dev.js
CHANGED
|
@@ -22,6 +22,5 @@ router
|
|
|
22
22
|
.get("/api/dev/version", authorized(BUILDER), controller.getBudibaseVersion)
|
|
23
23
|
.delete("/api/dev/:appId/lock", authorized(BUILDER), controller.clearLock)
|
|
24
24
|
.post("/api/dev/:appId/revert", authorized(BUILDER), controller.revert)
|
|
25
|
-
.get("/api/beta/access", controller.checkBetaAccess)
|
|
26
25
|
|
|
27
26
|
module.exports = router
|
|
@@ -150,6 +150,11 @@ read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
|
|
|
150
150
|
* query:
|
|
151
151
|
* type: object
|
|
152
152
|
* properties:
|
|
153
|
+
* allOr:
|
|
154
|
+
* type: boolean
|
|
155
|
+
* description: Specifies that a row should be returned if it satisfies
|
|
156
|
+
* any of the specified options, rather than requiring it to fulfill all
|
|
157
|
+
* the search parameters. This defaults to false, meaning AND logic will be used.
|
|
153
158
|
* string:
|
|
154
159
|
* type: object
|
|
155
160
|
* example:
|
|
@@ -167,9 +172,9 @@ read.push(new Endpoint("get", "/tables/:tableId/rows/:rowId", controller.read))
|
|
|
167
172
|
* range:
|
|
168
173
|
* type: object
|
|
169
174
|
* description: Searches within a range, the format of this must be
|
|
170
|
-
*
|
|
175
|
+
* in the format of an object with a "low" and "high" property.
|
|
171
176
|
* example:
|
|
172
|
-
* columnName1:
|
|
177
|
+
* columnName1: { low: 10, high: 20 }
|
|
173
178
|
* equal:
|
|
174
179
|
* type: object
|
|
175
180
|
* description: Searches for rows that have a column value that is
|
|
@@ -218,7 +218,6 @@ describe("/queries", () => {
|
|
|
218
218
|
expect(res.body.schemaFields).toEqual(["a", "b"])
|
|
219
219
|
expect(res.body.rows.length).toEqual(1)
|
|
220
220
|
expect(events.query.previewed).toBeCalledTimes(1)
|
|
221
|
-
datasource.config = { schema: "public" }
|
|
222
221
|
expect(events.query.previewed).toBeCalledWith(datasource, query)
|
|
223
222
|
})
|
|
224
223
|
|
|
@@ -346,4 +345,170 @@ describe("/queries", () => {
|
|
|
346
345
|
expect(contents).toBe(null)
|
|
347
346
|
})
|
|
348
347
|
})
|
|
348
|
+
|
|
349
|
+
describe("Current User Request Mapping", () => {
|
|
350
|
+
|
|
351
|
+
async function previewGet(datasource, fields, params) {
|
|
352
|
+
return config.previewQuery(request, config, datasource, fields, params)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async function previewPost(datasource, fields, params) {
|
|
356
|
+
return config.previewQuery(request, config, datasource, fields, params, "create")
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
it("should parse global and query level header mappings", async () => {
|
|
360
|
+
const userDetails = config.getUserDetails()
|
|
361
|
+
|
|
362
|
+
const datasource = await config.restDatasource({
|
|
363
|
+
defaultHeaders: {
|
|
364
|
+
"test": "headerVal",
|
|
365
|
+
"emailHdr": "{{[user].[email]}}"
|
|
366
|
+
}
|
|
367
|
+
})
|
|
368
|
+
const res = await previewGet(datasource, {
|
|
369
|
+
path: "www.google.com",
|
|
370
|
+
queryString: "email={{[user].[email]}}",
|
|
371
|
+
headers: {
|
|
372
|
+
queryHdr : "{{[user].[firstName]}}",
|
|
373
|
+
secondHdr : "1234"
|
|
374
|
+
}
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
378
|
+
expect(parsedRequest.opts.headers).toEqual({
|
|
379
|
+
"test": "headerVal",
|
|
380
|
+
"emailHdr": userDetails.email,
|
|
381
|
+
"queryHdr": userDetails.firstName,
|
|
382
|
+
"secondHdr" : "1234"
|
|
383
|
+
})
|
|
384
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?email=" + userDetails.email)
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
it("should bind the current user to query parameters", async () => {
|
|
388
|
+
const userDetails = config.getUserDetails()
|
|
389
|
+
|
|
390
|
+
const datasource = await config.restDatasource()
|
|
391
|
+
|
|
392
|
+
const res = await previewGet(datasource, {
|
|
393
|
+
path: "www.google.com",
|
|
394
|
+
queryString: "test={{myEmail}}&testName={{myName}}&testParam={{testParam}}",
|
|
395
|
+
}, {
|
|
396
|
+
"myEmail" : "{{[user].[email]}}",
|
|
397
|
+
"myName" : "{{[user].[firstName]}}",
|
|
398
|
+
"testParam" : "1234"
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?test=" + userDetails.email +
|
|
402
|
+
"&testName=" + userDetails.firstName + "&testParam=1234")
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
it("should bind the current user the request body - plain text", async () => {
|
|
406
|
+
const userDetails = config.getUserDetails()
|
|
407
|
+
const datasource = await config.restDatasource()
|
|
408
|
+
|
|
409
|
+
const res = await previewPost(datasource, {
|
|
410
|
+
path: "www.google.com",
|
|
411
|
+
queryString: "testParam={{testParam}}",
|
|
412
|
+
requestBody: "This is plain text and this is my email: {{[user].[email]}}. This is a test param: {{testParam}}",
|
|
413
|
+
bodyType: "text"
|
|
414
|
+
}, {
|
|
415
|
+
"testParam" : "1234"
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
419
|
+
expect(parsedRequest.opts.body).toEqual(`This is plain text and this is my email: ${userDetails.email}. This is a test param: 1234`)
|
|
420
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
it("should bind the current user the request body - json", async () => {
|
|
424
|
+
const userDetails = config.getUserDetails()
|
|
425
|
+
const datasource = await config.restDatasource()
|
|
426
|
+
|
|
427
|
+
const res = await previewPost(datasource, {
|
|
428
|
+
path: "www.google.com",
|
|
429
|
+
queryString: "testParam={{testParam}}",
|
|
430
|
+
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
|
431
|
+
bodyType: "json"
|
|
432
|
+
}, {
|
|
433
|
+
"testParam" : "1234",
|
|
434
|
+
"userRef" : "{{[user].[firstName]}}"
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
438
|
+
const test = `{"email":"${userDetails.email}","queryCode":1234,"userRef":"${userDetails.firstName}"}`
|
|
439
|
+
expect(parsedRequest.opts.body).toEqual(test)
|
|
440
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
it("should bind the current user the request body - xml", async () => {
|
|
444
|
+
const userDetails = config.getUserDetails()
|
|
445
|
+
const datasource = await config.restDatasource()
|
|
446
|
+
|
|
447
|
+
const res = await previewPost(datasource, {
|
|
448
|
+
path: "www.google.com",
|
|
449
|
+
queryString: "testParam={{testParam}}",
|
|
450
|
+
requestBody: "<note> <email>{{[user].[email]}}</email> <code>{{testParam}}</code> " +
|
|
451
|
+
"<ref>{{userId}}</ref> <somestring>testing</somestring> </note>",
|
|
452
|
+
bodyType: "xml"
|
|
453
|
+
}, {
|
|
454
|
+
"testParam" : "1234",
|
|
455
|
+
"userId" : "{{[user].[firstName]}}"
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
459
|
+
const test = `<note> <email>${userDetails.email}</email> <code>1234</code> <ref>${userDetails.firstName}</ref> <somestring>testing</somestring> </note>`
|
|
460
|
+
|
|
461
|
+
expect(parsedRequest.opts.body).toEqual(test)
|
|
462
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
|
463
|
+
})
|
|
464
|
+
|
|
465
|
+
it("should bind the current user the request body - form-data", async () => {
|
|
466
|
+
const userDetails = config.getUserDetails()
|
|
467
|
+
const datasource = await config.restDatasource()
|
|
468
|
+
|
|
469
|
+
const res = await previewPost(datasource, {
|
|
470
|
+
path: "www.google.com",
|
|
471
|
+
queryString: "testParam={{testParam}}",
|
|
472
|
+
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
|
473
|
+
bodyType: "form"
|
|
474
|
+
}, {
|
|
475
|
+
"testParam" : "1234",
|
|
476
|
+
"userRef" : "{{[user].[firstName]}}"
|
|
477
|
+
})
|
|
478
|
+
|
|
479
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
480
|
+
|
|
481
|
+
const emailData = parsedRequest.opts.body._streams[1]
|
|
482
|
+
expect(emailData).toEqual(userDetails.email)
|
|
483
|
+
|
|
484
|
+
const queryCodeData = parsedRequest.opts.body._streams[4]
|
|
485
|
+
expect(queryCodeData).toEqual("1234")
|
|
486
|
+
|
|
487
|
+
const userRef = parsedRequest.opts.body._streams[7]
|
|
488
|
+
expect(userRef).toEqual(userDetails.firstName)
|
|
489
|
+
|
|
490
|
+
expect(res.body.rows[0].url).toEqual("http://www.google.com?testParam=1234")
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
it("should bind the current user the request body - encoded", async () => {
|
|
494
|
+
const userDetails = config.getUserDetails()
|
|
495
|
+
const datasource = await config.restDatasource()
|
|
496
|
+
|
|
497
|
+
const res = await previewPost(datasource, {
|
|
498
|
+
path: "www.google.com",
|
|
499
|
+
queryString: "testParam={{testParam}}",
|
|
500
|
+
requestBody: "{\"email\":\"{{[user].[email]}}\",\"queryCode\":{{testParam}},\"userRef\":\"{{userRef}}\"}",
|
|
501
|
+
bodyType: "encoded"
|
|
502
|
+
}, {
|
|
503
|
+
"testParam" : "1234",
|
|
504
|
+
"userRef" : "{{[user].[firstName]}}"
|
|
505
|
+
})
|
|
506
|
+
const parsedRequest = JSON.parse(res.body.extra.raw)
|
|
507
|
+
|
|
508
|
+
expect(parsedRequest.opts.body.email).toEqual(userDetails.email)
|
|
509
|
+
expect(parsedRequest.opts.body.queryCode).toEqual("1234")
|
|
510
|
+
expect(parsedRequest.opts.body.userRef).toEqual(userDetails.firstName)
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
});
|
|
349
514
|
})
|
package/src/app.ts
CHANGED
|
@@ -18,7 +18,9 @@ const { logAlert } = require("@budibase/backend-core/logging")
|
|
|
18
18
|
const { Thread } = require("./threads")
|
|
19
19
|
import redis from "./utilities/redis"
|
|
20
20
|
import * as migrations from "./migrations"
|
|
21
|
-
import { events, installation } from "@budibase/backend-core"
|
|
21
|
+
import { events, installation, tenancy } from "@budibase/backend-core"
|
|
22
|
+
import { createAdminUser, getChecklist } from "./utilities/workerRequests"
|
|
23
|
+
import { tenantSucceeded } from "@budibase/backend-core/dist/src/events/publishers/backfill"
|
|
22
24
|
|
|
23
25
|
const app = new Koa()
|
|
24
26
|
|
|
@@ -110,6 +112,33 @@ module.exports = server.listen(env.PORT || 0, async () => {
|
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
// check and create admin user if required
|
|
116
|
+
if (
|
|
117
|
+
env.SELF_HOSTED &&
|
|
118
|
+
!env.MULTI_TENANCY &&
|
|
119
|
+
env.BB_ADMIN_USER_EMAIL &&
|
|
120
|
+
env.BB_ADMIN_USER_PASSWORD
|
|
121
|
+
) {
|
|
122
|
+
const checklist = await getChecklist()
|
|
123
|
+
if (!checklist?.adminUser?.checked) {
|
|
124
|
+
try {
|
|
125
|
+
const tenantId = tenancy.getTenantId()
|
|
126
|
+
await createAdminUser(
|
|
127
|
+
env.BB_ADMIN_USER_EMAIL,
|
|
128
|
+
env.BB_ADMIN_USER_PASSWORD,
|
|
129
|
+
tenantId
|
|
130
|
+
)
|
|
131
|
+
console.log(
|
|
132
|
+
"Admin account automatically created for",
|
|
133
|
+
env.BB_ADMIN_USER_EMAIL
|
|
134
|
+
)
|
|
135
|
+
} catch (e) {
|
|
136
|
+
logAlert("Error creating initial admin user. Exiting.", e)
|
|
137
|
+
shutdown()
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
113
142
|
// check for version updates
|
|
114
143
|
await installation.checkInstallVersion()
|
|
115
144
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
const { getTable } = require("../api/controllers/table/utils")
|
|
2
|
-
const {
|
|
2
|
+
const {
|
|
3
|
+
findHBSBlocks,
|
|
4
|
+
decodeJSBinding,
|
|
5
|
+
isJSBinding,
|
|
6
|
+
encodeJSBinding,
|
|
7
|
+
} = require("@budibase/string-templates")
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* When values are input to the system generally they will be of type string as this is required for template strings.
|
|
@@ -77,11 +82,21 @@ exports.getError = err => {
|
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
exports.substituteLoopStep = (hbsString, substitute) => {
|
|
80
|
-
let blocks =
|
|
85
|
+
let blocks = []
|
|
86
|
+
let checkForJS = isJSBinding(hbsString)
|
|
87
|
+
if (checkForJS) {
|
|
88
|
+
hbsString = decodeJSBinding(hbsString)
|
|
89
|
+
blocks.push(hbsString)
|
|
90
|
+
} else {
|
|
91
|
+
blocks = findHBSBlocks(hbsString)
|
|
92
|
+
}
|
|
81
93
|
for (let block of blocks) {
|
|
82
|
-
let oldBlock = block
|
|
83
94
|
block = block.replace(/loop/, substitute)
|
|
84
|
-
|
|
95
|
+
if (checkForJS) {
|
|
96
|
+
hbsString = encodeJSBinding(block)
|
|
97
|
+
} else {
|
|
98
|
+
hbsString = block
|
|
99
|
+
}
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
return hbsString
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as env from "../../environment"
|
|
2
|
+
import { AutomationResults, Automation, App } from "@budibase/types"
|
|
3
|
+
import { automations } from "@budibase/pro"
|
|
4
|
+
import { db as dbUtils } from "@budibase/backend-core"
|
|
5
|
+
|
|
6
|
+
export async function storeLog(
|
|
7
|
+
automation: Automation,
|
|
8
|
+
results: AutomationResults
|
|
9
|
+
) {
|
|
10
|
+
// can disable this if un-needed in self-host, also only do this for prod apps
|
|
11
|
+
if (env.DISABLE_AUTOMATION_LOGS) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
await automations.logs.storeLog(automation, results)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function checkAppMetadata(apps: App[]) {
|
|
18
|
+
const maxStartDate = await automations.logs.oldestLogDate()
|
|
19
|
+
for (let metadata of apps) {
|
|
20
|
+
if (!metadata.automationErrors) {
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
for (let [key, errors] of Object.entries(metadata.automationErrors)) {
|
|
24
|
+
const updated = []
|
|
25
|
+
for (let error of errors) {
|
|
26
|
+
const startDate = error.split(dbUtils.SEPARATOR)[2]
|
|
27
|
+
if (startDate > maxStartDate) {
|
|
28
|
+
updated.push(error)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
metadata.automationErrors[key] = updated
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return apps
|
|
35
|
+
}
|
|
@@ -50,43 +50,51 @@ exports.definition = {
|
|
|
50
50
|
outputs: {
|
|
51
51
|
properties: {
|
|
52
52
|
success: {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
description: "Whether the action was successful",
|
|
55
|
+
},
|
|
56
|
+
result: {
|
|
53
57
|
type: "boolean",
|
|
54
58
|
description: "Whether the logic block passed",
|
|
55
59
|
},
|
|
56
60
|
},
|
|
57
|
-
required: ["success"],
|
|
61
|
+
required: ["success", "result"],
|
|
58
62
|
},
|
|
59
63
|
},
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
exports.run = async function filter({ inputs }) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
value
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
67
|
+
try {
|
|
68
|
+
let { field, condition, value } = inputs
|
|
69
|
+
// coerce types so that we can use them
|
|
70
|
+
if (!isNaN(value) && !isNaN(field)) {
|
|
71
|
+
value = parseFloat(value)
|
|
72
|
+
field = parseFloat(field)
|
|
73
|
+
} else if (!isNaN(Date.parse(value)) && !isNaN(Date.parse(field))) {
|
|
74
|
+
value = Date.parse(value)
|
|
75
|
+
field = Date.parse(field)
|
|
76
|
+
}
|
|
77
|
+
let result = false
|
|
78
|
+
if (typeof field !== "object" && typeof value !== "object") {
|
|
79
|
+
switch (condition) {
|
|
80
|
+
case FilterConditions.EQUAL:
|
|
81
|
+
result = field === value
|
|
82
|
+
break
|
|
83
|
+
case FilterConditions.NOT_EQUAL:
|
|
84
|
+
result = field !== value
|
|
85
|
+
break
|
|
86
|
+
case FilterConditions.GREATER_THAN:
|
|
87
|
+
result = field > value
|
|
88
|
+
break
|
|
89
|
+
case FilterConditions.LESS_THAN:
|
|
90
|
+
result = field < value
|
|
91
|
+
break
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
result = false
|
|
87
95
|
}
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
return { success: true, result }
|
|
97
|
+
} catch (err) {
|
|
98
|
+
return { success: false, result: false }
|
|
90
99
|
}
|
|
91
|
-
return { success }
|
|
92
100
|
}
|
|
@@ -6,7 +6,8 @@ describe("test the filter logic", () => {
|
|
|
6
6
|
let res = await setup.runStep(setup.actions.FILTER.stepId,
|
|
7
7
|
{ field, condition, value }
|
|
8
8
|
)
|
|
9
|
-
expect(res.
|
|
9
|
+
expect(res.result).toEqual(pass)
|
|
10
|
+
expect(res.success).toEqual(true)
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
it("should be able test equality", async () => {
|
|
@@ -97,7 +97,7 @@ exports.externalTrigger = async function (
|
|
|
97
97
|
// values are likely to be submitted as strings, so we shall convert to correct type
|
|
98
98
|
const coercedFields = {}
|
|
99
99
|
const fields = automation.definition.trigger.inputs.fields
|
|
100
|
-
for (let key of Object.keys(fields)) {
|
|
100
|
+
for (let key of Object.keys(fields || {})) {
|
|
101
101
|
coercedFields[key] = coerce(params.fields[key], fields[key])
|
|
102
102
|
}
|
|
103
103
|
params.fields = coercedFields
|
|
@@ -65,6 +65,7 @@ async function getLinksForRows(rows) {
|
|
|
65
65
|
// return duplicates, could be querying for both tables in a relation
|
|
66
66
|
return getUniqueByProp(
|
|
67
67
|
responses
|
|
68
|
+
.filter(el => el != null)
|
|
68
69
|
// create a unique ID which we can use for getting only unique ones
|
|
69
70
|
.map(el => ({ ...el, unique: el.id + el.thisId + el.fieldName })),
|
|
70
71
|
"unique"
|