@budibase/server 1.0.98 → 1.0.101
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.cca3db8c.js +1291 -0
- package/builder/assets/{index.7c8961b4.css → index.ea3718aa.css} +2 -2
- package/builder/assets/{vendor.a7c6ad0a.js → vendor.8e34a169.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +354 -334
- package/coverage/coverage-final.json +15 -15
- 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 +4 -4
- 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 +18 -18
- package/coverage/lcov-report/api/controllers/integration.js.html +59 -11
- 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 +7 -7
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +2 -2
- 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 +10 -10
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +19 -7
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +6 -6
- 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/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +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 +3 -3
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- 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/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/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 +2 -2
- 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 +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 +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +12 -12
- 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/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 +20 -8
- 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/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 +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +10 -10
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
- package/coverage/lcov-report/db/newid.js.html +2 -2
- package/coverage/lcov-report/db/utils.js.html +2 -2
- 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 +31 -31
- 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 +75 -15
- 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 +15 -15
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- 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/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +1 -1
- package/coverage/lcov-report/threads/index.js.html +1 -1
- package/coverage/lcov-report/threads/query.js.html +1 -1
- package/coverage/lcov-report/threads/utils.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 +1 -1
- package/coverage/lcov-report/utilities/index.html +1 -1
- 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 +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +12 -12
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +8 -8
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- 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/usageQuota/index.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.js.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 +584 -546
- package/dist/api/controllers/integration.js +15 -1
- package/dist/api/controllers/permission.js +3 -4
- package/dist/api/controllers/query/import/index.js +2 -1
- package/dist/api/controllers/query/import/sources/base/index.js +12 -1
- package/dist/api/controllers/query/import/sources/curl.js +2 -2
- package/dist/api/controllers/query/import/sources/openapi3.js +174 -0
- package/dist/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
- package/dist/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
- package/dist/api/controllers/row/internal.js +2 -1
- package/dist/api/routes/analytics.js +2 -2
- package/dist/api/routes/table.js +1 -1
- package/dist/automations/utils.js +3 -1
- package/dist/definitions/datasource.js +1 -0
- package/dist/environment.js +2 -0
- package/dist/integrations/base/sql.js +16 -9
- package/dist/integrations/dynamodb.js +3 -1
- package/dist/integrations/firebase.js +192 -0
- package/dist/integrations/googlesheets.js +17 -1
- package/dist/integrations/index.js +4 -1
- package/dist/integrations/mysql.js +14 -1
- package/dist/integrations/rest.js +2 -1
- package/dist/middleware/authorized.js +24 -7
- package/dist/package.json +7 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -5
- package/scripts/dev/manage.js +2 -1
- package/specs/openapi.json +23 -3
- package/specs/openapi.yaml +20 -4
- package/specs/resources/query.js +27 -5
- package/src/api/controllers/integration.js +17 -1
- package/src/api/controllers/permission.js +3 -3
- package/src/api/controllers/query/import/index.ts +2 -1
- package/src/api/controllers/query/import/sources/base/index.ts +12 -2
- package/src/api/controllers/query/import/sources/curl.ts +2 -2
- package/src/api/controllers/query/import/sources/openapi3.ts +205 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml +153 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.yaml +804 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js +240 -0
- package/src/api/controllers/query/import/tests/index.spec.js +43 -0
- package/src/api/controllers/row/internal.js +5 -1
- package/src/api/routes/analytics.js +2 -2
- package/src/api/routes/table.js +1 -1
- package/src/api/routes/tests/misc.spec.js +2 -2
- package/src/automations/utils.js +5 -1
- package/src/definitions/datasource.ts +2 -5
- package/src/definitions/openapi.ts +480 -470
- package/src/environment.js +2 -0
- package/src/integrations/base/sql.ts +14 -9
- package/src/integrations/dynamodb.ts +3 -1
- package/src/integrations/firebase.ts +205 -0
- package/src/integrations/googlesheets.ts +16 -1
- package/src/integrations/index.ts +4 -1
- package/src/integrations/mysql.ts +15 -1
- package/src/integrations/rest.ts +2 -1
- package/src/integrations/tests/sql.spec.js +51 -0
- package/src/middleware/authorized.js +26 -6
- package/builder/assets/index.2dcb5072.js +0 -1291
package/src/environment.js
CHANGED
|
@@ -46,6 +46,8 @@ module.exports = {
|
|
|
46
46
|
MULTI_TENANCY: process.env.MULTI_TENANCY,
|
|
47
47
|
HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
|
|
48
48
|
API_REQ_LIMIT_PER_SEC: process.env.API_REQ_LIMIT_PER_SEC,
|
|
49
|
+
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
|
|
50
|
+
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
|
|
49
51
|
// environment
|
|
50
52
|
NODE_ENV: process.env.NODE_ENV,
|
|
51
53
|
JEST_WORKER_ID: process.env.JEST_WORKER_ID,
|
|
@@ -31,11 +31,8 @@ function parse(input: any) {
|
|
|
31
31
|
if (typeof input !== "string") {
|
|
32
32
|
return input
|
|
33
33
|
}
|
|
34
|
-
if (input === MAX_ISO_DATE) {
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
if (input === MIN_ISO_DATE) {
|
|
38
|
-
return new Date(-8640000000000000)
|
|
34
|
+
if (input === MAX_ISO_DATE || input === MIN_ISO_DATE) {
|
|
35
|
+
return null
|
|
39
36
|
}
|
|
40
37
|
if (isIsoDateString(input)) {
|
|
41
38
|
return new Date(input)
|
|
@@ -134,11 +131,19 @@ class InternalBuilder {
|
|
|
134
131
|
}
|
|
135
132
|
if (filters.range) {
|
|
136
133
|
iterate(filters.range, (key, value) => {
|
|
137
|
-
if (
|
|
138
|
-
|
|
134
|
+
if (value.low && value.high) {
|
|
135
|
+
// Use a between operator if we have 2 valid range values
|
|
136
|
+
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
|
137
|
+
query = query[fnc](key, [value.low, value.high])
|
|
138
|
+
} else if (value.low) {
|
|
139
|
+
// Use just a single greater than operator if we only have a low
|
|
140
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
141
|
+
query = query[fnc](key, ">", value.low)
|
|
142
|
+
} else if (value.high) {
|
|
143
|
+
// Use just a single less than operator if we only have a high
|
|
144
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
145
|
+
query = query[fnc](key, "<", value.high)
|
|
139
146
|
}
|
|
140
|
-
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
|
141
|
-
query = query[fnc](key, [value.low, value.high])
|
|
142
147
|
})
|
|
143
148
|
}
|
|
144
149
|
if (filters.equal) {
|
|
@@ -131,7 +131,9 @@ module DynamoModule {
|
|
|
131
131
|
|
|
132
132
|
constructor(config: DynamoDBConfig) {
|
|
133
133
|
this.config = config
|
|
134
|
-
this.
|
|
134
|
+
if (!this.config.endpoint) {
|
|
135
|
+
this.connect()
|
|
136
|
+
}
|
|
135
137
|
let options = {
|
|
136
138
|
correctClockSkew: true,
|
|
137
139
|
endpoint: config.endpoint ? config.endpoint : undefined,
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DatasourceFieldTypes,
|
|
3
|
+
Integration,
|
|
4
|
+
QueryTypes,
|
|
5
|
+
} from "../definitions/datasource"
|
|
6
|
+
import { IntegrationBase } from "./base/IntegrationBase"
|
|
7
|
+
import { Firestore, WhereFilterOp } from "@google-cloud/firestore"
|
|
8
|
+
|
|
9
|
+
module Firebase {
|
|
10
|
+
interface FirebaseConfig {
|
|
11
|
+
email: string
|
|
12
|
+
privateKey: string
|
|
13
|
+
projectId: string
|
|
14
|
+
serviceAccount?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SCHEMA: Integration = {
|
|
18
|
+
docs: "https://firebase.google.com/docs/firestore/quickstart",
|
|
19
|
+
friendlyName: "Firestore",
|
|
20
|
+
description:
|
|
21
|
+
"Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
|
|
22
|
+
datasource: {
|
|
23
|
+
email: {
|
|
24
|
+
type: DatasourceFieldTypes.STRING,
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
privateKey: {
|
|
28
|
+
type: DatasourceFieldTypes.STRING,
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
projectId: {
|
|
32
|
+
type: DatasourceFieldTypes.STRING,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
serviceAccount: {
|
|
36
|
+
type: DatasourceFieldTypes.JSON,
|
|
37
|
+
required: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
query: {
|
|
41
|
+
create: {
|
|
42
|
+
type: QueryTypes.JSON,
|
|
43
|
+
},
|
|
44
|
+
read: {
|
|
45
|
+
type: QueryTypes.JSON,
|
|
46
|
+
},
|
|
47
|
+
update: {
|
|
48
|
+
type: QueryTypes.JSON,
|
|
49
|
+
},
|
|
50
|
+
delete: {
|
|
51
|
+
type: QueryTypes.JSON,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
extra: {
|
|
55
|
+
collection: {
|
|
56
|
+
displayName: "Collection",
|
|
57
|
+
type: DatasourceFieldTypes.STRING,
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
filterField: {
|
|
61
|
+
displayName: "Filter field",
|
|
62
|
+
type: DatasourceFieldTypes.STRING,
|
|
63
|
+
required: false,
|
|
64
|
+
},
|
|
65
|
+
filter: {
|
|
66
|
+
displayName: "Filter comparison",
|
|
67
|
+
type: DatasourceFieldTypes.LIST,
|
|
68
|
+
required: false,
|
|
69
|
+
data: {
|
|
70
|
+
read: [
|
|
71
|
+
"==",
|
|
72
|
+
"<",
|
|
73
|
+
"<=",
|
|
74
|
+
"==",
|
|
75
|
+
"!=",
|
|
76
|
+
">=",
|
|
77
|
+
">",
|
|
78
|
+
"array-contains",
|
|
79
|
+
"in",
|
|
80
|
+
"not-in",
|
|
81
|
+
"array-contains-any",
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
filterValue: {
|
|
86
|
+
displayName: "Filter value",
|
|
87
|
+
type: DatasourceFieldTypes.STRING,
|
|
88
|
+
required: false,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class FirebaseIntegration implements IntegrationBase {
|
|
94
|
+
private config: FirebaseConfig
|
|
95
|
+
private db: Firestore
|
|
96
|
+
|
|
97
|
+
constructor(config: FirebaseConfig) {
|
|
98
|
+
this.config = config
|
|
99
|
+
if (config.serviceAccount) {
|
|
100
|
+
const serviceAccount = JSON.parse(config.serviceAccount)
|
|
101
|
+
this.db = new Firestore({
|
|
102
|
+
projectId: serviceAccount.project_id,
|
|
103
|
+
credentials: {
|
|
104
|
+
client_email: serviceAccount.client_email,
|
|
105
|
+
private_key: serviceAccount.private_key,
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
} else {
|
|
109
|
+
this.db = new Firestore({
|
|
110
|
+
projectId: config.projectId,
|
|
111
|
+
credentials: {
|
|
112
|
+
client_email: config.email,
|
|
113
|
+
private_key: config.privateKey,
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async create(query: { json: object; extra: { [key: string]: string } }) {
|
|
120
|
+
try {
|
|
121
|
+
const documentReference = this.db
|
|
122
|
+
.collection(query.extra.collection)
|
|
123
|
+
.doc()
|
|
124
|
+
await documentReference.set({ ...query.json, id: documentReference.id })
|
|
125
|
+
const snapshot = await documentReference.get()
|
|
126
|
+
return snapshot.data()
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error("Error writing to Firestore", err)
|
|
129
|
+
throw err
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async read(query: { json: object; extra: { [key: string]: string } }) {
|
|
134
|
+
try {
|
|
135
|
+
let snapshot
|
|
136
|
+
const collectionRef = this.db.collection(query.extra.collection)
|
|
137
|
+
if (
|
|
138
|
+
query.extra.filterField &&
|
|
139
|
+
query.extra.filter &&
|
|
140
|
+
query.extra.filterValue
|
|
141
|
+
) {
|
|
142
|
+
snapshot = await collectionRef
|
|
143
|
+
.where(
|
|
144
|
+
query.extra.filterField,
|
|
145
|
+
query.extra.filter as WhereFilterOp,
|
|
146
|
+
query.extra.filterValue
|
|
147
|
+
)
|
|
148
|
+
.get()
|
|
149
|
+
} else {
|
|
150
|
+
snapshot = await collectionRef.get()
|
|
151
|
+
}
|
|
152
|
+
const result: any[] = []
|
|
153
|
+
snapshot.forEach(doc => result.push(doc.data()))
|
|
154
|
+
|
|
155
|
+
return result
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error("Error querying Firestore", err)
|
|
158
|
+
throw err
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async update(query: {
|
|
163
|
+
json: Record<string, any>
|
|
164
|
+
extra: { [key: string]: string }
|
|
165
|
+
}) {
|
|
166
|
+
try {
|
|
167
|
+
await this.db
|
|
168
|
+
.collection(query.extra.collection)
|
|
169
|
+
.doc(query.json.id)
|
|
170
|
+
.update(query.json)
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
await this.db
|
|
174
|
+
.collection(query.extra.collection)
|
|
175
|
+
.doc(query.json.id)
|
|
176
|
+
.get()
|
|
177
|
+
).data()
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.error("Error writing to firebase", err)
|
|
180
|
+
throw err
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async delete(query: {
|
|
185
|
+
json: { id: string }
|
|
186
|
+
extra: { [key: string]: string }
|
|
187
|
+
}) {
|
|
188
|
+
try {
|
|
189
|
+
await this.db
|
|
190
|
+
.collection(query.extra.collection)
|
|
191
|
+
.doc(query.json.id)
|
|
192
|
+
.delete()
|
|
193
|
+
return true
|
|
194
|
+
} catch (err) {
|
|
195
|
+
console.error("Error writing to mongodb", err)
|
|
196
|
+
throw err
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = {
|
|
202
|
+
schema: SCHEMA,
|
|
203
|
+
integration: FirebaseIntegration,
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -10,6 +10,7 @@ import { Table, TableSchema } from "../definitions/common"
|
|
|
10
10
|
import { buildExternalTableId } from "./utils"
|
|
11
11
|
import { DataSourceOperation, FieldTypes } from "../constants"
|
|
12
12
|
import { GoogleSpreadsheet } from "google-spreadsheet"
|
|
13
|
+
import env from "../environment"
|
|
13
14
|
|
|
14
15
|
module GoogleSheetsModule {
|
|
15
16
|
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
|
|
@@ -138,13 +139,27 @@ module GoogleSheetsModule {
|
|
|
138
139
|
try {
|
|
139
140
|
// Initialise oAuth client
|
|
140
141
|
const db = getGlobalDB()
|
|
141
|
-
|
|
142
|
+
let googleConfig = await getScopedConfig(db, {
|
|
142
143
|
type: Configs.GOOGLE,
|
|
143
144
|
})
|
|
145
|
+
|
|
146
|
+
if (!googleConfig) {
|
|
147
|
+
googleConfig = {
|
|
148
|
+
clientID: env.GOOGLE_CLIENT_ID,
|
|
149
|
+
clientSecret: env.GOOGLE_CLIENT_SECRET,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
144
153
|
const oauthClient = new OAuth2Client({
|
|
145
154
|
clientId: googleConfig.clientID,
|
|
146
155
|
clientSecret: googleConfig.clientSecret,
|
|
147
156
|
})
|
|
157
|
+
oauthClient.on("tokens", tokens => {
|
|
158
|
+
oauthClient.setCredentials({
|
|
159
|
+
refresh_token: googleConfig.refreshToken,
|
|
160
|
+
access_token: tokens.access_token,
|
|
161
|
+
})
|
|
162
|
+
})
|
|
148
163
|
oauthClient.credentials.access_token = this.config.auth.accessToken
|
|
149
164
|
oauthClient.credentials.refresh_token = this.config.auth.refreshToken
|
|
150
165
|
this.client.useOAuth2Client(oauthClient)
|
|
@@ -10,6 +10,7 @@ const mysql = require("./mysql")
|
|
|
10
10
|
const arangodb = require("./arangodb")
|
|
11
11
|
const rest = require("./rest")
|
|
12
12
|
const googlesheets = require("./googlesheets")
|
|
13
|
+
const firebase = require("./firebase")
|
|
13
14
|
const { SourceNames } = require("../definitions/datasource")
|
|
14
15
|
const environment = require("../environment")
|
|
15
16
|
|
|
@@ -25,6 +26,7 @@ const DEFINITIONS = {
|
|
|
25
26
|
[SourceNames.MYSQL]: mysql.schema,
|
|
26
27
|
[SourceNames.ARANGODB]: arangodb.schema,
|
|
27
28
|
[SourceNames.REST]: rest.schema,
|
|
29
|
+
[SourceNames.FIREBASE]: firebase.schema,
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
const INTEGRATIONS = {
|
|
@@ -39,6 +41,8 @@ const INTEGRATIONS = {
|
|
|
39
41
|
[SourceNames.MYSQL]: mysql.integration,
|
|
40
42
|
[SourceNames.ARANGODB]: arangodb.integration,
|
|
41
43
|
[SourceNames.REST]: rest.integration,
|
|
44
|
+
[SourceNames.FIREBASE]: firebase.integration,
|
|
45
|
+
[SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
// optionally add oracle integration if the oracle binary can be installed
|
|
@@ -50,7 +54,6 @@ if (!(process.arch === "arm64" && process.platform === "darwin")) {
|
|
|
50
54
|
|
|
51
55
|
if (environment.SELF_HOSTED) {
|
|
52
56
|
DEFINITIONS[SourceNames.GOOGLE_SHEETS] = googlesheets.schema
|
|
53
|
-
INTEGRATIONS[SourceNames.GOOGLE_SHEETS] = googlesheets.integration
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
module.exports = {
|
|
@@ -80,6 +80,20 @@ module MySQLModule {
|
|
|
80
80
|
},
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function bindingTypeCoerce(bindings: any[]) {
|
|
84
|
+
for (let i = 0; i < bindings.length; i++) {
|
|
85
|
+
const binding = bindings[i]
|
|
86
|
+
if (typeof binding !== "string") {
|
|
87
|
+
continue
|
|
88
|
+
}
|
|
89
|
+
const matches = binding.match(/^\d*/g)
|
|
90
|
+
if (matches && matches[0] !== "" && !isNaN(Number(matches[0]))) {
|
|
91
|
+
bindings[i] = parseFloat(binding)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return bindings
|
|
95
|
+
}
|
|
96
|
+
|
|
83
97
|
class MySQLIntegration extends Sql implements DatasourcePlus {
|
|
84
98
|
private config: MySQLConfig
|
|
85
99
|
private client: any
|
|
@@ -122,7 +136,7 @@ module MySQLModule {
|
|
|
122
136
|
// Node MySQL is callback based, so we must wrap our call in a promise
|
|
123
137
|
const response = await this.client.query(
|
|
124
138
|
query.sql,
|
|
125
|
-
query.bindings || []
|
|
139
|
+
bindingTypeCoerce(query.bindings || [])
|
|
126
140
|
)
|
|
127
141
|
return response[0]
|
|
128
142
|
} finally {
|
package/src/integrations/rest.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
PaginationValues,
|
|
12
12
|
} from "../definitions/datasource"
|
|
13
13
|
import { IntegrationBase } from "./base/IntegrationBase"
|
|
14
|
+
import { get } from "lodash"
|
|
14
15
|
|
|
15
16
|
const BodyTypes = {
|
|
16
17
|
NONE: "none",
|
|
@@ -163,7 +164,7 @@ module RestModule {
|
|
|
163
164
|
// Check if a pagination cursor exists in the response
|
|
164
165
|
let nextCursor = null
|
|
165
166
|
if (pagination?.responseParam) {
|
|
166
|
-
nextCursor = data
|
|
167
|
+
nextCursor = get(data, pagination.responseParam)
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
return {
|
|
@@ -187,4 +187,55 @@ describe("SQL query builder", () => {
|
|
|
187
187
|
sql: `select * from (select * from \`${TABLE_NAME}\` limit ?) as \`${TABLE_NAME}\``
|
|
188
188
|
})
|
|
189
189
|
})
|
|
190
|
+
|
|
191
|
+
it("should use greater than when only low range specified", () => {
|
|
192
|
+
const date = new Date()
|
|
193
|
+
const query = sql._query(generateReadJson({
|
|
194
|
+
filters: {
|
|
195
|
+
range: {
|
|
196
|
+
property: {
|
|
197
|
+
low: date,
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}))
|
|
202
|
+
expect(query).toEqual({
|
|
203
|
+
bindings: [date, limit],
|
|
204
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"`
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it("should use less than when only high range specified", () => {
|
|
209
|
+
const date = new Date()
|
|
210
|
+
const query = sql._query(generateReadJson({
|
|
211
|
+
filters: {
|
|
212
|
+
range: {
|
|
213
|
+
property: {
|
|
214
|
+
high: date,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}))
|
|
219
|
+
expect(query).toEqual({
|
|
220
|
+
bindings: [date, limit],
|
|
221
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" < $1 limit $2) as "${TABLE_NAME}"`
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it("should use greater than when only low range specified", () => {
|
|
226
|
+
const date = new Date()
|
|
227
|
+
const query = sql._query(generateReadJson({
|
|
228
|
+
filters: {
|
|
229
|
+
range: {
|
|
230
|
+
property: {
|
|
231
|
+
low: date,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}))
|
|
236
|
+
expect(query).toEqual({
|
|
237
|
+
bindings: [date, limit],
|
|
238
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"`
|
|
239
|
+
})
|
|
240
|
+
})
|
|
190
241
|
})
|
|
@@ -5,6 +5,7 @@ const {
|
|
|
5
5
|
} = require("@budibase/backend-core/roles")
|
|
6
6
|
const {
|
|
7
7
|
PermissionTypes,
|
|
8
|
+
PermissionLevels,
|
|
8
9
|
doesHaveBasePermission,
|
|
9
10
|
} = require("@budibase/backend-core/permissions")
|
|
10
11
|
const builderMiddleware = require("./builder")
|
|
@@ -64,7 +65,7 @@ const checkAuthorizedResource = async (
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
module.exports =
|
|
67
|
-
(permType, permLevel = null) =>
|
|
68
|
+
(permType, permLevel = null, opts = { schema: false }) =>
|
|
68
69
|
async (ctx, next) => {
|
|
69
70
|
// webhooks don't need authentication, each webhook unique
|
|
70
71
|
// also internal requests (between services) don't need authorized
|
|
@@ -81,15 +82,25 @@ module.exports =
|
|
|
81
82
|
await builderMiddleware(ctx, permType)
|
|
82
83
|
|
|
83
84
|
// get the resource roles
|
|
84
|
-
let resourceRoles = []
|
|
85
|
+
let resourceRoles = [],
|
|
86
|
+
otherLevelRoles
|
|
87
|
+
const otherLevel =
|
|
88
|
+
permLevel === PermissionLevels.READ
|
|
89
|
+
? PermissionLevels.WRITE
|
|
90
|
+
: PermissionLevels.READ
|
|
85
91
|
const appId = getAppId()
|
|
86
92
|
if (appId && hasResource(ctx)) {
|
|
87
93
|
resourceRoles = await getRequiredResourceRole(permLevel, ctx)
|
|
94
|
+
if (opts && opts.schema) {
|
|
95
|
+
otherLevelRoles = await getRequiredResourceRole(otherLevel, ctx)
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
// if the resource is public, proceed
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
if (
|
|
101
|
+
resourceRoles.includes(BUILTIN_ROLE_IDS.PUBLIC) ||
|
|
102
|
+
(otherLevelRoles && otherLevelRoles.includes(BUILTIN_ROLE_IDS.PUBLIC))
|
|
103
|
+
) {
|
|
93
104
|
return next()
|
|
94
105
|
}
|
|
95
106
|
|
|
@@ -98,8 +109,17 @@ module.exports =
|
|
|
98
109
|
return ctx.throw(403, "Session not authenticated")
|
|
99
110
|
}
|
|
100
111
|
|
|
101
|
-
|
|
102
|
-
|
|
112
|
+
try {
|
|
113
|
+
// check authorized
|
|
114
|
+
await checkAuthorized(ctx, resourceRoles, permType, permLevel)
|
|
115
|
+
} catch (err) {
|
|
116
|
+
// this is a schema, check if
|
|
117
|
+
if (opts && opts.schema && permLevel) {
|
|
118
|
+
await checkAuthorized(ctx, otherLevelRoles, permType, otherLevel)
|
|
119
|
+
} else {
|
|
120
|
+
throw err
|
|
121
|
+
}
|
|
122
|
+
}
|
|
103
123
|
|
|
104
124
|
// csrf protection
|
|
105
125
|
return csrf(ctx, next)
|