@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.
Files changed (237) hide show
  1. package/builder/assets/index.cca3db8c.js +1291 -0
  2. package/builder/assets/{index.7c8961b4.css → index.ea3718aa.css} +2 -2
  3. package/builder/assets/{vendor.a7c6ad0a.js → vendor.8e34a169.js} +1 -1
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +354 -334
  6. package/coverage/coverage-final.json +15 -15
  7. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/application.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +18 -18
  18. package/coverage/lcov-report/api/controllers/integration.js.html +59 -11
  19. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/permission.js.html +7 -7
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/index.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/query/validation.js.html +2 -2
  26. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/index.html +10 -10
  30. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/row/internal.js.html +19 -7
  32. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  33. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +6 -6
  35. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/analytics.js.html +3 -3
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +1 -1
  65. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/table.js.html +2 -2
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  82. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  83. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  84. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  85. package/coverage/lcov-report/automations/actions.js.html +1 -1
  86. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  87. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  88. package/coverage/lcov-report/automations/index.html +12 -12
  89. package/coverage/lcov-report/automations/index.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/index.html +1 -1
  99. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  104. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  106. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  107. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  111. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  112. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  114. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  115. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  116. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  117. package/coverage/lcov-report/automations/utils.js.html +20 -8
  118. package/coverage/lcov-report/constants/index.html +1 -1
  119. package/coverage/lcov-report/constants/index.js.html +1 -1
  120. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  121. package/coverage/lcov-report/constants/screens.js.html +1 -1
  122. package/coverage/lcov-report/db/client.js.html +1 -1
  123. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  124. package/coverage/lcov-report/db/index.html +1 -1
  125. package/coverage/lcov-report/db/index.js.html +1 -1
  126. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  127. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  128. package/coverage/lcov-report/db/linkedRows/index.js.html +10 -10
  129. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
  130. package/coverage/lcov-report/db/newid.js.html +2 -2
  131. package/coverage/lcov-report/db/utils.js.html +2 -2
  132. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  133. package/coverage/lcov-report/events/index.html +1 -1
  134. package/coverage/lcov-report/events/index.js.html +1 -1
  135. package/coverage/lcov-report/events/utils.js.html +1 -1
  136. package/coverage/lcov-report/index.html +31 -31
  137. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  138. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  139. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  140. package/coverage/lcov-report/middleware/authorized.js.html +75 -15
  141. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  142. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  143. package/coverage/lcov-report/middleware/index.html +15 -15
  144. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  145. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  146. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  147. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  148. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  149. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  150. package/coverage/lcov-report/threads/automation.js.html +1 -1
  151. package/coverage/lcov-report/threads/index.html +1 -1
  152. package/coverage/lcov-report/threads/index.js.html +1 -1
  153. package/coverage/lcov-report/threads/query.js.html +1 -1
  154. package/coverage/lcov-report/threads/utils.js.html +1 -1
  155. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  156. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  157. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  158. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  159. package/coverage/lcov-report/utilities/global.js.html +1 -1
  160. package/coverage/lcov-report/utilities/index.html +1 -1
  161. package/coverage/lcov-report/utilities/index.js.html +1 -1
  162. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  163. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  164. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  165. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  166. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  167. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +12 -12
  168. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +8 -8
  169. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  170. package/coverage/lcov-report/utilities/security.js.html +1 -1
  171. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  172. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  173. package/coverage/lcov-report/utilities/usageQuota/index.js.html +1 -1
  174. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  175. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  176. package/coverage/lcov-report/utilities/users.js.html +1 -1
  177. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  178. package/coverage/lcov.info +584 -546
  179. package/dist/api/controllers/integration.js +15 -1
  180. package/dist/api/controllers/permission.js +3 -4
  181. package/dist/api/controllers/query/import/index.js +2 -1
  182. package/dist/api/controllers/query/import/sources/base/index.js +12 -1
  183. package/dist/api/controllers/query/import/sources/curl.js +2 -2
  184. package/dist/api/controllers/query/import/sources/openapi3.js +174 -0
  185. package/dist/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
  186. package/dist/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
  187. package/dist/api/controllers/row/internal.js +2 -1
  188. package/dist/api/routes/analytics.js +2 -2
  189. package/dist/api/routes/table.js +1 -1
  190. package/dist/automations/utils.js +3 -1
  191. package/dist/definitions/datasource.js +1 -0
  192. package/dist/environment.js +2 -0
  193. package/dist/integrations/base/sql.js +16 -9
  194. package/dist/integrations/dynamodb.js +3 -1
  195. package/dist/integrations/firebase.js +192 -0
  196. package/dist/integrations/googlesheets.js +17 -1
  197. package/dist/integrations/index.js +4 -1
  198. package/dist/integrations/mysql.js +14 -1
  199. package/dist/integrations/rest.js +2 -1
  200. package/dist/middleware/authorized.js +24 -7
  201. package/dist/package.json +7 -4
  202. package/dist/tsconfig.tsbuildinfo +1 -1
  203. package/package.json +8 -5
  204. package/scripts/dev/manage.js +2 -1
  205. package/specs/openapi.json +23 -3
  206. package/specs/openapi.yaml +20 -4
  207. package/specs/resources/query.js +27 -5
  208. package/src/api/controllers/integration.js +17 -1
  209. package/src/api/controllers/permission.js +3 -3
  210. package/src/api/controllers/query/import/index.ts +2 -1
  211. package/src/api/controllers/query/import/sources/base/index.ts +12 -2
  212. package/src/api/controllers/query/import/sources/curl.ts +2 -2
  213. package/src/api/controllers/query/import/sources/openapi3.ts +205 -0
  214. package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
  215. package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml +153 -0
  216. package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
  217. package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.yaml +804 -0
  218. package/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js +240 -0
  219. package/src/api/controllers/query/import/tests/index.spec.js +43 -0
  220. package/src/api/controllers/row/internal.js +5 -1
  221. package/src/api/routes/analytics.js +2 -2
  222. package/src/api/routes/table.js +1 -1
  223. package/src/api/routes/tests/misc.spec.js +2 -2
  224. package/src/automations/utils.js +5 -1
  225. package/src/definitions/datasource.ts +2 -5
  226. package/src/definitions/openapi.ts +480 -470
  227. package/src/environment.js +2 -0
  228. package/src/integrations/base/sql.ts +14 -9
  229. package/src/integrations/dynamodb.ts +3 -1
  230. package/src/integrations/firebase.ts +205 -0
  231. package/src/integrations/googlesheets.ts +16 -1
  232. package/src/integrations/index.ts +4 -1
  233. package/src/integrations/mysql.ts +15 -1
  234. package/src/integrations/rest.ts +2 -1
  235. package/src/integrations/tests/sql.spec.js +51 -0
  236. package/src/middleware/authorized.js +26 -6
  237. package/builder/assets/index.2dcb5072.js +0 -1291
@@ -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 new Date(8640000000000000)
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 (!value.high || !value.low) {
138
- return
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.connect()
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
- const googleConfig = await getScopedConfig(db, {
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 {
@@ -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?.[pagination.responseParam]
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
- const isPublicResource = resourceRoles.includes(BUILTIN_ROLE_IDS.PUBLIC)
92
- if (isPublicResource) {
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
- // check authorized
102
- await checkAuthorized(ctx, resourceRoles, permType, permLevel)
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)