@budibase/server 2.0.33 → 2.0.34-alpha.1

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 (277) hide show
  1. package/__mocks__/mongodb.ts +1 -1
  2. package/builder/assets/backups-default.8c011f1b.png +0 -0
  3. package/builder/assets/{index.dfa4073c.css → index.b15ffe95.css} +2 -2
  4. package/builder/assets/{index.ce49a649.js → index.cf543543.js} +340 -332
  5. package/builder/index.html +2 -2
  6. package/coverage/clover.xml +635 -690
  7. package/coverage/coverage-final.json +34 -36
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/cloud.js.html +74 -62
  11. package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/dev.js.html +2 -2
  13. package/coverage/lcov-report/api/controllers/index.html +17 -32
  14. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  20. package/coverage/lcov-report/api/controllers/query/validation.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  25. package/coverage/lcov-report/api/controllers/row/internal.js.html +12 -12
  26. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +15 -15
  28. package/coverage/lcov-report/api/controllers/row/utils.js.html +13 -13
  29. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +12 -9
  31. package/coverage/lcov-report/api/controllers/table/external.js.html +10 -10
  32. package/coverage/lcov-report/api/controllers/table/index.html +16 -16
  33. package/coverage/lcov-report/api/controllers/table/index.js.html +5 -5
  34. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  38. package/coverage/lcov-report/api/controllers/view/index.js.html +3 -3
  39. package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
  40. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  42. package/coverage/lcov-report/api/index.html +1 -1
  43. package/coverage/lcov-report/api/index.js.html +7 -7
  44. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  45. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  46. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  47. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/index.html +5 -20
  53. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/utils/index.html +1 -1
  67. package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  70. package/coverage/lcov-report/automations/actions.js.html +1 -1
  71. package/coverage/lcov-report/automations/automationUtils.js.html +6 -6
  72. package/coverage/lcov-report/automations/bullboard.js.html +17 -92
  73. package/coverage/lcov-report/automations/index.html +20 -20
  74. package/coverage/lcov-report/automations/index.js.html +9 -9
  75. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  76. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  77. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  78. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  79. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  80. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/index.html +1 -1
  82. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/loop.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  87. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/updateRow.js.html +3 -3
  90. package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  92. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  93. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  94. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  95. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  96. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  97. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  100. package/coverage/lcov-report/automations/triggers.js.html +30 -30
  101. package/coverage/lcov-report/constants/index.html +5 -5
  102. package/coverage/lcov-report/constants/index.js.html +10 -16
  103. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  104. package/coverage/lcov-report/constants/screens.js.html +1 -1
  105. package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
  106. package/coverage/lcov-report/db/index.html +19 -19
  107. package/coverage/lcov-report/db/index.js.html +1 -1
  108. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +11 -11
  109. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  110. package/coverage/lcov-report/db/linkedRows/index.js.html +11 -11
  111. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +3 -3
  112. package/coverage/lcov-report/db/newid.js.html +2 -2
  113. package/coverage/lcov-report/db/utils.js.html +37 -316
  114. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  115. package/coverage/lcov-report/events/index.html +1 -1
  116. package/coverage/lcov-report/events/index.js.html +2 -2
  117. package/coverage/lcov-report/events/utils.js.html +9 -9
  118. package/coverage/lcov-report/index.html +77 -77
  119. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  120. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  121. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  122. package/coverage/lcov-report/middleware/builder.js.html +11 -11
  123. package/coverage/lcov-report/middleware/currentapp.js.html +34 -34
  124. package/coverage/lcov-report/middleware/index.html +1 -1
  125. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  126. package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
  127. package/coverage/lcov-report/middleware/resourceId.js.html +7 -7
  128. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  129. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  130. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  131. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  132. package/coverage/lcov-report/utilities/csvParser.js.html +11 -8
  133. package/coverage/lcov-report/utilities/global.js.html +16 -16
  134. package/coverage/lcov-report/utilities/index.html +15 -15
  135. package/coverage/lcov-report/utilities/index.js.html +7 -7
  136. package/coverage/lcov-report/utilities/plugins.js.html +1 -1
  137. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +52 -52
  138. package/coverage/lcov-report/utilities/queue/index.html +21 -21
  139. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  140. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  141. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  142. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +54 -39
  143. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
  144. package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
  145. package/coverage/lcov-report/utilities/security.js.html +2 -2
  146. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  147. package/coverage/lcov-report/utilities/usageQuota/index.html +14 -14
  148. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +23 -11
  149. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
  150. package/coverage/lcov-report/utilities/users.js.html +1 -1
  151. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  152. package/coverage/lcov.info +1144 -1248
  153. package/dist/api/controllers/application.js +4 -7
  154. package/dist/api/controllers/backup.js +19 -13
  155. package/dist/api/controllers/cloud.js +38 -35
  156. package/dist/api/controllers/deploy/index.js +11 -2
  157. package/dist/api/controllers/dev.js +1 -1
  158. package/dist/api/controllers/query/index.js +7 -2
  159. package/dist/api/controllers/row/index.js +30 -10
  160. package/dist/api/controllers/static/index.js +2 -2
  161. package/dist/api/controllers/static/templates/preview.hbs +10 -0
  162. package/dist/api/controllers/table/bulkFormula.js +4 -3
  163. package/dist/api/controllers/table/external.js +5 -4
  164. package/dist/api/controllers/table/index.js +4 -4
  165. package/dist/api/controllers/table/internal.js +10 -3
  166. package/dist/api/controllers/table/utils.js +7 -49
  167. package/dist/api/controllers/view/index.js +2 -2
  168. package/dist/api/routes/backup.js +34 -7
  169. package/dist/api/routes/index.js +9 -4
  170. package/dist/app.js +18 -2
  171. package/dist/automations/automationUtils.js +2 -2
  172. package/dist/automations/bullboard.js +5 -33
  173. package/dist/automations/index.js +4 -4
  174. package/dist/automations/steps/updateRow.js +2 -2
  175. package/dist/automations/triggers.js +6 -6
  176. package/dist/automations/utils.js +18 -12
  177. package/dist/constants/index.js +4 -5
  178. package/dist/db/utils.js +10 -75
  179. package/dist/index.js +1 -0
  180. package/dist/integrations/arangodb.js +2 -0
  181. package/dist/integrations/base/sqlTable.js +1 -0
  182. package/dist/integrations/mongodb.js +300 -11
  183. package/dist/integrations/rest.js +38 -5
  184. package/dist/migrations/functions/backfill/app/tables.js +5 -8
  185. package/dist/migrations/functions/{quotas1.js → syncQuotas.js} +3 -7
  186. package/dist/migrations/functions/usageQuotas/syncApps.js +0 -1
  187. package/dist/migrations/functions/{pluginCount.js → usageQuotas/syncPlugins.js} +1 -3
  188. package/dist/migrations/functions/usageQuotas/syncRows.js +9 -5
  189. package/dist/migrations/index.js +10 -38
  190. package/dist/package.json +14 -14
  191. package/dist/sdk/app/backups/constants.js +5 -0
  192. package/dist/sdk/app/backups/exports.js +172 -0
  193. package/dist/sdk/app/backups/imports.js +162 -0
  194. package/dist/sdk/app/backups/index.js +29 -0
  195. package/dist/sdk/app/backups/statistics.js +73 -0
  196. package/dist/sdk/app/tables/index.js +61 -0
  197. package/dist/sdk/index.js +15 -0
  198. package/dist/tests/utilities/TestConfiguration.js +4 -2
  199. package/dist/threads/automation.js +12 -17
  200. package/dist/tsconfig.build.tsbuildinfo +1 -1
  201. package/dist/utilities/csvParser.js +1 -0
  202. package/dist/utilities/fileSystem/index.js +3 -95
  203. package/dist/utilities/fileSystem/utilities.js +2 -1
  204. package/dist/utilities/rowProcessor/index.js +5 -0
  205. package/dist/utilities/usageQuota/rows.js +6 -4
  206. package/package.json +15 -15
  207. package/specs/openapi.json +3 -0
  208. package/specs/openapi.yaml +3 -0
  209. package/src/api/controllers/application.ts +5 -12
  210. package/src/api/controllers/{backup.js → backup.ts} +7 -7
  211. package/src/api/controllers/cloud.js +44 -40
  212. package/src/api/controllers/deploy/index.ts +20 -8
  213. package/src/api/controllers/dev.js +1 -1
  214. package/src/api/controllers/query/index.ts +8 -2
  215. package/src/api/controllers/row/index.ts +36 -13
  216. package/src/api/controllers/static/index.ts +2 -2
  217. package/src/api/controllers/static/templates/preview.hbs +10 -0
  218. package/src/api/controllers/table/bulkFormula.js +4 -3
  219. package/src/api/controllers/table/external.js +4 -4
  220. package/src/api/controllers/table/index.js +4 -4
  221. package/src/api/controllers/table/internal.ts +8 -9
  222. package/src/api/controllers/table/utils.ts +4 -53
  223. package/src/api/controllers/view/index.js +2 -2
  224. package/src/api/routes/backup.ts +10 -0
  225. package/src/api/routes/index.ts +11 -5
  226. package/src/api/routes/tests/backup.spec.js +1 -1
  227. package/src/api/routes/tests/{deployment.spec.js → deployment.spec.ts} +4 -4
  228. package/src/api/routes/tests/row.spec.js +22 -27
  229. package/src/app.ts +19 -2
  230. package/src/automations/automationUtils.js +2 -2
  231. package/src/automations/bullboard.js +8 -33
  232. package/src/automations/index.js +4 -4
  233. package/src/automations/steps/updateRow.js +2 -2
  234. package/src/automations/tests/automation.spec.js +1 -6
  235. package/src/automations/triggers.js +6 -6
  236. package/src/automations/utils.ts +18 -12
  237. package/src/constants/index.js +4 -6
  238. package/src/db/utils.js +17 -110
  239. package/src/definitions/automations.ts +0 -12
  240. package/src/definitions/datasource.ts +1 -0
  241. package/src/index.ts +1 -0
  242. package/src/integrations/arangodb.ts +2 -0
  243. package/src/integrations/base/sqlTable.ts +1 -0
  244. package/src/integrations/mongodb.ts +290 -27
  245. package/src/integrations/rest.ts +17 -5
  246. package/src/integrations/tests/mongo.spec.ts +19 -19
  247. package/src/integrations/tests/rest.spec.ts +38 -22
  248. package/src/migrations/functions/backfill/app/tables.ts +7 -13
  249. package/src/migrations/functions/backfill/global.ts +1 -1
  250. package/src/migrations/functions/{quotas1.ts → syncQuotas.ts} +3 -8
  251. package/src/migrations/functions/tests/{quotas1.spec.js → syncQuotas.spec.js} +5 -2
  252. package/src/migrations/functions/usageQuotas/syncApps.ts +0 -1
  253. package/src/migrations/functions/usageQuotas/syncPlugins.ts +10 -0
  254. package/src/migrations/functions/usageQuotas/syncRows.ts +15 -6
  255. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +9 -1
  256. package/src/migrations/index.ts +21 -45
  257. package/src/migrations/tests/index.spec.ts +0 -1
  258. package/src/sdk/app/backups/constants.ts +2 -0
  259. package/src/sdk/app/backups/exports.ts +171 -0
  260. package/src/sdk/app/backups/imports.ts +169 -0
  261. package/src/sdk/app/backups/index.ts +9 -0
  262. package/src/sdk/app/backups/statistics.ts +78 -0
  263. package/src/sdk/app/tables/index.ts +61 -0
  264. package/src/sdk/index.ts +13 -0
  265. package/src/tests/utilities/TestConfiguration.js +5 -2
  266. package/src/threads/automation.ts +20 -27
  267. package/src/utilities/csvParser.js +1 -0
  268. package/src/utilities/fileSystem/index.js +2 -119
  269. package/src/utilities/fileSystem/utilities.js +2 -0
  270. package/src/utilities/rowProcessor/index.js +5 -0
  271. package/src/utilities/usageQuota/rows.js +7 -3
  272. package/coverage/lcov-report/api/controllers/backup.js.html +0 -142
  273. package/coverage/lcov-report/api/routes/backup.js.html +0 -115
  274. package/dist/automations/listeners.js +0 -102
  275. package/src/api/routes/backup.js +0 -10
  276. package/src/automations/listeners.ts +0 -78
  277. package/src/migrations/functions/pluginCount.ts +0 -12
@@ -1,17 +1,16 @@
1
- jest.mock("node-fetch", () =>
2
- jest.fn(() => ({
3
- headers: {
4
- raw: () => {
5
- return { "content-type": ["application/json"] }
6
- },
7
- get: () => ["application/json"],
1
+ const mockFetch = jest.fn(() => ({
2
+ headers: {
3
+ raw: () => {
4
+ return { "content-type": ["application/json"] }
8
5
  },
9
- json: jest.fn(() => ({
10
- my_next_cursor: 123,
11
- })),
12
- text: jest.fn(),
13
- }))
14
- )
6
+ get: () => ["application/json"],
7
+ },
8
+ json: jest.fn(() => ({
9
+ my_next_cursor: 123,
10
+ })),
11
+ text: jest.fn(),
12
+ }))
13
+ jest.mock("node-fetch", () => mockFetch)
15
14
  import fetch from "node-fetch"
16
15
  import { default as RestIntegration } from "../rest"
17
16
  const FormData = require("form-data")
@@ -256,7 +255,7 @@ describe("REST Integration", () => {
256
255
  authConfigId: "c59c14bd1898a43baa08da68959b24686",
257
256
  }
258
257
  await config.integration.read(query)
259
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/?`, {
258
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/`, {
260
259
  method: "GET",
261
260
  headers: {
262
261
  Authorization: "Basic dXNlcjpwYXNzd29yZA==",
@@ -269,7 +268,7 @@ describe("REST Integration", () => {
269
268
  authConfigId: "0d91d732f34e4befabeff50b392a8ff3",
270
269
  }
271
270
  await config.integration.read(query)
272
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/?`, {
271
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/`, {
273
272
  method: "GET",
274
273
  headers: {
275
274
  Authorization: "Bearer mytoken",
@@ -327,7 +326,7 @@ describe("REST Integration", () => {
327
326
  },
328
327
  }
329
328
  await config.integration.create(query)
330
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
329
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
331
330
  body: JSON.stringify({
332
331
  [pageParam]: pageValue,
333
332
  [sizeParam]: sizeValue,
@@ -359,7 +358,7 @@ describe("REST Integration", () => {
359
358
  },
360
359
  }
361
360
  await config.integration.create(query)
362
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
361
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
363
362
  body: expect.any(FormData),
364
363
  headers: {},
365
364
  method: "POST",
@@ -390,7 +389,7 @@ describe("REST Integration", () => {
390
389
  },
391
390
  }
392
391
  await config.integration.create(query)
393
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
392
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
394
393
  body: expect.any(URLSearchParams),
395
394
  headers: {},
396
395
  method: "POST",
@@ -456,7 +455,7 @@ describe("REST Integration", () => {
456
455
  },
457
456
  }
458
457
  const res = await config.integration.create(query)
459
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
458
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
460
459
  body: JSON.stringify({
461
460
  [pageParam]: pageValue,
462
461
  [sizeParam]: sizeValue,
@@ -490,7 +489,7 @@ describe("REST Integration", () => {
490
489
  },
491
490
  }
492
491
  const res = await config.integration.create(query)
493
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
492
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
494
493
  body: expect.any(FormData),
495
494
  headers: {},
496
495
  method: "POST",
@@ -523,7 +522,7 @@ describe("REST Integration", () => {
523
522
  },
524
523
  }
525
524
  const res = await config.integration.create(query)
526
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api?`, {
525
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/api`, {
527
526
  body: expect.any(URLSearchParams),
528
527
  headers: {},
529
528
  method: "POST",
@@ -563,7 +562,7 @@ describe("REST Integration", () => {
563
562
  legacyHttpParser: true,
564
563
  })
565
564
  await config.integration.read({})
566
- expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/?`, {
565
+ expect(fetch).toHaveBeenCalledWith(`${BASE_URL}/`, {
567
566
  method: "GET",
568
567
  headers: {},
569
568
  extraHttpOptions: {
@@ -572,4 +571,21 @@ describe("REST Integration", () => {
572
571
  })
573
572
  })
574
573
  })
574
+
575
+ it("Attaches custom agent when Reject Unauthorized option is false", async () => {
576
+ config = new TestConfiguration({
577
+ url: BASE_URL,
578
+ rejectUnauthorized: false,
579
+ })
580
+ await config.integration.read({})
581
+
582
+ const calls: any = mockFetch.mock.calls[0]
583
+ const url = calls[0]
584
+ expect(url).toBe(`${BASE_URL}/`)
585
+
586
+ const calledConfig = calls[1]
587
+ expect(calledConfig.method).toBe("GET")
588
+ expect(calledConfig.headers).toEqual({})
589
+ expect(calledConfig.agent.options.rejectUnauthorized).toBe(false)
590
+ })
575
591
  })
@@ -1,18 +1,12 @@
1
1
  import { events } from "@budibase/backend-core"
2
- import { getTableParams } from "../../../../db/utils"
3
- import { Table } from "@budibase/types"
2
+ import sdk from "../../../../sdk"
3
+ import PouchDB from "pouchdb"
4
4
 
5
- const getTables = async (appDb: any): Promise<Table[]> => {
6
- const response = await appDb.allDocs(
7
- getTableParams(null, {
8
- include_docs: true,
9
- })
10
- )
11
- return response.rows.map((row: any) => row.doc)
12
- }
13
-
14
- export const backfill = async (appDb: any, timestamp: string | number) => {
15
- const tables = await getTables(appDb)
5
+ export const backfill = async (
6
+ appDb: PouchDB.Database,
7
+ timestamp: string | number
8
+ ) => {
9
+ const tables = await sdk.tables.getAllInternalTables(appDb)
16
10
 
17
11
  for (const table of tables) {
18
12
  await events.table.created(table, timestamp)
@@ -8,7 +8,7 @@ import {
8
8
  accounts,
9
9
  db as dbUtils,
10
10
  } from "@budibase/backend-core"
11
- import { QuotaUsage } from "@budibase/pro"
11
+ import { QuotaUsage } from "@budibase/types"
12
12
  import {
13
13
  CloudAccount,
14
14
  App,
@@ -1,20 +1,15 @@
1
1
  import { runQuotaMigration } from "./usageQuotas"
2
2
  import * as syncApps from "./usageQuotas/syncApps"
3
3
  import * as syncRows from "./usageQuotas/syncRows"
4
+ import * as syncPlugins from "./usageQuotas/syncPlugins"
4
5
 
5
6
  /**
6
- * Date:
7
- * January 2022
8
- *
9
- * Description:
10
- * Synchronise the app and row quotas to the state of the db after it was
11
- * discovered that the quota resets were still in place and the row quotas
12
- * weren't being decremented correctly.
7
+ * Synchronise quotas to the state of the db.
13
8
  */
14
-
15
9
  export const run = async () => {
16
10
  await runQuotaMigration(async () => {
17
11
  await syncApps.run()
18
12
  await syncRows.run()
13
+ await syncPlugins.run()
19
14
  })
20
15
  }
@@ -2,11 +2,13 @@ const TestConfig = require("../../../tests/utilities/TestConfiguration")
2
2
 
3
3
  const syncApps = jest.fn()
4
4
  const syncRows = jest.fn()
5
+ const syncPlugins = jest.fn()
5
6
 
6
7
  jest.mock("../usageQuotas/syncApps", () => ({ run: syncApps }) )
7
8
  jest.mock("../usageQuotas/syncRows", () => ({ run: syncRows }) )
9
+ jest.mock("../usageQuotas/syncPlugins", () => ({ run: syncPlugins }) )
8
10
 
9
- const migration = require("../quotas1")
11
+ const migration = require("../syncQuotas")
10
12
 
11
13
  describe("run", () => {
12
14
  let config = new TestConfig(false)
@@ -17,9 +19,10 @@ describe("run", () => {
17
19
 
18
20
  afterAll(config.end)
19
21
 
20
- it("runs ", async () => {
22
+ it("run", async () => {
21
23
  await migration.run()
22
24
  expect(syncApps).toHaveBeenCalledTimes(1)
23
25
  expect(syncRows).toHaveBeenCalledTimes(1)
26
+ expect(syncPlugins).toHaveBeenCalledTimes(1)
24
27
  })
25
28
  })
@@ -5,7 +5,6 @@ import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
5
5
 
6
6
  export const run = async () => {
7
7
  // get app count
8
- // @ts-ignore
9
8
  const devApps = await getAllApps({ dev: true })
10
9
  const appCount = devApps ? devApps.length : 0
11
10
 
@@ -0,0 +1,10 @@
1
+ import { logging } from "@budibase/backend-core"
2
+ import { plugins } from "@budibase/pro"
3
+
4
+ export const run = async () => {
5
+ try {
6
+ await plugins.checkPluginQuotas()
7
+ } catch (err) {
8
+ logging.logAlert("Failed to update plugin quotas", err)
9
+ }
10
+ }
@@ -2,19 +2,28 @@ import { getTenantId } from "@budibase/backend-core/tenancy"
2
2
  import { getAllApps } from "@budibase/backend-core/db"
3
3
  import { getUniqueRows } from "../../../utilities/usageQuota/rows"
4
4
  import { quotas } from "@budibase/pro"
5
- import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
5
+ import { StaticQuotaName, QuotaUsageType } from "@budibase/types"
6
6
 
7
7
  export const run = async () => {
8
8
  // get all rows in all apps
9
- // @ts-ignore
10
9
  const allApps = await getAllApps({ all: true })
11
- // @ts-ignore
12
10
  const appIds = allApps ? allApps.map((app: { appId: any }) => app.appId) : []
13
- const rows = await getUniqueRows(appIds)
14
- const rowCount = rows ? rows.length : 0
11
+ const { appRows } = await getUniqueRows(appIds)
12
+
13
+ // get the counts per app
14
+ const counts: { [key: string]: number } = {}
15
+ let rowCount = 0
16
+ Object.entries(appRows).forEach(([appId, rows]) => {
17
+ counts[appId] = rows.length
18
+ rowCount += rows.length
19
+ })
15
20
 
16
21
  // sync row count
17
22
  const tenantId = getTenantId()
18
23
  console.log(`[Tenant: ${tenantId}] Syncing row count: ${rowCount}`)
19
- await quotas.setUsage(rowCount, StaticQuotaName.ROWS, QuotaUsageType.STATIC)
24
+ await quotas.setUsagePerApp(
25
+ counts,
26
+ StaticQuotaName.ROWS,
27
+ QuotaUsageType.STATIC
28
+ )
20
29
  }
@@ -2,6 +2,7 @@ import TestConfig from "../../../../tests/utilities/TestConfiguration"
2
2
  import * as syncRows from "../syncRows"
3
3
  import { quotas } from "@budibase/pro"
4
4
  import { QuotaUsageType, StaticQuotaName } from "@budibase/types"
5
+ const { getProdAppID } = require("@budibase/backend-core/db")
5
6
 
6
7
  describe("syncRows", () => {
7
8
  let config = new TestConfig(false)
@@ -22,10 +23,11 @@ describe("syncRows", () => {
22
23
  expect(usageDoc.usageQuota.rows).toEqual(300)
23
24
 
24
25
  // app 1
26
+ const app1 = config.app
25
27
  await config.createTable()
26
28
  await config.createRow()
27
29
  // app 2
28
- await config.createApp("second-app")
30
+ const app2 = await config.createApp("second-app")
29
31
  await config.createTable()
30
32
  await config.createRow()
31
33
  await config.createRow()
@@ -36,6 +38,12 @@ describe("syncRows", () => {
36
38
  // assert the migration worked
37
39
  usageDoc = await quotas.getQuotaUsage()
38
40
  expect(usageDoc.usageQuota.rows).toEqual(3)
41
+ expect(usageDoc.apps?.[getProdAppID(app1.appId)].usageQuota.rows).toEqual(
42
+ 1
43
+ )
44
+ expect(usageDoc.apps?.[getProdAppID(app2.appId)].usageQuota.rows).toEqual(
45
+ 2
46
+ )
39
47
  })
40
48
  })
41
49
  })
@@ -1,14 +1,18 @@
1
- import { migrations, redis } from "@budibase/backend-core"
2
- import { Migration, MigrationOptions, MigrationName } from "@budibase/types"
1
+ import { locks, migrations } from "@budibase/backend-core"
2
+ import {
3
+ Migration,
4
+ MigrationOptions,
5
+ MigrationName,
6
+ LockType,
7
+ LockName,
8
+ } from "@budibase/types"
3
9
  import env from "../environment"
4
10
 
5
11
  // migration functions
6
12
  import * as userEmailViewCasing from "./functions/userEmailViewCasing"
7
- import * as quota1 from "./functions/quotas1"
13
+ import * as syncQuotas from "./functions/syncQuotas"
8
14
  import * as appUrls from "./functions/appUrls"
9
15
  import * as backfill from "./functions/backfill"
10
- import * as pluginCount from "./functions/pluginCount"
11
-
12
16
  /**
13
17
  * Populate the migration function and additional configuration from
14
18
  * the static migration definitions.
@@ -26,10 +30,10 @@ export const buildMigrations = () => {
26
30
  })
27
31
  break
28
32
  }
29
- case MigrationName.QUOTAS_1: {
33
+ case MigrationName.SYNC_QUOTAS: {
30
34
  serverMigrations.push({
31
35
  ...definition,
32
- fn: quota1.run,
36
+ fn: syncQuotas.run,
33
37
  })
34
38
  break
35
39
  }
@@ -69,16 +73,6 @@ export const buildMigrations = () => {
69
73
  })
70
74
  break
71
75
  }
72
- case MigrationName.PLUGIN_COUNT: {
73
- if (env.SELF_HOSTED) {
74
- serverMigrations.push({
75
- ...definition,
76
- fn: pluginCount.run,
77
- silent: !!env.SELF_HOSTED,
78
- preventRetry: false,
79
- })
80
- }
81
- }
82
76
  }
83
77
  }
84
78
 
@@ -98,33 +92,15 @@ export const migrate = async (options?: MigrationOptions) => {
98
92
  }
99
93
 
100
94
  const migrateWithLock = async (options?: MigrationOptions) => {
101
- // get a new lock client
102
- const redlock = await redis.clients.getMigrationsRedlock()
103
- // lock for 15 minutes
104
- const ttl = 1000 * 60 * 15
105
-
106
- let migrationLock
107
-
108
- // acquire lock
109
- try {
110
- migrationLock = await redlock.lock("migrations", ttl)
111
- } catch (e: any) {
112
- if (e.name === "LockError") {
113
- return
114
- } else {
115
- throw e
95
+ await locks.doWithLock(
96
+ {
97
+ type: LockType.TRY_ONCE,
98
+ name: LockName.MIGRATIONS,
99
+ ttl: 1000 * 60 * 15, // auto expire the migration lock after 15 minutes
100
+ systemLock: true,
101
+ },
102
+ async () => {
103
+ await migrations.runMigrations(MIGRATIONS, options)
116
104
  }
117
- }
118
-
119
- // run migrations
120
- try {
121
- await migrations.runMigrations(MIGRATIONS, options)
122
- } finally {
123
- // release lock
124
- try {
125
- await migrationLock.unlock()
126
- } catch (e) {
127
- console.error("unable to release migration lock")
128
- }
129
- }
105
+ )
130
106
  }
@@ -4,7 +4,6 @@ import {
4
4
  tenancy,
5
5
  DocumentType,
6
6
  context,
7
- db,
8
7
  } from "@budibase/backend-core"
9
8
  import TestConfig from "../../tests/utilities/TestConfiguration"
10
9
  import structures from "../../tests/utilities/structures"
@@ -0,0 +1,2 @@
1
+ export const DB_EXPORT_FILE = "db.txt"
2
+ export const GLOBAL_DB_EXPORT_FILE = "global.txt"
@@ -0,0 +1,171 @@
1
+ import { db as dbCore } from "@budibase/backend-core"
2
+ import { budibaseTempDir } from "../../../utilities/budibaseDir"
3
+ import { retrieveDirectory } from "../../../utilities/fileSystem/utilities"
4
+ import { streamFile, createTempFolder } from "../../../utilities/fileSystem"
5
+ import { ObjectStoreBuckets } from "../../../constants"
6
+ import {
7
+ LINK_USER_METADATA_PREFIX,
8
+ TABLE_ROW_PREFIX,
9
+ USER_METDATA_PREFIX,
10
+ } from "../../../db/utils"
11
+ import { DB_EXPORT_FILE, GLOBAL_DB_EXPORT_FILE } from "./constants"
12
+ import fs from "fs"
13
+ import { join } from "path"
14
+ import env from "../../../environment"
15
+ const uuid = require("uuid/v4")
16
+ const tar = require("tar")
17
+ const MemoryStream = require("memorystream")
18
+
19
+ type ExportOpts = {
20
+ filter?: any
21
+ exportPath?: string
22
+ tar?: boolean
23
+ excludeRows?: boolean
24
+ }
25
+
26
+ function tarFilesToTmp(tmpDir: string, files: string[]) {
27
+ const exportFile = join(budibaseTempDir(), `${uuid()}.tar.gz`)
28
+ tar.create(
29
+ {
30
+ sync: true,
31
+ gzip: true,
32
+ file: exportFile,
33
+ recursive: true,
34
+ cwd: tmpDir,
35
+ },
36
+ files
37
+ )
38
+ return exportFile
39
+ }
40
+
41
+ /**
42
+ * Exports a DB to either file or a variable (memory).
43
+ * @param {string} dbName the DB which is to be exported.
44
+ * @param {object} opts various options for the export, e.g. whether to stream,
45
+ * a filter function or the name of the export.
46
+ * @return {*} either a readable stream or a string
47
+ */
48
+ export async function exportDB(dbName: string, opts: ExportOpts = {}) {
49
+ return dbCore.doWithDB(dbName, async (db: any) => {
50
+ // Write the dump to file if required
51
+ if (opts?.exportPath) {
52
+ const path = opts?.exportPath
53
+ const writeStream = fs.createWriteStream(path)
54
+ await db.dump(writeStream, { filter: opts?.filter })
55
+ return path
56
+ } else {
57
+ // Stringify the dump in memory if required
58
+ const memStream = new MemoryStream()
59
+ let appString = ""
60
+ memStream.on("data", (chunk: any) => {
61
+ appString += chunk.toString()
62
+ })
63
+ await db.dump(memStream, { filter: opts?.filter })
64
+ return appString
65
+ }
66
+ })
67
+ }
68
+
69
+ function defineFilter(excludeRows?: boolean) {
70
+ const ids = [USER_METDATA_PREFIX, LINK_USER_METADATA_PREFIX]
71
+ if (excludeRows) {
72
+ ids.push(TABLE_ROW_PREFIX)
73
+ }
74
+ return (doc: any) =>
75
+ !ids.map(key => doc._id.includes(key)).reduce((prev, curr) => prev || curr)
76
+ }
77
+
78
+ /**
79
+ * Local utility to back up the database state for an app, excluding global user
80
+ * data or user relationships.
81
+ * @param {string} appId The app to back up
82
+ * @param {object} config Config to send to export DB/attachment export
83
+ * @returns {*} either a string or a stream of the backup
84
+ */
85
+ export async function exportApp(appId: string, config?: ExportOpts) {
86
+ const prodAppId = dbCore.getProdAppID(appId)
87
+ const appPath = `${prodAppId}/`
88
+ // export bucket contents
89
+ let tmpPath
90
+ if (!env.isTest()) {
91
+ tmpPath = await retrieveDirectory(ObjectStoreBuckets.APPS, appPath)
92
+ } else {
93
+ tmpPath = createTempFolder(uuid())
94
+ }
95
+ const downloadedPath = join(tmpPath, appPath)
96
+ if (fs.existsSync(downloadedPath)) {
97
+ const allFiles = fs.readdirSync(downloadedPath)
98
+ for (let file of allFiles) {
99
+ const path = join(downloadedPath, file)
100
+ // move out of app directory, simplify structure
101
+ fs.renameSync(path, join(downloadedPath, "..", file))
102
+ }
103
+ // remove the old app directory created by object export
104
+ fs.rmdirSync(downloadedPath)
105
+ }
106
+ // enforce an export of app DB to the tmp path
107
+ const dbPath = join(tmpPath, DB_EXPORT_FILE)
108
+ await exportDB(appId, {
109
+ ...config,
110
+ filter: defineFilter(config?.excludeRows),
111
+ exportPath: dbPath,
112
+ })
113
+ // if tar requested, return where the tarball is
114
+ if (config?.tar) {
115
+ // now the tmpPath contains both the DB export and attachments, tar this
116
+ const tarPath = tarFilesToTmp(tmpPath, fs.readdirSync(tmpPath))
117
+ // cleanup the tmp export files as tarball returned
118
+ fs.rmSync(tmpPath, { recursive: true, force: true })
119
+ return tarPath
120
+ }
121
+ // tar not requested, turn the directory where export is
122
+ else {
123
+ return tmpPath
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Export all apps + global DB (if supplied) to a single tarball, this includes
129
+ * the attachments for each app as well.
130
+ * @param {object[]} appMetadata The IDs and names of apps to export.
131
+ * @param {string} globalDbContents The contents of the global DB to export as well.
132
+ * @return {string} The path to the tarball.
133
+ */
134
+ export async function exportMultipleApps(
135
+ appMetadata: { appId: string; name: string }[],
136
+ globalDbContents?: string
137
+ ) {
138
+ const tmpPath = join(budibaseTempDir(), uuid())
139
+ fs.mkdirSync(tmpPath)
140
+ let exportPromises: Promise<void>[] = []
141
+ // export each app to a directory, then move it into the complete export
142
+ const exportAndMove = async (appId: string, appName: string) => {
143
+ const path = await exportApp(appId)
144
+ await fs.promises.rename(path, join(tmpPath, appName))
145
+ }
146
+ for (let metadata of appMetadata) {
147
+ exportPromises.push(exportAndMove(metadata.appId, metadata.name))
148
+ }
149
+ // wait for all exports to finish
150
+ await Promise.all(exportPromises)
151
+ // add the global DB contents
152
+ if (globalDbContents) {
153
+ fs.writeFileSync(join(tmpPath, GLOBAL_DB_EXPORT_FILE), globalDbContents)
154
+ }
155
+ const appNames = appMetadata.map(metadata => metadata.name)
156
+ const tarPath = tarFilesToTmp(tmpPath, [...appNames, GLOBAL_DB_EXPORT_FILE])
157
+ // clear up the tmp path now tarball generated
158
+ fs.rmSync(tmpPath, { recursive: true, force: true })
159
+ return tarPath
160
+ }
161
+
162
+ /**
163
+ * Streams a backup of the database state for an app
164
+ * @param {string} appId The ID of the app which is to be backed up.
165
+ * @param {boolean} excludeRows Flag to state whether the export should include data.
166
+ * @returns {*} a readable stream of the backup which is written in real time
167
+ */
168
+ export async function streamExportApp(appId: string, excludeRows: boolean) {
169
+ const tmpPath = await exportApp(appId, { excludeRows, tar: true })
170
+ return streamFile(tmpPath)
171
+ }