@budibase/server 1.2.44-alpha.0 → 1.2.46

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 (205) hide show
  1. package/__mocks__/mongodb.ts +0 -4
  2. package/__mocks__/node-fetch.ts +1 -8
  3. package/builder/assets/index.08dd0c5e.css +6 -0
  4. package/builder/assets/index.f6823431.js +975 -0
  5. package/builder/assets/{vendor.67dbd8fa.js → vendor.6bcafa60.js} +1 -1
  6. package/builder/index.html +3 -3
  7. package/coverage/clover.xml +714 -727
  8. package/coverage/coverage-final.json +27 -27
  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 +35 -35
  29. package/coverage/lcov-report/api/controllers/row/internal.js.html +88 -46
  30. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +191 -317
  31. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +15 -15
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +30 -39
  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 +41 -41
  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 +17 -17
  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 +2 -2
  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 +13 -7
  80. package/coverage/lcov-report/automations/index.html +12 -12
  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 +11 -11
  116. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  117. package/coverage/lcov-report/db/linkedRows/index.js.html +19 -19
  118. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
  119. package/coverage/lcov-report/db/newid.js.html +4 -4
  120. package/coverage/lcov-report/db/utils.js.html +71 -71
  121. package/coverage/lcov-report/events/AutomationEmitter.js.html +5 -5
  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 +25 -25
  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 +12 -12
  130. package/coverage/lcov-report/middleware/currentapp.js.html +33 -33
  131. package/coverage/lcov-report/middleware/index.html +1 -1
  132. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  133. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  134. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  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 +39 -39
  149. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
  150. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  151. package/coverage/lcov-report/utilities/security.js.html +1 -1
  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 +1168 -1194
  159. package/dist/api/controllers/row/internal.js +15 -1
  160. package/dist/api/controllers/row/internalSearch.js +4 -39
  161. package/dist/api/controllers/row/utils.js +1 -3
  162. package/dist/api/controllers/static/index.js +2 -8
  163. package/dist/api/controllers/table/external.js +1 -1
  164. package/dist/api/routes/static.js +0 -2
  165. package/dist/automations/bullboard.js +2 -0
  166. package/dist/automations/listeners.js +102 -0
  167. package/dist/automations/logging/index.js +0 -3
  168. package/dist/automations/utils.js +6 -2
  169. package/dist/integrations/base/sql.js +30 -62
  170. package/dist/integrations/base/utils.js +27 -13
  171. package/dist/integrations/microsoftSqlServer.js +2 -5
  172. package/dist/integrations/mongodb.js +8 -35
  173. package/dist/integrations/mysql.js +2 -2
  174. package/dist/integrations/postgres.js +2 -5
  175. package/dist/package.json +7 -7
  176. package/dist/threads/automation.js +27 -11
  177. package/dist/tsconfig.build.tsbuildinfo +1 -1
  178. package/dist/utilities/fileSystem/index.js +1 -2
  179. package/package.json +8 -8
  180. package/src/api/controllers/row/internal.js +15 -1
  181. package/src/api/controllers/row/internalSearch.js +3 -45
  182. package/src/api/controllers/row/utils.js +1 -4
  183. package/src/api/controllers/static/index.ts +1 -5
  184. package/src/api/controllers/table/external.js +1 -1
  185. package/src/api/routes/static.ts +0 -11
  186. package/src/api/routes/tests/row.spec.js +149 -67
  187. package/src/automations/bullboard.js +2 -0
  188. package/src/automations/listeners.ts +78 -0
  189. package/src/automations/logging/index.ts +0 -3
  190. package/src/automations/utils.ts +7 -6
  191. package/src/integrations/base/sql.ts +30 -67
  192. package/src/integrations/base/utils.ts +18 -9
  193. package/src/integrations/microsoftSqlServer.ts +2 -3
  194. package/src/integrations/mongodb.ts +8 -35
  195. package/src/integrations/mysql.ts +1 -1
  196. package/src/integrations/postgres.ts +1 -2
  197. package/src/integrations/tests/mongo.spec.js +0 -218
  198. package/src/integrations/tests/sql.spec.js +11 -101
  199. package/src/threads/automation.ts +35 -16
  200. package/src/utilities/fileSystem/index.js +0 -2
  201. package/builder/assets/index.6b1c808b.css +0 -6
  202. package/builder/assets/index.7e1eb5c8.js +0 -977
  203. package/dist/integrations/base/query.js +0 -27
  204. package/src/api/routes/tests/internalSearch.spec.js +0 -176
  205. package/src/integrations/base/query.ts +0 -16
@@ -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, deleteFiles, } = require("./utilities");
17
+ const { upload, retrieve, retrieveToTmp, streamUpload, deleteFolder, downloadTarball, } = 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");
@@ -289,6 +289,5 @@ exports.cleanup = appIds => {
289
289
  exports.upload = upload;
290
290
  exports.retrieve = retrieve;
291
291
  exports.retrieveToTmp = retrieveToTmp;
292
- exports.deleteFiles = deleteFiles;
293
292
  exports.TOP_LEVEL_PATH = TOP_LEVEL_PATH;
294
293
  exports.NODE_MODULES_PATH = NODE_MODULES_PATH;
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.44-alpha.0",
4
+ "version": "1.2.46",
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.44-alpha.0",
81
- "@budibase/client": "1.2.44-alpha.0",
82
- "@budibase/pro": "1.2.43",
83
- "@budibase/string-templates": "1.2.44-alpha.0",
84
- "@budibase/types": "1.2.44-alpha.0",
80
+ "@budibase/backend-core": "^1.2.46",
81
+ "@budibase/client": "^1.2.46",
82
+ "@budibase/pro": "1.2.45",
83
+ "@budibase/string-templates": "^1.2.46",
84
+ "@budibase/types": "^1.2.46",
85
85
  "@bull-board/api": "3.7.0",
86
86
  "@bull-board/koa": "3.9.4",
87
87
  "@elastic/elasticsearch": "7.10.0",
@@ -106,7 +106,7 @@
106
106
  "google-auth-library": "7.12.0",
107
107
  "google-spreadsheet": "3.2.0",
108
108
  "jimp": "0.16.1",
109
- "joi": "17.6.0",
109
+ "joi": "17.2.1",
110
110
  "js-yaml": "4.1.0",
111
111
  "jsonschema": "1.4.0",
112
112
  "knex": "0.95.15",
@@ -195,5 +195,5 @@
195
195
  "optionalDependencies": {
196
196
  "oracledb": "5.3.0"
197
197
  },
198
- "gitHead": "a9aebf552f8f7e69aa0afa1d88c6f090a609f470"
198
+ "gitHead": "9c20cb857b8fd3caa99fab0c926c32bc2189deaa"
199
199
  }
@@ -375,6 +375,7 @@ exports.exportRows = async ctx => {
375
375
  const table = await db.get(ctx.params.tableId)
376
376
  const rowIds = ctx.request.body.rows
377
377
  let format = ctx.query.format
378
+ const { columns } = ctx.request.body
378
379
  let response = (
379
380
  await db.allDocs({
380
381
  include_docs: true,
@@ -382,7 +383,20 @@ exports.exportRows = async ctx => {
382
383
  })
383
384
  ).rows.map(row => row.doc)
384
385
 
385
- let rows = await outputProcessing(table, response)
386
+ let result = await outputProcessing(table, response)
387
+ let rows = []
388
+
389
+ // Filter data to only specified columns if required
390
+ if (columns && columns.length) {
391
+ for (let i = 0; i < result.length; i++) {
392
+ rows[i] = {}
393
+ for (let column of columns) {
394
+ rows[i][column] = result[i][column]
395
+ }
396
+ }
397
+ } else {
398
+ rows = result
399
+ }
386
400
 
387
401
  let headers = Object.keys(rows[0])
388
402
  const exporter = exporters[format]
@@ -1,5 +1,4 @@
1
1
  const { SearchIndexes } = require("../../../db/utils")
2
- const { removeKeyNumbering } = require("./utils")
3
2
  const fetch = require("node-fetch")
4
3
  const { getCouchInfo } = require("@budibase/backend-core/db")
5
4
  const { getAppId } = require("@budibase/backend-core/context")
@@ -21,8 +20,6 @@ class QueryBuilder {
21
20
  notEmpty: {},
22
21
  oneOf: {},
23
22
  contains: {},
24
- notContains: {},
25
- containsAny: {},
26
23
  ...base,
27
24
  }
28
25
  this.limit = 50
@@ -128,16 +125,6 @@ class QueryBuilder {
128
125
  return this
129
126
  }
130
127
 
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
-
141
128
  /**
142
129
  * Preprocesses a value before going into a lucene search.
143
130
  * Transforms strings to lowercase and wraps strings and bools in quotes.
@@ -183,29 +170,11 @@ class QueryBuilder {
183
170
  return `${key}:${builder.preprocess(value, allPreProcessingOpts)}`
184
171
  }
185
172
 
186
- const contains = (key, value, mode = "AND") => {
187
- if (Array.isArray(value) && value.length === 0) {
173
+ const contains = (key, value) => {
174
+ if (!value && value !== 0) {
188
175
  return null
189
176
  }
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")
177
+ return `${key}:${builder.preprocess(value, { escape: true })}`
209
178
  }
210
179
 
211
180
  const oneOf = (key, value) => {
@@ -228,8 +197,6 @@ class QueryBuilder {
228
197
 
229
198
  function build(structure, queryFn) {
230
199
  for (let [key, value] of Object.entries(structure)) {
231
- // check for new format - remove numbering if needed
232
- key = removeKeyNumbering(key)
233
200
  key = builder.preprocess(key.replace(/ /g, "_"), {
234
201
  escape: true,
235
202
  })
@@ -308,12 +275,6 @@ class QueryBuilder {
308
275
  if (this.query.contains) {
309
276
  build(this.query.contains, contains)
310
277
  }
311
- if (this.query.notContains) {
312
- build(this.query.notContains, notContains)
313
- }
314
- if (this.query.containsAny) {
315
- build(this.query.containsAny, containsAny)
316
- }
317
278
  // make sure table ID is always added as an AND
318
279
  if (tableId) {
319
280
  query = `(${query})`
@@ -349,9 +310,6 @@ class QueryBuilder {
349
310
  }
350
311
  }
351
312
 
352
- // exported for unit testing
353
- exports.QueryBuilder = QueryBuilder
354
-
355
313
  /**
356
314
  * Executes a lucene search query.
357
315
  * @param url The query URL
@@ -3,9 +3,8 @@ 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")
6
7
  const { getAppDB } = require("@budibase/backend-core/context")
7
- const { makeExternalQuery } = require("../../../integrations/base/query")
8
- const { removeKeyNumbering } = require("../../../integrations/base/utils")
9
8
 
10
9
  validateJs.extend(validateJs.validators.datetime, {
11
10
  parse: function (value) {
@@ -17,8 +16,6 @@ validateJs.extend(validateJs.validators.datetime, {
17
16
  },
18
17
  })
19
18
 
20
- exports.removeKeyNumbering = removeKeyNumbering
21
-
22
19
  exports.getDatasourceAndQuery = async json => {
23
20
  const datasourceId = json.endpoint.datasourceId
24
21
  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, deleteFiles } = require("../../../utilities/fileSystem")
15
+ const { upload } = 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,10 +97,6 @@ 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
-
104
100
  export const serveApp = async function (ctx: any) {
105
101
  const db = getAppDB({ skip_setup: true })
106
102
  const appInfo = await db.get(DocumentType.APP_METADATA)
@@ -14,7 +14,7 @@ const {
14
14
  FieldTypes,
15
15
  RelationshipTypes,
16
16
  } = require("../../../constants")
17
- const { makeExternalQuery } = require("../../../integrations/base/query")
17
+ const { makeExternalQuery } = require("../../../integrations/base/utils")
18
18
  const { cloneDeep } = require("lodash/fp")
19
19
  const csvParser = require("../../../utilities/csvParser")
20
20
  const { handleRequest } = require("../row/external")
@@ -38,11 +38,6 @@ 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
- )
46
41
  .post("/api/beta/:feature", controller.toggleBetaUiFeature)
47
42
  .post(
48
43
  "/api/attachments/:tableId/upload",
@@ -50,12 +45,6 @@ router
50
45
  authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
51
46
  controller.uploadFile
52
47
  )
53
- .post(
54
- "/api/attachments/:tableId/delete",
55
- paramResource("tableId"),
56
- authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
57
- controller.deleteObjects
58
- )
59
48
  .get("/:appId/:path*", controller.serveApp)
60
49
  .get("/app/:appUrl/:path*", controller.serveApp)
61
50
  .post(
@@ -3,7 +3,12 @@ const setup = require("./utilities")
3
3
  const { basicRow } = setup.structures
4
4
  const { doInAppContext } = require("@budibase/backend-core/context")
5
5
  const { doInTenant } = require("@budibase/backend-core/tenancy")
6
- const { quotas, QuotaUsageType, StaticQuotaName, MonthlyQuotaName } = require("@budibase/pro")
6
+ const {
7
+ quotas,
8
+ QuotaUsageType,
9
+ StaticQuotaName,
10
+ MonthlyQuotaName,
11
+ } = require("@budibase/pro")
7
12
 
8
13
  describe("/rows", () => {
9
14
  let request = setup.getRequest()
@@ -23,23 +28,30 @@ describe("/rows", () => {
23
28
  await request
24
29
  .get(`/api/${table._id}/rows/${id}`)
25
30
  .set(config.defaultHeaders())
26
- .expect('Content-Type', /json/)
31
+ .expect("Content-Type", /json/)
27
32
  .expect(status)
28
33
 
29
34
  const getRowUsage = async () => {
30
- return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS))
35
+ return config.doInContext(null, () =>
36
+ quotas.getCurrentUsageValue(QuotaUsageType.STATIC, StaticQuotaName.ROWS)
37
+ )
31
38
  }
32
39
 
33
40
  const getQueryUsage = async () => {
34
- return config.doInContext(null, () => quotas.getCurrentUsageValue(QuotaUsageType.MONTHLY, MonthlyQuotaName.QUERIES))
41
+ return config.doInContext(null, () =>
42
+ quotas.getCurrentUsageValue(
43
+ QuotaUsageType.MONTHLY,
44
+ MonthlyQuotaName.QUERIES
45
+ )
46
+ )
35
47
  }
36
48
 
37
- const assertRowUsage = async (expected) => {
49
+ const assertRowUsage = async expected => {
38
50
  const usage = await getRowUsage()
39
51
  expect(usage).toBe(expected)
40
52
  }
41
53
 
42
- const assertQueryUsage = async (expected) => {
54
+ const assertQueryUsage = async expected => {
43
55
  const usage = await getQueryUsage()
44
56
  expect(usage).toBe(expected)
45
57
  }
@@ -76,10 +88,12 @@ describe("/rows", () => {
76
88
  name: "Updated Name",
77
89
  })
78
90
  .set(config.defaultHeaders())
79
- .expect('Content-Type', /json/)
91
+ .expect("Content-Type", /json/)
80
92
  .expect(200)
81
93
 
82
- expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
94
+ expect(res.res.statusMessage).toEqual(
95
+ `${table.name} updated successfully.`
96
+ )
83
97
  expect(res.body.name).toEqual("Updated Name")
84
98
  // await assertRowUsage(rowUsage)
85
99
  // await assertQueryUsage(queryUsage + 1)
@@ -92,7 +106,7 @@ describe("/rows", () => {
92
106
  const res = await request
93
107
  .get(`/api/${table._id}/rows/${existing._id}`)
94
108
  .set(config.defaultHeaders())
95
- .expect('Content-Type', /json/)
109
+ .expect("Content-Type", /json/)
96
110
  .expect(200)
97
111
 
98
112
  expect(res.body).toEqual({
@@ -110,7 +124,7 @@ describe("/rows", () => {
110
124
  const newRow = {
111
125
  tableId: table._id,
112
126
  name: "Second Contact",
113
- status: "new"
127
+ status: "new",
114
128
  }
115
129
  await config.createRow()
116
130
  await config.createRow(newRow)
@@ -119,7 +133,7 @@ describe("/rows", () => {
119
133
  const res = await request
120
134
  .get(`/api/${table._id}/rows`)
121
135
  .set(config.defaultHeaders())
122
- .expect('Content-Type', /json/)
136
+ .expect("Content-Type", /json/)
123
137
  .expect(200)
124
138
 
125
139
  expect(res.body.length).toBe(2)
@@ -135,17 +149,36 @@ describe("/rows", () => {
135
149
  await request
136
150
  .get(`/api/${table._id}/rows/not-a-valid-id`)
137
151
  .set(config.defaultHeaders())
138
- .expect('Content-Type', /json/)
152
+ .expect("Content-Type", /json/)
139
153
  .expect(404)
140
154
  await assertQueryUsage(queryUsage) // no change
141
155
  })
142
156
 
143
157
  it("row values are coerced", async () => {
144
- const str = {type:"string", constraints: { type: "string", presence: false }}
145
- const attachment = {type:"attachment", constraints: { type: "array", presence: false }}
146
- const bool = {type:"boolean", constraints: { type: "boolean", presence: false }}
147
- const number = {type:"number", constraints: { type: "number", presence: false }}
148
- const datetime = {type:"datetime", constraints: { type: "string", presence: false, datetime: {earliest:"", latest: ""} }}
158
+ const str = {
159
+ type: "string",
160
+ constraints: { type: "string", presence: false },
161
+ }
162
+ const attachment = {
163
+ type: "attachment",
164
+ constraints: { type: "array", presence: false },
165
+ }
166
+ const bool = {
167
+ type: "boolean",
168
+ constraints: { type: "boolean", presence: false },
169
+ }
170
+ const number = {
171
+ type: "number",
172
+ constraints: { type: "number", presence: false },
173
+ }
174
+ const datetime = {
175
+ type: "datetime",
176
+ constraints: {
177
+ type: "string",
178
+ presence: false,
179
+ datetime: { earliest: "", latest: "" },
180
+ },
181
+ }
149
182
 
150
183
  table = await config.createTable({
151
184
  name: "TestTable2",
@@ -171,9 +204,9 @@ describe("/rows", () => {
171
204
  boolUndefined: bool,
172
205
  boolString: bool,
173
206
  boolBool: bool,
174
- attachmentNull : attachment,
175
- attachmentUndefined : attachment,
176
- attachmentEmpty : attachment,
207
+ attachmentNull: attachment,
208
+ attachmentUndefined: attachment,
209
+ attachmentEmpty: attachment,
177
210
  },
178
211
  })
179
212
 
@@ -198,9 +231,9 @@ describe("/rows", () => {
198
231
  boolString: "true",
199
232
  boolBool: true,
200
233
  tableId: table._id,
201
- attachmentNull : null,
202
- attachmentUndefined : undefined,
203
- attachmentEmpty : "",
234
+ attachmentNull: null,
235
+ attachmentUndefined: undefined,
236
+ attachmentEmpty: "",
204
237
  }
205
238
 
206
239
  const id = (await config.createRow(row))._id
@@ -218,7 +251,9 @@ describe("/rows", () => {
218
251
  expect(saved.datetimeEmptyString).toBe(null)
219
252
  expect(saved.datetimeNull).toBe(null)
220
253
  expect(saved.datetimeUndefined).toBe(undefined)
221
- expect(saved.datetimeString).toBe(new Date(row.datetimeString).toISOString())
254
+ expect(saved.datetimeString).toBe(
255
+ new Date(row.datetimeString).toISOString()
256
+ )
222
257
  expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString())
223
258
  expect(saved.boolNull).toBe(null)
224
259
  expect(saved.boolEmpty).toBe(null)
@@ -247,10 +282,12 @@ describe("/rows", () => {
247
282
  name: "Updated Name",
248
283
  })
249
284
  .set(config.defaultHeaders())
250
- .expect('Content-Type', /json/)
285
+ .expect("Content-Type", /json/)
251
286
  .expect(200)
252
-
253
- expect(res.res.statusMessage).toEqual(`${table.name} updated successfully.`)
287
+
288
+ expect(res.res.statusMessage).toEqual(
289
+ `${table.name} updated successfully.`
290
+ )
254
291
  expect(res.body.name).toEqual("Updated Name")
255
292
  expect(res.body.description).toEqual(existing.description)
256
293
 
@@ -292,16 +329,14 @@ describe("/rows", () => {
292
329
  const res = await request
293
330
  .delete(`/api/${table._id}/rows`)
294
331
  .send({
295
- rows: [
296
- createdRow
297
- ]
332
+ rows: [createdRow],
298
333
  })
299
334
  .set(config.defaultHeaders())
300
- .expect('Content-Type', /json/)
335
+ .expect("Content-Type", /json/)
301
336
  .expect(200)
302
337
  expect(res.body[0]._id).toEqual(createdRow._id)
303
- await assertRowUsage(rowUsage -1)
304
- await assertQueryUsage(queryUsage +1)
338
+ await assertRowUsage(rowUsage - 1)
339
+ await assertQueryUsage(queryUsage + 1)
305
340
  })
306
341
  })
307
342
 
@@ -314,9 +349,9 @@ describe("/rows", () => {
314
349
  .post(`/api/${table._id}/rows/validate`)
315
350
  .send({ name: "ivan" })
316
351
  .set(config.defaultHeaders())
317
- .expect('Content-Type', /json/)
352
+ .expect("Content-Type", /json/)
318
353
  .expect(200)
319
-
354
+
320
355
  expect(res.body.valid).toBe(true)
321
356
  expect(Object.keys(res.body.errors)).toEqual([])
322
357
  await assertRowUsage(rowUsage)
@@ -331,9 +366,9 @@ describe("/rows", () => {
331
366
  .post(`/api/${table._id}/rows/validate`)
332
367
  .send({ name: 1 })
333
368
  .set(config.defaultHeaders())
334
- .expect('Content-Type', /json/)
369
+ .expect("Content-Type", /json/)
335
370
  .expect(200)
336
-
371
+
337
372
  expect(res.body.valid).toBe(false)
338
373
  expect(Object.keys(res.body.errors)).toEqual(["name"])
339
374
  await assertRowUsage(rowUsage)
@@ -351,19 +386,16 @@ describe("/rows", () => {
351
386
  const res = await request
352
387
  .delete(`/api/${table._id}/rows`)
353
388
  .send({
354
- rows: [
355
- row1,
356
- row2,
357
- ]
389
+ rows: [row1, row2],
358
390
  })
359
391
  .set(config.defaultHeaders())
360
- .expect('Content-Type', /json/)
392
+ .expect("Content-Type", /json/)
361
393
  .expect(200)
362
394
 
363
395
  expect(res.body.length).toEqual(2)
364
396
  await loadRow(row1._id, 404)
365
397
  await assertRowUsage(rowUsage - 2)
366
- await assertQueryUsage(queryUsage +1)
398
+ await assertQueryUsage(queryUsage + 1)
367
399
  })
368
400
  })
369
401
 
@@ -376,12 +408,12 @@ describe("/rows", () => {
376
408
  const res = await request
377
409
  .get(`/api/views/${table._id}`)
378
410
  .set(config.defaultHeaders())
379
- .expect('Content-Type', /json/)
411
+ .expect("Content-Type", /json/)
380
412
  .expect(200)
381
413
  expect(res.body.length).toEqual(1)
382
414
  expect(res.body[0]._id).toEqual(row._id)
383
415
  await assertRowUsage(rowUsage)
384
- await assertQueryUsage(queryUsage +1)
416
+ await assertQueryUsage(queryUsage + 1)
385
417
  })
386
418
 
387
419
  it("should throw an error if view doesn't exist", async () => {
@@ -406,7 +438,7 @@ describe("/rows", () => {
406
438
  const res = await request
407
439
  .get(`/api/views/${view.name}`)
408
440
  .set(config.defaultHeaders())
409
- .expect('Content-Type', /json/)
441
+ .expect("Content-Type", /json/)
410
442
  .expect(200)
411
443
  expect(res.body.length).toEqual(1)
412
444
  expect(res.body[0]._id).toEqual(row._id)
@@ -418,21 +450,24 @@ describe("/rows", () => {
418
450
 
419
451
  describe("fetchEnrichedRows", () => {
420
452
  it("should allow enriching some linked rows", async () => {
421
- const { table, firstRow, secondRow } = await doInTenant(setup.structures.TENANT_ID, async () => {
422
- const table = await config.createLinkedTable()
423
- const firstRow = await config.createRow({
424
- name: "Test Contact",
425
- description: "original description",
426
- tableId: table._id
427
- })
428
- const secondRow = await config.createRow({
429
- name: "Test 2",
430
- description: "og desc",
431
- link: [{_id: firstRow._id}],
432
- tableId: table._id,
433
- })
434
- return { table, firstRow, secondRow }
435
- })
453
+ const { table, firstRow, secondRow } = await doInTenant(
454
+ setup.structures.TENANT_ID,
455
+ async () => {
456
+ const table = await config.createLinkedTable()
457
+ const firstRow = await config.createRow({
458
+ name: "Test Contact",
459
+ description: "original description",
460
+ tableId: table._id,
461
+ })
462
+ const secondRow = await config.createRow({
463
+ name: "Test 2",
464
+ description: "og desc",
465
+ link: [{ _id: firstRow._id }],
466
+ tableId: table._id,
467
+ })
468
+ return { table, firstRow, secondRow }
469
+ }
470
+ )
436
471
  const rowUsage = await getRowUsage()
437
472
  const queryUsage = await getQueryUsage()
438
473
 
@@ -440,7 +475,7 @@ describe("/rows", () => {
440
475
  const resBasic = await request
441
476
  .get(`/api/${table._id}/rows/${secondRow._id}`)
442
477
  .set(config.defaultHeaders())
443
- .expect('Content-Type', /json/)
478
+ .expect("Content-Type", /json/)
444
479
  .expect(200)
445
480
  expect(resBasic.body.link[0]._id).toBe(firstRow._id)
446
481
  expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact")
@@ -449,14 +484,14 @@ describe("/rows", () => {
449
484
  const resEnriched = await request
450
485
  .get(`/api/${table._id}/${secondRow._id}/enrich`)
451
486
  .set(config.defaultHeaders())
452
- .expect('Content-Type', /json/)
487
+ .expect("Content-Type", /json/)
453
488
  .expect(200)
454
489
  expect(resEnriched.body.link.length).toBe(1)
455
490
  expect(resEnriched.body.link[0]._id).toBe(firstRow._id)
456
491
  expect(resEnriched.body.link[0].name).toBe("Test Contact")
457
492
  expect(resEnriched.body.link[0].description).toBe("original description")
458
493
  await assertRowUsage(rowUsage)
459
- await assertQueryUsage(queryUsage +2)
494
+ await assertQueryUsage(queryUsage + 2)
460
495
  })
461
496
  })
462
497
 
@@ -466,9 +501,11 @@ describe("/rows", () => {
466
501
  const row = await config.createRow({
467
502
  name: "test",
468
503
  description: "test",
469
- attachment: [{
470
- key: `${config.getAppId()}/attachments/test/thing.csv`,
471
- }],
504
+ attachment: [
505
+ {
506
+ key: `${config.getAppId()}/attachments/test/thing.csv`,
507
+ },
508
+ ],
472
509
  tableId: table._id,
473
510
  })
474
511
  // the environment needs configured for this
@@ -482,4 +519,49 @@ describe("/rows", () => {
482
519
  })
483
520
  })
484
521
  })
522
+
523
+ describe("exportData", () => {
524
+ it("should allow exporting all columns", async () => {
525
+ const existing = await config.createRow()
526
+ const res = await request
527
+ .post(`/api/${table._id}/rows/exportRows?format=json`)
528
+ .set(config.defaultHeaders())
529
+ .send({
530
+ rows: [existing._id],
531
+ })
532
+ .expect("Content-Type", /json/)
533
+ .expect(200)
534
+ const results = JSON.parse(res.text)
535
+ expect(results.length).toEqual(1)
536
+ const row = results[0]
537
+
538
+ // Ensure all original columns were exported
539
+ expect(Object.keys(row).length).toBeGreaterThanOrEqual(
540
+ Object.keys(existing).length
541
+ )
542
+ Object.keys(existing).forEach(key => {
543
+ expect(row[key]).toEqual(existing[key])
544
+ })
545
+ })
546
+
547
+ it("should allow exporting only certain columns", async () => {
548
+ const existing = await config.createRow()
549
+ const res = await request
550
+ .post(`/api/${table._id}/rows/exportRows?format=json`)
551
+ .set(config.defaultHeaders())
552
+ .send({
553
+ rows: [existing._id],
554
+ columns: ["_id"],
555
+ })
556
+ .expect("Content-Type", /json/)
557
+ .expect(200)
558
+ const results = JSON.parse(res.text)
559
+ expect(results.length).toEqual(1)
560
+ const row = results[0]
561
+
562
+ // Ensure only the _id column was exported
563
+ expect(Object.keys(row).length).toEqual(1)
564
+ expect(row._id).toEqual(existing._id)
565
+ })
566
+ })
485
567
  })
@@ -8,12 +8,14 @@ const Queue = env.isTest()
8
8
  const { JobQueues } = require("../constants")
9
9
  const { utils } = require("@budibase/backend-core/redis")
10
10
  const { opts, redisProtocolUrl } = utils.getRedisOptions()
11
+ const listeners = require("./listeners")
11
12
 
12
13
  const CLEANUP_PERIOD_MS = 60 * 1000
13
14
  const queueConfig = redisProtocolUrl || { redis: opts }
14
15
  let cleanupInternal = null
15
16
 
16
17
  let automationQueue = new Queue(JobQueues.AUTOMATIONS, queueConfig)
18
+ listeners.addListeners(automationQueue)
17
19
 
18
20
  async function cleanup() {
19
21
  await automationQueue.clean(CLEANUP_PERIOD_MS, "completed")