@budibase/server 1.2.57 → 1.2.58-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.
Files changed (207) hide show
  1. package/__mocks__/mongodb.ts +4 -0
  2. package/__mocks__/node-fetch.ts +8 -1
  3. package/builder/assets/index.d7a7633b.js +875 -0
  4. package/builder/assets/index.fdb1647e.css +6 -0
  5. package/builder/assets/{vendor.6bcafa60.js → vendor.67dbd8fa.js} +1 -1
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +510 -485
  8. package/coverage/coverage-final.json +18 -18
  9. package/coverage/lcov-report/api/controllers/apikeys.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 +1 -1
  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 +1 -1
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  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 +1 -1
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/index.html +25 -25
  29. package/coverage/lcov-report/api/controllers/row/internal.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +317 -191
  31. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +27 -18
  33. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  34. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/table/external.js.html +2 -2
  37. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  38. package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
  39. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/user.js.html +19 -19
  41. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  42. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  43. package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  46. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  47. package/coverage/lcov-report/api/index.html +1 -1
  48. package/coverage/lcov-report/api/index.js.html +5 -5
  49. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/index.html +1 -1
  60. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  74. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  77. package/coverage/lcov-report/automations/actions.js.html +1 -1
  78. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  79. package/coverage/lcov-report/automations/bullboard.js.html +9 -6
  80. package/coverage/lcov-report/automations/index.html +11 -11
  81. package/coverage/lcov-report/automations/index.js.html +1 -1
  82. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/index.html +1 -1
  89. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  106. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  107. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  108. package/coverage/lcov-report/constants/index.html +1 -1
  109. package/coverage/lcov-report/constants/index.js.html +30 -30
  110. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  111. package/coverage/lcov-report/constants/screens.js.html +1 -1
  112. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  113. package/coverage/lcov-report/db/index.html +1 -1
  114. package/coverage/lcov-report/db/index.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
  116. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  117. package/coverage/lcov-report/db/linkedRows/index.js.html +1 -1
  118. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  119. package/coverage/lcov-report/db/newid.js.html +4 -4
  120. package/coverage/lcov-report/db/utils.js.html +69 -69
  121. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  122. package/coverage/lcov-report/events/index.html +1 -1
  123. package/coverage/lcov-report/events/index.js.html +1 -1
  124. package/coverage/lcov-report/events/utils.js.html +1 -1
  125. package/coverage/lcov-report/index.html +33 -33
  126. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  127. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  128. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  129. package/coverage/lcov-report/middleware/builder.js.html +11 -11
  130. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  131. package/coverage/lcov-report/middleware/index.html +10 -10
  132. package/coverage/lcov-report/middleware/joi-validator.js.html +18 -9
  133. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  134. package/coverage/lcov-report/middleware/resourceId.js.html +12 -12
  135. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  136. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  137. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  138. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  139. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  140. package/coverage/lcov-report/utilities/global.js.html +31 -31
  141. package/coverage/lcov-report/utilities/index.html +1 -1
  142. package/coverage/lcov-report/utilities/index.js.html +23 -23
  143. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +2 -2
  144. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  145. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  146. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  147. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  148. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +1 -1
  149. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  150. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  151. package/coverage/lcov-report/utilities/security.js.html +2 -2
  152. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  153. package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
  154. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
  155. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  156. package/coverage/lcov-report/utilities/users.js.html +7 -7
  157. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  158. package/coverage/lcov.info +824 -780
  159. package/dist/api/controllers/row/internalSearch.js +39 -4
  160. package/dist/api/controllers/row/utils.js +3 -1
  161. package/dist/api/controllers/static/index.js +26 -2
  162. package/dist/api/controllers/static/templates/preview.hbs +103 -0
  163. package/dist/api/controllers/table/external.js +1 -1
  164. package/dist/api/routes/static.js +3 -0
  165. package/dist/app.js +4 -3
  166. package/dist/automations/bullboard.js +1 -0
  167. package/dist/automations/logging/index.js +3 -0
  168. package/dist/integrations/base/query.js +27 -0
  169. package/dist/integrations/base/sql.js +62 -30
  170. package/dist/integrations/base/utils.js +13 -27
  171. package/dist/integrations/microsoftSqlServer.js +5 -2
  172. package/dist/integrations/mongodb.js +35 -8
  173. package/dist/integrations/mysql.js +2 -2
  174. package/dist/integrations/postgres.js +5 -2
  175. package/dist/middleware/joi-validator.js +7 -4
  176. package/dist/package.json +7 -7
  177. package/dist/threads/index.js +1 -0
  178. package/dist/tsconfig.build.tsbuildinfo +1 -1
  179. package/dist/utilities/fileSystem/index.js +2 -1
  180. package/dist/utilities/redis.js +1 -0
  181. package/package.json +8 -8
  182. package/src/api/controllers/row/internalSearch.js +45 -3
  183. package/src/api/controllers/row/utils.js +4 -1
  184. package/src/api/controllers/static/index.ts +21 -1
  185. package/src/api/controllers/static/templates/preview.hbs +103 -0
  186. package/src/api/controllers/table/external.js +1 -1
  187. package/src/api/routes/static.ts +12 -0
  188. package/src/api/routes/tests/internalSearch.spec.js +176 -0
  189. package/src/api/routes/tests/static.spec.js +19 -7
  190. package/src/app.ts +5 -3
  191. package/src/automations/bullboard.js +1 -0
  192. package/src/automations/logging/index.ts +3 -0
  193. package/src/integrations/base/query.ts +16 -0
  194. package/src/integrations/base/sql.ts +67 -30
  195. package/src/integrations/base/utils.ts +9 -18
  196. package/src/integrations/microsoftSqlServer.ts +3 -2
  197. package/src/integrations/mongodb.ts +35 -8
  198. package/src/integrations/mysql.ts +1 -1
  199. package/src/integrations/postgres.ts +2 -1
  200. package/src/integrations/tests/mongo.spec.js +218 -0
  201. package/src/integrations/tests/sql.spec.js +101 -11
  202. package/src/middleware/joi-validator.js +7 -4
  203. package/src/threads/index.ts +1 -0
  204. package/src/utilities/fileSystem/index.js +2 -0
  205. package/src/utilities/redis.js +1 -0
  206. package/builder/assets/index.08dd0c5e.css +0 -6
  207. package/builder/assets/index.b6eebfec.js +0 -975
@@ -14,7 +14,7 @@ const { join } = require("path");
14
14
  const uuid = require("uuid/v4");
15
15
  const { doWithDB, dangerousGetDB, closeDB, } = require("@budibase/backend-core/db");
16
16
  const { ObjectStoreBuckets } = require("../../constants");
17
- const { upload, retrieve, retrieveToTmp, streamUpload, deleteFolder, downloadTarball, } = require("./utilities");
17
+ const { upload, retrieve, retrieveToTmp, streamUpload, deleteFolder, downloadTarball, deleteFiles, } = require("./utilities");
18
18
  const { updateClientLibrary } = require("./clientLibrary");
19
19
  const env = require("../../environment");
20
20
  const { USER_METDATA_PREFIX, LINK_USER_METADATA_PREFIX, TABLE_ROW_PREFIX, } = require("../../db/utils");
@@ -291,5 +291,6 @@ exports.cleanup = appIds => {
291
291
  exports.upload = upload;
292
292
  exports.retrieve = retrieve;
293
293
  exports.retrieveToTmp = retrieveToTmp;
294
+ exports.deleteFiles = deleteFiles;
294
295
  exports.TOP_LEVEL_PATH = TOP_LEVEL_PATH;
295
296
  exports.NODE_MODULES_PATH = NODE_MODULES_PATH;
@@ -30,6 +30,7 @@ exports.shutdown = () => __awaiter(void 0, void 0, void 0, function* () {
30
30
  yield debounceClient.finish();
31
31
  if (flagClient)
32
32
  yield flagClient.finish();
33
+ console.log("Redis shutdown");
33
34
  });
34
35
  exports.doesUserHaveLock = (devAppId, user) => __awaiter(void 0, void 0, void 0, function* () {
35
36
  const value = yield devAppClient.get(devAppId);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "1.2.57",
4
+ "version": "1.2.58-alpha.2",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -77,11 +77,11 @@
77
77
  "license": "GPL-3.0",
78
78
  "dependencies": {
79
79
  "@apidevtools/swagger-parser": "10.0.3",
80
- "@budibase/backend-core": "^1.2.57",
81
- "@budibase/client": "^1.2.57",
82
- "@budibase/pro": "1.2.56",
83
- "@budibase/string-templates": "^1.2.57",
84
- "@budibase/types": "^1.2.57",
80
+ "@budibase/backend-core": "1.2.58-alpha.2",
81
+ "@budibase/client": "1.2.58-alpha.2",
82
+ "@budibase/pro": "1.2.58-alpha.1",
83
+ "@budibase/string-templates": "1.2.58-alpha.2",
84
+ "@budibase/types": "1.2.58-alpha.2",
85
85
  "@bull-board/api": "3.7.0",
86
86
  "@bull-board/koa": "3.9.4",
87
87
  "@elastic/elasticsearch": "7.10.0",
@@ -107,7 +107,7 @@
107
107
  "google-auth-library": "7.12.0",
108
108
  "google-spreadsheet": "3.2.0",
109
109
  "jimp": "0.16.1",
110
- "joi": "17.2.1",
110
+ "joi": "17.6.0",
111
111
  "js-yaml": "4.1.0",
112
112
  "jsonschema": "1.4.0",
113
113
  "knex": "0.95.15",
@@ -196,5 +196,5 @@
196
196
  "optionalDependencies": {
197
197
  "oracledb": "5.3.0"
198
198
  },
199
- "gitHead": "605b91baf8bed0f1ffbb2d3304d4525c866bdd77"
199
+ "gitHead": "675fdd4b88456e4a663f8e2efb148556e0a35aab"
200
200
  }
@@ -1,4 +1,5 @@
1
1
  const { SearchIndexes } = require("../../../db/utils")
2
+ const { removeKeyNumbering } = require("./utils")
2
3
  const fetch = require("node-fetch")
3
4
  const { getCouchInfo } = require("@budibase/backend-core/db")
4
5
  const { getAppId } = require("@budibase/backend-core/context")
@@ -20,6 +21,8 @@ class QueryBuilder {
20
21
  notEmpty: {},
21
22
  oneOf: {},
22
23
  contains: {},
24
+ notContains: {},
25
+ containsAny: {},
23
26
  ...base,
24
27
  }
25
28
  this.limit = 50
@@ -125,6 +128,16 @@ class QueryBuilder {
125
128
  return this
126
129
  }
127
130
 
131
+ addNotContains(key, value) {
132
+ this.query.notContains[key] = value
133
+ return this
134
+ }
135
+
136
+ addContainsAny(key, value) {
137
+ this.query.containsAny[key] = value
138
+ return this
139
+ }
140
+
128
141
  /**
129
142
  * Preprocesses a value before going into a lucene search.
130
143
  * Transforms strings to lowercase and wraps strings and bools in quotes.
@@ -170,11 +183,29 @@ class QueryBuilder {
170
183
  return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
171
184
  }
172
185
 
173
- const contains = (key, value) => {
174
- if (!value && value !== 0) {
186
+ const contains = (key, value, mode = "AND") => {
187
+ if (Array.isArray(value) && value.length === 0) {
175
188
  return null
176
189
  }
177
- return `${key}:${builder.preprocess(value, { escape: true })}`
190
+ if (!Array.isArray(value)) {
191
+ return `${key}:${value}`
192
+ }
193
+ let statement = `${builder.preprocess(value[0], { escape: true })}`
194
+ for (let i = 1; i < value.length; i++) {
195
+ statement += ` ${mode} ${builder.preprocess(value[i], {
196
+ escape: true,
197
+ })}`
198
+ }
199
+ return `${key}:(${statement})`
200
+ }
201
+
202
+ const notContains = (key, value) => {
203
+ const allPrefix = allOr === "" ? "*:* AND" : ""
204
+ return allPrefix + "NOT " + contains(key, value)
205
+ }
206
+
207
+ const containsAny = (key, value) => {
208
+ return contains(key, value, "OR")
178
209
  }
179
210
 
180
211
  const oneOf = (key, value) => {
@@ -197,6 +228,8 @@ class QueryBuilder {
197
228
 
198
229
  function build(structure, queryFn) {
199
230
  for (let [key, value] of Object.entries(structure)) {
231
+ // check for new format - remove numbering if needed
232
+ key = removeKeyNumbering(key)
200
233
  key = builder.preprocess(key.replace(/ /g, "_"), {
201
234
  escape: true,
202
235
  })
@@ -275,6 +308,12 @@ class QueryBuilder {
275
308
  if (this.query.contains) {
276
309
  build(this.query.contains, contains)
277
310
  }
311
+ if (this.query.notContains) {
312
+ build(this.query.notContains, notContains)
313
+ }
314
+ if (this.query.containsAny) {
315
+ build(this.query.containsAny, containsAny)
316
+ }
278
317
  // make sure table ID is always added as an AND
279
318
  if (tableId) {
280
319
  query = `(${query})`
@@ -310,6 +349,9 @@ class QueryBuilder {
310
349
  }
311
350
  }
312
351
 
352
+ // exported for unit testing
353
+ exports.QueryBuilder = QueryBuilder
354
+
313
355
  /**
314
356
  * Executes a lucene search query.
315
357
  * @param url The query URL
@@ -3,8 +3,9 @@ const { cloneDeep } = require("lodash/fp")
3
3
  const { InternalTables } = require("../../../db/utils")
4
4
  const userController = require("../user")
5
5
  const { FieldTypes } = require("../../../constants")
6
- const { makeExternalQuery } = require("../../../integrations/base/utils")
7
6
  const { getAppDB } = require("@budibase/backend-core/context")
7
+ const { makeExternalQuery } = require("../../../integrations/base/query")
8
+ const { removeKeyNumbering } = require("../../../integrations/base/utils")
8
9
 
9
10
  validateJs.extend(validateJs.validators.datetime, {
10
11
  parse: function (value) {
@@ -16,6 +17,8 @@ validateJs.extend(validateJs.validators.datetime, {
16
17
  },
17
18
  })
18
19
 
20
+ exports.removeKeyNumbering = removeKeyNumbering
21
+
19
22
  exports.getDatasourceAndQuery = async json => {
20
23
  const datasourceId = json.endpoint.datasourceId
21
24
  const db = getAppDB()
@@ -12,7 +12,7 @@ const {
12
12
  } = require("../../../utilities/fileSystem")
13
13
  const env = require("../../../environment")
14
14
  const { clientLibraryPath } = require("../../../utilities")
15
- const { upload } = require("../../../utilities/fileSystem")
15
+ const { upload, deleteFiles } = require("../../../utilities/fileSystem")
16
16
  const { attachmentsRelativeURL } = require("../../../utilities")
17
17
  const { DocumentType } = require("../../../db/utils")
18
18
  const { getAppDB, getAppId } = require("@budibase/backend-core/context")
@@ -97,6 +97,10 @@ export const uploadFile = async function (ctx: any) {
97
97
  ctx.body = await Promise.all(uploads)
98
98
  }
99
99
 
100
+ export const deleteObjects = async function (ctx: any) {
101
+ ctx.body = await deleteFiles(ObjectStoreBuckets.APPS, ctx.request.body.keys)
102
+ }
103
+
100
104
  export const serveApp = async function (ctx: any) {
101
105
  const db = getAppDB({ skip_setup: true })
102
106
  const appInfo = await db.get(DocumentType.APP_METADATA)
@@ -124,6 +128,22 @@ export const serveApp = async function (ctx: any) {
124
128
  }
125
129
  }
126
130
 
131
+ export const serveBuilderPreview = async function (ctx: any) {
132
+ const db = getAppDB({ skip_setup: true })
133
+ const appInfo = await db.get(DocumentType.APP_METADATA)
134
+
135
+ if (!env.isJest()) {
136
+ let appId = getAppId()
137
+ const previewHbs = loadHandlebarsFile(`${__dirname}/templates/preview.hbs`)
138
+ ctx.body = await processString(previewHbs, {
139
+ clientLibPath: clientLibraryPath(appId, appInfo.version, ctx),
140
+ })
141
+ } else {
142
+ // just return the app info for jest to assert on
143
+ ctx.body = { ...appInfo, builderPreview: true }
144
+ }
145
+ }
146
+
127
147
  export const serveClientLibrary = async function (ctx: any) {
128
148
  return send(ctx, "budibase-client.js", {
129
149
  root: join(NODE_MODULES_PATH, "@budibase", "client", "dist"),
@@ -0,0 +1,103 @@
1
+ <html lang="en">
2
+ <head>
3
+ <title>Budibase Builder Preview</title>
4
+ <link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
5
+ <link rel="preconnect" href="https://fonts.gstatic.com" />
6
+ <link
7
+ href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700&display=swap"
8
+ rel="stylesheet"
9
+ />
10
+ <link
11
+ href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css"
12
+ rel="stylesheet"
13
+ />
14
+ <style>
15
+ html, body {
16
+ padding: 0;
17
+ margin: 0;
18
+ }
19
+ html {
20
+ height: 100%;
21
+ width: 100%;
22
+ overflow: hidden;
23
+ display: flex;
24
+ flex-direction: column;
25
+ justify-content: flex-start;
26
+ align-items: stretch;
27
+ }
28
+ body {
29
+ flex: 1 1 auto;
30
+ overflow: hidden;
31
+ }
32
+
33
+ *,
34
+ *:before,
35
+ *:after {
36
+ box-sizing: border-box;
37
+ }
38
+ </style>
39
+ <script src='{{ clientLibPath }}'></script>
40
+ <script>
41
+ function receiveMessage(event) {
42
+ if (!event.data) {
43
+ return
44
+ }
45
+
46
+ // Parse received message
47
+ // If parsing fails, just ignore and wait for the next message
48
+ let parsed
49
+ try {
50
+ parsed = JSON.parse(event.data)
51
+ } catch (error) {
52
+ console.error("Client received invalid JSON")
53
+ // Ignore
54
+ }
55
+ if (!parsed || !parsed.isBudibaseEvent) {
56
+ return
57
+ }
58
+
59
+ // Extract data from message
60
+ const {
61
+ selectedComponentId,
62
+ layout,
63
+ screen,
64
+ appId,
65
+ theme,
66
+ customTheme,
67
+ previewDevice,
68
+ navigation,
69
+ hiddenComponentIds
70
+ } = parsed
71
+
72
+ // Set some flags so the app knows we're in the builder
73
+ window["##BUDIBASE_IN_BUILDER##"] = true
74
+ window["##BUDIBASE_APP_ID##"] = appId
75
+ window["##BUDIBASE_PREVIEW_LAYOUT##"] = layout
76
+ window["##BUDIBASE_PREVIEW_SCREEN##"] = screen
77
+ window["##BUDIBASE_SELECTED_COMPONENT_ID##"] = selectedComponentId
78
+ window["##BUDIBASE_PREVIEW_ID##"] = Math.random()
79
+ window["##BUDIBASE_PREVIEW_THEME##"] = theme
80
+ window["##BUDIBASE_PREVIEW_CUSTOM_THEME##"] = customTheme
81
+ window["##BUDIBASE_PREVIEW_DEVICE##"] = previewDevice
82
+ window["##BUDIBASE_PREVIEW_NAVIGATION##"] = navigation
83
+ window["##BUDIBASE_HIDDEN_COMPONENT_IDS##"] = hiddenComponentIds
84
+
85
+ // Initialise app
86
+ try {
87
+ if (window.loadBudibase) {
88
+ window.loadBudibase()
89
+ document.documentElement.classList.add("loaded")
90
+ } else {
91
+ throw "The client library couldn't be loaded"
92
+ }
93
+ } catch (error) {
94
+ window.parent.postMessage({ type: "error", error })
95
+ }
96
+ }
97
+
98
+ window.addEventListener("message", receiveMessage)
99
+ window.parent.postMessage({ type: "ready" })
100
+ </script>
101
+ </head>
102
+ <body></body>
103
+ </html>
@@ -14,7 +14,7 @@ const {
14
14
  FieldTypes,
15
15
  RelationshipTypes,
16
16
  } = require("../../../constants")
17
- const { makeExternalQuery } = require("../../../integrations/base/utils")
17
+ const { makeExternalQuery } = require("../../../integrations/base/query")
18
18
  const { cloneDeep } = require("lodash/fp")
19
19
  const csvParser = require("../../../utilities/csvParser")
20
20
  const { handleRequest } = require("../row/external")
@@ -38,6 +38,11 @@ router
38
38
  // TODO: for now this builder endpoint is not authorized/secured, will need to be
39
39
  .get("/builder/:file*", controller.serveBuilder)
40
40
  .post("/api/attachments/process", authorized(BUILDER), controller.uploadFile)
41
+ .post(
42
+ "/api/attachments/delete",
43
+ authorized(BUILDER),
44
+ controller.deleteObjects
45
+ )
41
46
  .post("/api/beta/:feature", controller.toggleBetaUiFeature)
42
47
  .post(
43
48
  "/api/attachments/:tableId/upload",
@@ -45,6 +50,13 @@ router
45
50
  authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
46
51
  controller.uploadFile
47
52
  )
53
+ .post(
54
+ "/api/attachments/:tableId/delete",
55
+ paramResource("tableId"),
56
+ authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
57
+ controller.deleteObjects
58
+ )
59
+ .get("/preview", authorized(BUILDER), controller.serveBuilderPreview)
48
60
  .get("/:appId/:path*", controller.serveApp)
49
61
  .get("/app/:appUrl/:path*", controller.serveApp)
50
62
  .post(
@@ -0,0 +1,176 @@
1
+ const search = require("../../controllers/row/internalSearch")
2
+ // this will be mocked out for _search endpoint
3
+ const fetch = require("node-fetch")
4
+ const PARAMS = {
5
+ tableId: "ta_12345679abcdef",
6
+ version: "1",
7
+ bookmark: null,
8
+ sort: null,
9
+ sortOrder: "ascending",
10
+ sortType: "string",
11
+ }
12
+
13
+ function checkLucene(resp, expected, params = PARAMS) {
14
+ const query = resp.rows[0].query
15
+ const json = JSON.parse(query)
16
+ if (PARAMS.sort) {
17
+ expect(json.sort).toBe(`${PARAMS.sort}<${PARAMS.sortType}>`)
18
+ }
19
+ if (PARAMS.bookmark) {
20
+ expect(json.bookmark).toBe(PARAMS.bookmark)
21
+ }
22
+ expect(json.include_docs).toBe(true)
23
+ expect(json.q).toBe(`(${expected}) AND tableId:"${params.tableId}"`)
24
+ expect(json.limit).toBe(params.limit || 50)
25
+ }
26
+
27
+ describe("internal search", () => {
28
+ it("default query", async () => {
29
+ const response = await search.paginatedSearch({
30
+ }, PARAMS)
31
+ checkLucene(response, `*:*`)
32
+ })
33
+
34
+ it("test equal query", async () => {
35
+ const response = await search.paginatedSearch({
36
+ equal: {
37
+ "column": "1",
38
+ }
39
+ }, PARAMS)
40
+ checkLucene(response, `*:* AND column:"1"`)
41
+ })
42
+
43
+ it("test notEqual query", async () => {
44
+ const response = await search.paginatedSearch({
45
+ notEqual: {
46
+ "column": "1",
47
+ }
48
+ }, PARAMS)
49
+ checkLucene(response, `*:* AND !column:"1"`)
50
+ })
51
+
52
+ it("test OR query", async () => {
53
+ const response = await search.paginatedSearch({
54
+ allOr: true,
55
+ equal: {
56
+ "column": "2",
57
+ },
58
+ notEqual: {
59
+ "column": "1",
60
+ }
61
+ }, PARAMS)
62
+ checkLucene(response, `column:"2" OR !column:"1"`)
63
+ })
64
+
65
+ it("test AND query", async () => {
66
+ const response = await search.paginatedSearch({
67
+ equal: {
68
+ "column": "2",
69
+ },
70
+ notEqual: {
71
+ "column": "1",
72
+ }
73
+ }, PARAMS)
74
+ checkLucene(response, `*:* AND column:"2" AND !column:"1"`)
75
+ })
76
+
77
+ it("test pagination query", async () => {
78
+ const updatedParams = {
79
+ ...PARAMS,
80
+ limit: 100,
81
+ bookmark: "awd",
82
+ sort: "column",
83
+ }
84
+ const response = await search.paginatedSearch({
85
+ string: {
86
+ "column": "2",
87
+ },
88
+ }, updatedParams)
89
+ checkLucene(response, `*:* AND column:2*`, updatedParams)
90
+ })
91
+
92
+ it("test range query", async () => {
93
+ const response = await search.paginatedSearch({
94
+ range: {
95
+ "column": { low: 1, high: 2 },
96
+ },
97
+ }, PARAMS)
98
+ checkLucene(response, `*:* AND column:[1 TO 2]`, PARAMS)
99
+ })
100
+
101
+ it("test empty query", async () => {
102
+ const response = await search.paginatedSearch({
103
+ empty: {
104
+ "column": "",
105
+ },
106
+ }, PARAMS)
107
+ checkLucene(response, `*:* AND !column:["" TO *]`, PARAMS)
108
+ })
109
+
110
+ it("test notEmpty query", async () => {
111
+ const response = await search.paginatedSearch({
112
+ notEmpty: {
113
+ "column": "",
114
+ },
115
+ }, PARAMS)
116
+ checkLucene(response, `*:* AND column:["" TO *]`, PARAMS)
117
+ })
118
+
119
+ it("test oneOf query", async () => {
120
+ const response = await search.paginatedSearch({
121
+ oneOf: {
122
+ "column": ["a", "b"],
123
+ },
124
+ }, PARAMS)
125
+ checkLucene(response, `*:* AND column:("a" OR "b")`, PARAMS)
126
+ })
127
+
128
+ it("test contains query", async () => {
129
+ const response = await search.paginatedSearch({
130
+ contains: {
131
+ "column": "a",
132
+ "colArr": [1, 2, 3],
133
+ },
134
+ }, PARAMS)
135
+ checkLucene(response, `*:* AND column:a AND colArr:(1 AND 2 AND 3)`, PARAMS)
136
+ })
137
+
138
+ it("test multiple of same column", async () => {
139
+ const response = await search.paginatedSearch({
140
+ allOr: true,
141
+ equal: {
142
+ "1:column": "a",
143
+ "2:column": "b",
144
+ "3:column": "c",
145
+ },
146
+ }, PARAMS)
147
+ checkLucene(response, `column:"a" OR column:"b" OR column:"c"`, PARAMS)
148
+ })
149
+
150
+ it("check a weird case for lucene building", async () => {
151
+ const response = await search.paginatedSearch({
152
+ equal: {
153
+ "1:1:column": "a",
154
+ },
155
+ }, PARAMS)
156
+ checkLucene(response, `*:* AND 1\\:column:"a"`, PARAMS)
157
+ })
158
+
159
+ it("test containsAny query", async () => {
160
+ const response = await search.paginatedSearch({
161
+ containsAny: {
162
+ "column": ["a", "b", "c"]
163
+ },
164
+ }, PARAMS)
165
+ checkLucene(response, `*:* AND column:(a OR b OR c)`, PARAMS)
166
+ })
167
+
168
+ it("test notContains query", async () => {
169
+ const response = await search.paginatedSearch({
170
+ notContains: {
171
+ "column": ["a", "b", "c"]
172
+ },
173
+ }, PARAMS)
174
+ checkLucene(response, `*:* AND NOT column:(a AND b AND c)`, PARAMS)
175
+ })
176
+ })
@@ -40,7 +40,6 @@ describe("/static", () => {
40
40
  })
41
41
 
42
42
  describe("/app", () => {
43
-
44
43
  beforeEach(() => {
45
44
  jest.clearAllMocks()
46
45
  })
@@ -60,7 +59,7 @@ describe("/static", () => {
60
59
  it("should serve the app by url", async () => {
61
60
  const headers = config.defaultHeaders()
62
61
  delete headers[constants.Headers.APP_ID]
63
-
62
+
64
63
  const res = await request
65
64
  .get(`/app${config.prodApp.url}`)
66
65
  .set(headers)
@@ -82,7 +81,7 @@ describe("/static", () => {
82
81
  describe("/attachments", () => {
83
82
  describe("generateSignedUrls", () => {
84
83
  let datasource
85
-
84
+
86
85
  beforeEach(async () => {
87
86
  datasource = await config.createDatasource({
88
87
  datasource: {
@@ -93,7 +92,7 @@ describe("/static", () => {
93
92
  },
94
93
  })
95
94
  })
96
-
95
+
97
96
  it("should be able to generate a signed upload URL", async () => {
98
97
  const bucket = "foo"
99
98
  const key = "bar"
@@ -108,7 +107,7 @@ describe("/static", () => {
108
107
  `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}`
109
108
  )
110
109
  })
111
-
110
+
112
111
  it("should handle an invalid datasource ID", async () => {
113
112
  const res = await request
114
113
  .post(`/api/attachments/foo/url`)
@@ -123,7 +122,7 @@ describe("/static", () => {
123
122
  "The specified datasource could not be found"
124
123
  )
125
124
  })
126
-
125
+
127
126
  it("should require a bucket parameter", async () => {
128
127
  const res = await request
129
128
  .post(`/api/attachments/${datasource._id}/url`)
@@ -136,7 +135,7 @@ describe("/static", () => {
136
135
  .expect(400)
137
136
  expect(res.body.message).toEqual("bucket and key values are required")
138
137
  })
139
-
138
+
140
139
  it("should require a key parameter", async () => {
141
140
  const res = await request
142
141
  .post(`/api/attachments/${datasource._id}/url`)
@@ -151,4 +150,17 @@ describe("/static", () => {
151
150
  })
152
151
  })
153
152
 
153
+ describe("/preview", () => {
154
+ beforeEach(() => {
155
+ jest.clearAllMocks()
156
+ })
157
+
158
+ it("should serve the builder preview", async () => {
159
+ const headers = config.defaultHeaders()
160
+ const res = await request.get(`/preview`).set(headers).expect(200)
161
+
162
+ expect(res.body.appId).toBe(config.appId)
163
+ expect(res.body.builderPreview).toBe(true)
164
+ })
165
+ })
154
166
  })
package/src/app.ts CHANGED
@@ -83,9 +83,7 @@ server.on("close", async () => {
83
83
  return
84
84
  }
85
85
  shuttingDown = true
86
- if (!env.isTest()) {
87
- console.log("Server Closed")
88
- }
86
+ console.log("Server Closed")
89
87
  await automations.shutdown()
90
88
  await redis.shutdown()
91
89
  await events.shutdown()
@@ -167,3 +165,7 @@ process.on("uncaughtException", err => {
167
165
  process.on("SIGTERM", () => {
168
166
  shutdown()
169
167
  })
168
+
169
+ process.on("SIGINT", () => {
170
+ shutdown()
171
+ })
@@ -53,6 +53,7 @@ exports.shutdown = async () => {
53
53
  await automationQueue.close()
54
54
  automationQueue = null
55
55
  }
56
+ console.log("Bull shutdown")
56
57
  }
57
58
 
58
59
  exports.queue = automationQueue
@@ -23,6 +23,9 @@ export async function checkAppMetadata(apps: App[]) {
23
23
  for (let [key, errors] of Object.entries(metadata.automationErrors)) {
24
24
  const updated = []
25
25
  for (let error of errors) {
26
+ if (!error) {
27
+ continue
28
+ }
26
29
  const startDate = error.split(dbUtils.SEPARATOR)[2]
27
30
  if (startDate > maxStartDate) {
28
31
  updated.push(error)
@@ -0,0 +1,16 @@
1
+ import { QueryJson, Datasource } from "@budibase/types"
2
+ const { integrations } = require("../index")
3
+
4
+ export async function makeExternalQuery(
5
+ datasource: Datasource,
6
+ json: QueryJson
7
+ ) {
8
+ const Integration = integrations[datasource.source]
9
+ // query is the opinionated function
10
+ if (Integration.prototype.query) {
11
+ const integration = new Integration(datasource.config)
12
+ return integration.query(json)
13
+ } else {
14
+ throw "Datasource does not support query."
15
+ }
16
+ }