@budibase/server 1.0.46-alpha.1 → 1.0.46-alpha.5

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 (238) hide show
  1. package/builder/assets/{index.0df4f7ab.css → index.243ca52c.css} +1 -1
  2. package/builder/assets/{index.d109814f.js → index.298ba3d3.js} +184 -184
  3. package/builder/assets/{vendor.10e2ad1b.js → vendor.3bd2f661.js} +1 -1
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +1685 -1534
  6. package/coverage/coverage-final.json +98 -94
  7. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/application.js.html +192 -129
  10. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/automation.js.html +21 -21
  12. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  13. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  15. package/coverage/lcov-report/api/controllers/datasource.js.html +30 -30
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +19 -34
  18. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/layout.js.html +6 -6
  20. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
  22. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  23. package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
  24. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  25. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  26. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  27. package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
  28. package/coverage/lcov-report/api/controllers/row/index.html +1 -1
  29. package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
  30. package/coverage/lcov-report/api/controllers/row/internal.js.html +44 -44
  31. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +8 -8
  32. package/coverage/lcov-report/api/controllers/row/utils.js.html +25 -25
  33. package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
  34. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  35. package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
  36. package/coverage/lcov-report/api/controllers/table/index.html +16 -16
  37. package/coverage/lcov-report/api/controllers/table/index.js.html +25 -25
  38. package/coverage/lcov-report/api/controllers/table/internal.js.html +40 -34
  39. package/coverage/lcov-report/api/controllers/table/utils.js.html +76 -61
  40. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/user.js.html +20 -20
  42. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  43. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  44. package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
  45. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  46. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  47. package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
  48. package/coverage/lcov-report/api/index.html +1 -1
  49. package/coverage/lcov-report/api/index.js.html +10 -10
  50. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/index.html +7 -22
  62. package/coverage/lcov-report/api/routes/index.js.html +4 -10
  63. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/static.js.html +17 -2
  74. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  79. package/coverage/lcov-report/automations/actions.js.html +24 -24
  80. package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
  81. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  82. package/coverage/lcov-report/automations/index.html +1 -1
  83. package/coverage/lcov-report/automations/index.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  85. package/coverage/lcov-report/automations/steps/createRow.js.html +13 -19
  86. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  87. package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
  88. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  89. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  90. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  91. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  92. package/coverage/lcov-report/automations/steps/index.html +13 -13
  93. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  94. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  95. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  96. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  97. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  99. package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
  100. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  101. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  102. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  103. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  104. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  106. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  109. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggers.js.html +18 -18
  111. package/coverage/lcov-report/automations/utils.js.html +32 -32
  112. package/coverage/lcov-report/constants/index.html +1 -1
  113. package/coverage/lcov-report/constants/index.js.html +22 -22
  114. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  115. package/coverage/lcov-report/constants/screens.js.html +4 -4
  116. package/coverage/lcov-report/db/client.js.html +18 -18
  117. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  118. package/coverage/lcov-report/db/index.html +15 -15
  119. package/coverage/lcov-report/db/index.js.html +3 -3
  120. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
  121. package/coverage/lcov-report/db/linkedRows/index.html +1 -1
  122. package/coverage/lcov-report/db/linkedRows/index.js.html +31 -31
  123. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
  124. package/coverage/lcov-report/db/newid.js.html +4 -4
  125. package/coverage/lcov-report/db/utils.js.html +85 -85
  126. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  127. package/coverage/lcov-report/events/index.html +1 -1
  128. package/coverage/lcov-report/events/index.js.html +5 -5
  129. package/coverage/lcov-report/events/utils.js.html +3 -3
  130. package/coverage/lcov-report/index.html +99 -69
  131. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  132. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  133. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  134. package/coverage/lcov-report/middleware/authorized.js.html +11 -11
  135. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  136. package/coverage/lcov-report/middleware/currentapp.js.html +34 -61
  137. package/coverage/lcov-report/middleware/index.html +25 -25
  138. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  139. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  140. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  141. package/coverage/lcov-report/middleware/usageQuota.js.html +275 -41
  142. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  143. package/coverage/lcov-report/migrations/usageQuotas/index.html +141 -0
  144. package/coverage/lcov-report/migrations/usageQuotas/index.js.html +152 -0
  145. package/coverage/lcov-report/{api/routes/hosting.js.html → migrations/usageQuotas/syncApps.js.html} +42 -27
  146. package/coverage/lcov-report/{api/controllers/hosting.js.html → migrations/usageQuotas/syncRows.js.html} +41 -44
  147. package/coverage/lcov-report/threads/automation.js.html +1 -1
  148. package/coverage/lcov-report/threads/index.html +15 -15
  149. package/coverage/lcov-report/threads/index.js.html +10 -10
  150. package/coverage/lcov-report/threads/query.js.html +23 -8
  151. package/coverage/lcov-report/threads/utils.js.html +14 -14
  152. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  153. package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
  154. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  155. package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
  156. package/coverage/lcov-report/utilities/global.js.html +26 -26
  157. package/coverage/lcov-report/utilities/index.html +19 -19
  158. package/coverage/lcov-report/utilities/index.js.html +25 -25
  159. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
  160. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  161. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  162. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  163. package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +53 -53
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +10 -10
  166. package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
  167. package/coverage/lcov-report/utilities/security.js.html +8 -8
  168. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  169. package/coverage/lcov-report/utilities/usageQuota/index.html +141 -0
  170. package/coverage/lcov-report/utilities/usageQuota/index.js.html +356 -0
  171. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +302 -0
  172. package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +134 -0
  173. package/coverage/lcov-report/utilities/users.js.html +5 -5
  174. package/coverage/lcov-report/utilities/workerRequests.js.html +39 -108
  175. package/coverage/lcov.info +2415 -2154
  176. package/dist/api/controllers/application.js +45 -24
  177. package/dist/api/controllers/static/index.js +59 -10
  178. package/dist/api/controllers/table/internal.js +2 -0
  179. package/dist/api/controllers/table/utils.js +5 -0
  180. package/dist/api/routes/index.js +0 -2
  181. package/dist/api/routes/static.js +2 -1
  182. package/dist/automations/steps/createRow.js +2 -4
  183. package/dist/automations/steps/deleteRow.js +1 -4
  184. package/dist/environment.js +1 -0
  185. package/dist/integrations/rest.js +5 -5
  186. package/dist/integrations/s3.js +1 -1
  187. package/dist/integrations/utils.js +6 -3
  188. package/dist/middleware/currentapp.js +0 -9
  189. package/dist/middleware/usageQuota.js +82 -13
  190. package/dist/migrations/usageQuotas/index.js +24 -0
  191. package/dist/migrations/usageQuotas/syncApps.js +26 -0
  192. package/dist/migrations/usageQuotas/syncRows.js +29 -0
  193. package/dist/package.json +5 -5
  194. package/dist/tests/utilities/TestConfiguration.js +3 -1
  195. package/dist/threads/query.js +4 -0
  196. package/dist/tsconfig.tsbuildinfo +1 -1
  197. package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
  198. package/dist/utilities/usageQuota/rows.js +77 -0
  199. package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
  200. package/dist/utilities/workerRequests.js +0 -20
  201. package/nodemon.json +1 -1
  202. package/package.json +6 -6
  203. package/src/api/controllers/application.js +48 -27
  204. package/src/api/controllers/static/index.js +63 -10
  205. package/src/api/controllers/table/internal.js +2 -0
  206. package/src/api/controllers/table/utils.js +5 -0
  207. package/src/api/routes/index.js +0 -2
  208. package/src/api/routes/static.js +5 -0
  209. package/src/api/routes/tests/application.spec.js +2 -2
  210. package/src/api/routes/tests/static.spec.js +98 -0
  211. package/src/automations/steps/createRow.js +2 -4
  212. package/src/automations/steps/deleteRow.js +1 -4
  213. package/src/environment.js +1 -0
  214. package/src/integrations/rest.ts +9 -28
  215. package/src/integrations/s3.ts +1 -1
  216. package/src/integrations/utils.ts +18 -5
  217. package/src/middleware/currentapp.js +0 -9
  218. package/src/middleware/tests/usageQuota.spec.js +18 -24
  219. package/src/middleware/usageQuota.js +93 -15
  220. package/src/migrations/tests/usageQuotas/index.spec.js +27 -0
  221. package/src/migrations/tests/usageQuotas/syncApps.spec.js +37 -0
  222. package/src/migrations/tests/usageQuotas/syncRows.spec.js +43 -0
  223. package/src/migrations/usageQuotas/index.js +24 -0
  224. package/src/migrations/usageQuotas/syncApps.js +18 -0
  225. package/src/migrations/usageQuotas/syncRows.js +21 -0
  226. package/src/tests/utilities/TestConfiguration.js +3 -1
  227. package/src/threads/query.js +5 -0
  228. package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
  229. package/src/utilities/usageQuota/index.js +92 -0
  230. package/src/utilities/usageQuota/rows.js +74 -0
  231. package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
  232. package/src/utilities/workerRequests.js +0 -23
  233. package/dist/api/controllers/hosting.js +0 -30
  234. package/dist/api/routes/hosting.js +0 -11
  235. package/src/api/controllers/hosting.js +0 -22
  236. package/src/api/routes/hosting.js +0 -13
  237. package/src/api/routes/tests/hosting.spec.js +0 -36
  238. package/src/utilities/usageQuota.js +0 -73
@@ -0,0 +1,98 @@
1
+ jest.mock("node-fetch")
2
+ jest.mock("aws-sdk", () => ({
3
+ config: {
4
+ update: jest.fn(),
5
+ },
6
+ DynamoDB: {
7
+ DocumentClient: jest.fn(),
8
+ },
9
+ S3: jest.fn(() => ({
10
+ getSignedUrl: jest.fn(() => {
11
+ return "my-url"
12
+ }),
13
+ })),
14
+ }))
15
+
16
+ const setup = require("./utilities")
17
+
18
+ describe("/attachments", () => {
19
+ let request = setup.getRequest()
20
+ let config = setup.getConfig()
21
+ let app
22
+
23
+ afterAll(setup.afterAll)
24
+
25
+ beforeEach(async () => {
26
+ app = await config.init()
27
+ })
28
+
29
+ describe("generateSignedUrls", () => {
30
+ let datasource
31
+
32
+ beforeEach(async () => {
33
+ datasource = await config.createDatasource({
34
+ datasource: {
35
+ type: "datasource",
36
+ name: "Test",
37
+ source: "S3",
38
+ config: {},
39
+ },
40
+ })
41
+ })
42
+
43
+ it("should be able to generate a signed upload URL", async () => {
44
+ const bucket = "foo"
45
+ const key = "bar"
46
+ const res = await request
47
+ .post(`/api/attachments/${datasource._id}/url`)
48
+ .send({ bucket, key })
49
+ .set(config.defaultHeaders())
50
+ .expect("Content-Type", /json/)
51
+ .expect(200)
52
+ expect(res.body.signedUrl).toEqual("my-url")
53
+ expect(res.body.publicUrl).toEqual(
54
+ `https://${bucket}.s3.eu-west-1.amazonaws.com/${key}`
55
+ )
56
+ })
57
+
58
+ it("should handle an invalid datasource ID", async () => {
59
+ const res = await request
60
+ .post(`/api/attachments/foo/url`)
61
+ .send({
62
+ bucket: "foo",
63
+ key: "bar",
64
+ })
65
+ .set(config.defaultHeaders())
66
+ .expect("Content-Type", /json/)
67
+ .expect(400)
68
+ expect(res.body.message).toEqual(
69
+ "The specified datasource could not be found"
70
+ )
71
+ })
72
+
73
+ it("should require a bucket parameter", async () => {
74
+ const res = await request
75
+ .post(`/api/attachments/${datasource._id}/url`)
76
+ .send({
77
+ bucket: undefined,
78
+ key: "bar",
79
+ })
80
+ .set(config.defaultHeaders())
81
+ .expect("Content-Type", /json/)
82
+ .expect(400)
83
+ expect(res.body.message).toEqual("bucket and key values are required")
84
+ })
85
+
86
+ it("should require a key parameter", async () => {
87
+ const res = await request
88
+ .post(`/api/attachments/${datasource._id}/url`)
89
+ .send({
90
+ bucket: "foo",
91
+ })
92
+ .set(config.defaultHeaders())
93
+ .expect("Content-Type", /json/)
94
+ .expect(400)
95
+ expect(res.body.message).toEqual("bucket and key values are required")
96
+ })
97
+ })
98
+ })
@@ -1,6 +1,5 @@
1
1
  const rowController = require("../../api/controllers/row")
2
2
  const automationUtils = require("../automationUtils")
3
- const env = require("../../environment")
4
3
  const usage = require("../../utilities/usageQuota")
5
4
  const { buildCtx } = require("./utils")
6
5
 
@@ -83,10 +82,9 @@ exports.run = async function ({ inputs, appId, emitter }) {
83
82
  inputs.row.tableId,
84
83
  inputs.row
85
84
  )
86
- if (env.USE_QUOTAS) {
87
- await usage.update(usage.Properties.ROW, 1)
88
- }
85
+ await usage.update(usage.Properties.ROW, 1, { dryRun: true })
89
86
  await rowController.save(ctx)
87
+ await usage.update(usage.Properties.ROW, 1)
90
88
  return {
91
89
  row: inputs.row,
92
90
  response: ctx.body,
@@ -1,5 +1,4 @@
1
1
  const rowController = require("../../api/controllers/row")
2
- const env = require("../../environment")
3
2
  const usage = require("../../utilities/usageQuota")
4
3
  const { buildCtx } = require("./utils")
5
4
  const automationUtils = require("../automationUtils")
@@ -74,9 +73,7 @@ exports.run = async function ({ inputs, appId, emitter }) {
74
73
  })
75
74
 
76
75
  try {
77
- if (env.isProd()) {
78
- await usage.update(usage.Properties.ROW, -1)
79
- }
76
+ await usage.update(usage.Properties.ROW, -1)
80
77
  await rowController.destroy(ctx)
81
78
  return {
82
79
  response: ctx.body,
@@ -38,6 +38,7 @@ module.exports = {
38
38
  MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY,
39
39
  MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY,
40
40
  USE_QUOTAS: process.env.USE_QUOTAS,
41
+ EXCLUDE_QUOTAS_TENANTS: process.env.EXCLUDE_QUOTAS_TENANTS,
41
42
  REDIS_URL: process.env.REDIS_URL,
42
43
  REDIS_PASSWORD: process.env.REDIS_PASSWORD,
43
44
  INTERNAL_API_KEY: process.env.INTERNAL_API_KEY,
@@ -43,8 +43,8 @@ const coreFields = {
43
43
  enum: Object.values(BodyTypes),
44
44
  },
45
45
  pagination: {
46
- type: DatasourceFieldTypes.OBJECT,
47
- },
46
+ type: DatasourceFieldTypes.OBJECT
47
+ }
48
48
  }
49
49
 
50
50
  module RestModule {
@@ -178,17 +178,12 @@ module RestModule {
178
178
  headers,
179
179
  },
180
180
  pagination: {
181
- cursor: nextCursor,
182
- },
181
+ cursor: nextCursor
182
+ }
183
183
  }
184
184
  }
185
185
 
186
- getUrl(
187
- path: string,
188
- queryString: string,
189
- pagination: PaginationConfig | null,
190
- paginationValues: PaginationValues | null
191
- ): string {
186
+ getUrl(path: string, queryString: string, pagination: PaginationConfig | null, paginationValues: PaginationValues | null): string {
192
187
  // Add pagination params to query string if required
193
188
  if (pagination?.location === "query" && paginationValues) {
194
189
  const { pageParam, sizeParam } = pagination
@@ -222,22 +217,14 @@ module RestModule {
222
217
  return complete
223
218
  }
224
219
 
225
- addBody(
226
- bodyType: string,
227
- body: string | any,
228
- input: any,
229
- pagination: PaginationConfig | null,
230
- paginationValues: PaginationValues | null
231
- ) {
220
+ addBody(bodyType: string, body: string | any, input: any, pagination: PaginationConfig | null, paginationValues: PaginationValues | null) {
232
221
  if (!input.headers) {
233
222
  input.headers = {}
234
223
  }
235
224
  if (bodyType === BodyTypes.NONE) {
236
225
  return input
237
226
  }
238
- let error,
239
- object: any = {},
240
- string = ""
227
+ let error, object: any = {}, string = ""
241
228
  try {
242
229
  if (body) {
243
230
  string = typeof body !== "string" ? JSON.stringify(body) : body
@@ -346,7 +333,7 @@ module RestModule {
346
333
  requestBody,
347
334
  authConfigId,
348
335
  pagination,
349
- paginationValues,
336
+ paginationValues
350
337
  } = query
351
338
  const authHeaders = this.getAuthHeaders(authConfigId)
352
339
 
@@ -365,13 +352,7 @@ module RestModule {
365
352
  }
366
353
 
367
354
  let input: any = { method, headers: this.headers }
368
- input = this.addBody(
369
- bodyType,
370
- requestBody,
371
- input,
372
- pagination,
373
- paginationValues
374
- )
355
+ input = this.addBody(bodyType, requestBody, input, pagination, paginationValues)
375
356
 
376
357
  this.startTimeMs = performance.now()
377
358
  const url = this.getUrl(path, queryString, pagination, paginationValues)
@@ -38,7 +38,7 @@ module S3Module {
38
38
  signatureVersion: {
39
39
  type: "string",
40
40
  required: false,
41
- default: "v4",
41
+ default: "v4"
42
42
  },
43
43
  },
44
44
  query: {
@@ -153,8 +153,15 @@ export function isIsoDateString(str: string) {
153
153
  * @param column The column to check, to see if it is a valid relationship.
154
154
  * @param tableIds The IDs of the tables which currently exist.
155
155
  */
156
- function shouldCopyRelationship(column: { type: string, tableId?: string }, tableIds: [string]) {
157
- return column.type === FieldTypes.LINK && column.tableId && tableIds.includes(column.tableId)
156
+ function shouldCopyRelationship(
157
+ column: { type: string; tableId?: string },
158
+ tableIds: [string]
159
+ ) {
160
+ return (
161
+ column.type === FieldTypes.LINK &&
162
+ column.tableId &&
163
+ tableIds.includes(column.tableId)
164
+ )
158
165
  }
159
166
 
160
167
  /**
@@ -165,9 +172,15 @@ function shouldCopyRelationship(column: { type: string, tableId?: string }, tabl
165
172
  * @param column The column to check for options or boolean type.
166
173
  * @param fetchedColumn The fetched column to check for the type in the external database.
167
174
  */
168
- function shouldCopySpecialColumn(column: { type: string }, fetchedColumn: { type: string } | undefined) {
169
- return column.type === FieldTypes.OPTIONS ||
170
- ((!fetchedColumn || fetchedColumn.type === FieldTypes.NUMBER) && column.type === FieldTypes.BOOLEAN)
175
+ function shouldCopySpecialColumn(
176
+ column: { type: string },
177
+ fetchedColumn: { type: string } | undefined
178
+ ) {
179
+ return (
180
+ column.type === FieldTypes.OPTIONS ||
181
+ ((!fetchedColumn || fetchedColumn.type === FieldTypes.NUMBER) &&
182
+ column.type === FieldTypes.BOOLEAN)
183
+ )
171
184
  }
172
185
 
173
186
  /**
@@ -47,15 +47,6 @@ module.exports = async (ctx, next) => {
47
47
  (!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
48
48
  ) {
49
49
  clearCookie(ctx, Cookies.CurrentApp)
50
- // have to set the return url on the server side as client side is not available
51
- setCookie(ctx, ctx.url, Cookies.RETURN_URL, {
52
- // don't sign so the browser can easily read
53
- sign: false,
54
- // use the request domain to match how ui handles the return url cookie.
55
- // it's important we don't use the shared domain here as the builder
56
- // can't delete from it without awareness of the domain.
57
- requestDomain: true,
58
- })
59
50
  return ctx.redirect("/")
60
51
  }
61
52
 
@@ -1,11 +1,5 @@
1
1
  jest.mock("../../db")
2
2
  jest.mock("../../utilities/usageQuota")
3
- jest.mock("../../environment", () => ({
4
- isTest: () => true,
5
- isProd: () => false,
6
- isDev: () => true,
7
- _set: () => {},
8
- }))
9
3
  jest.mock("@budibase/backend-core/tenancy", () => ({
10
4
  getTenantId: () => "testing123"
11
5
  }))
@@ -29,9 +23,10 @@ class TestConfiguration {
29
23
  },
30
24
  req: {
31
25
  method: "POST",
32
- url: "/rows"
26
+ url: "/applications"
33
27
  }
34
28
  }
29
+ usageQuota.useQuotas = () => true
35
30
  }
36
31
 
37
32
  executeMiddleware() {
@@ -113,7 +108,6 @@ describe("usageQuota middleware", () => {
113
108
 
114
109
  it("calculates and persists the correct usage quota for the relevant action", async () => {
115
110
  config.setUrl("/rows")
116
- config.setProd(true)
117
111
 
118
112
  await config.executeMiddleware()
119
113
 
@@ -121,20 +115,20 @@ describe("usageQuota middleware", () => {
121
115
  expect(config.next).toHaveBeenCalled()
122
116
  })
123
117
 
124
- it("calculates the correct file size from a file upload call and adds it to quota", async () => {
125
- config.setUrl("/upload")
126
- config.setProd(true)
127
- config.setFiles([
128
- {
129
- size: 100
130
- },
131
- {
132
- size: 10000
133
- },
134
- ])
135
- await config.executeMiddleware()
136
-
137
- expect(usageQuota.update).toHaveBeenCalledWith("storage", 10100)
138
- expect(config.next).toHaveBeenCalled()
139
- })
118
+ // it("calculates the correct file size from a file upload call and adds it to quota", async () => {
119
+ // config.setUrl("/upload")
120
+ // config.setProd(true)
121
+ // config.setFiles([
122
+ // {
123
+ // size: 100
124
+ // },
125
+ // {
126
+ // size: 10000
127
+ // },
128
+ // ])
129
+ // await config.executeMiddleware()
130
+
131
+ // expect(usageQuota.update).toHaveBeenCalledWith("storage", 10100)
132
+ // expect(config.next).toHaveBeenCalled()
133
+ // })
140
134
  })
@@ -1,14 +1,11 @@
1
1
  const CouchDB = require("../db")
2
2
  const usageQuota = require("../utilities/usageQuota")
3
- const env = require("../environment")
4
- const { getTenantId } = require("@budibase/backend-core/tenancy")
3
+ const { getUniqueRows } = require("../utilities/usageQuota/rows")
5
4
  const {
6
5
  isExternalTable,
7
6
  isRowId: isExternalRowId,
8
7
  } = require("../integrations/utils")
9
-
10
- // tenants without limits
11
- const EXCLUDED_TENANTS = ["bb", "default", "bbtest", "bbstaging"]
8
+ const migration = require("../migrations/usageQuotas")
12
9
 
13
10
  // currently only counting new writes and deletes
14
11
  const METHOD_MAP = {
@@ -18,13 +15,13 @@ const METHOD_MAP = {
18
15
 
19
16
  const DOMAIN_MAP = {
20
17
  rows: usageQuota.Properties.ROW,
21
- upload: usageQuota.Properties.UPLOAD,
22
- views: usageQuota.Properties.VIEW,
23
- users: usageQuota.Properties.USER,
18
+ // upload: usageQuota.Properties.UPLOAD, // doesn't work yet
19
+ // views: usageQuota.Properties.VIEW, // doesn't work yet
20
+ // users: usageQuota.Properties.USER, // doesn't work yet
24
21
  applications: usageQuota.Properties.APPS,
25
22
  // this will not be updated by endpoint calls
26
23
  // instead it will be updated by triggerInfo
27
- automationRuns: usageQuota.Properties.AUTOMATION,
24
+ // automationRuns: usageQuota.Properties.AUTOMATION, // doesn't work yet
28
25
  }
29
26
 
30
27
  function getProperty(url) {
@@ -36,10 +33,7 @@ function getProperty(url) {
36
33
  }
37
34
 
38
35
  module.exports = async (ctx, next) => {
39
- const tenantId = getTenantId()
40
-
41
- // if in development or a self hosted cloud usage quotas should not be executed
42
- if (env.isDev() || env.SELF_HOSTED || EXCLUDED_TENANTS.includes(tenantId)) {
36
+ if (!usageQuota.useQuotas()) {
43
37
  return next()
44
38
  }
45
39
 
@@ -80,9 +74,93 @@ module.exports = async (ctx, next) => {
80
74
  usage = files.map(file => file.size).reduce((total, size) => total + size)
81
75
  }
82
76
  try {
83
- await usageQuota.update(property, usage)
84
- return next()
77
+ await migration.run()
78
+ await performRequest(ctx, next, property, usage)
85
79
  } catch (err) {
86
80
  ctx.throw(400, err)
87
81
  }
88
82
  }
83
+
84
+ const performRequest = async (ctx, next, property, usage) => {
85
+ const usageContext = {
86
+ skipNext: false,
87
+ skipUsage: false,
88
+ [usageQuota.Properties.APPS]: {},
89
+ }
90
+
91
+ if (usage === -1) {
92
+ if (PRE_DELETE[property]) {
93
+ await PRE_DELETE[property](ctx, usageContext)
94
+ }
95
+ } else {
96
+ if (PRE_CREATE[property]) {
97
+ await PRE_CREATE[property](ctx, usageContext)
98
+ }
99
+ }
100
+
101
+ // run the request
102
+ if (!usageContext.skipNext) {
103
+ await usageQuota.update(property, usage, { dryRun: true })
104
+ await next()
105
+ }
106
+
107
+ if (usage === -1) {
108
+ if (POST_DELETE[property]) {
109
+ await POST_DELETE[property](ctx, usageContext)
110
+ }
111
+ } else {
112
+ if (POST_CREATE[property]) {
113
+ await POST_CREATE[property](ctx, usageContext)
114
+ }
115
+ }
116
+
117
+ // update the usage
118
+ if (!usageContext.skipUsage) {
119
+ await usageQuota.update(property, usage)
120
+ }
121
+ }
122
+
123
+ const appPreDelete = async (ctx, usageContext) => {
124
+ if (ctx.query.unpublish) {
125
+ // don't run usage decrement for unpublish
126
+ usageContext.skipUsage = true
127
+ return
128
+ }
129
+
130
+ // store the row count to delete
131
+ const rows = await getUniqueRows([ctx.appId])
132
+ if (rows.length) {
133
+ usageContext[usageQuota.Properties.APPS] = { rowCount: rows.length }
134
+ }
135
+ }
136
+
137
+ const appPostDelete = async (ctx, usageContext) => {
138
+ // delete the app rows from usage
139
+ const rowCount = usageContext[usageQuota.Properties.APPS].rowCount
140
+ if (rowCount) {
141
+ await usageQuota.update(usageQuota.Properties.ROW, -rowCount)
142
+ }
143
+ }
144
+
145
+ const appPostCreate = async ctx => {
146
+ // app import & template creation
147
+ if (ctx.request.body.useTemplate === "true") {
148
+ const rows = await getUniqueRows([ctx.response.body.appId])
149
+ const rowCount = rows ? rows.length : 0
150
+ await usageQuota.update(usageQuota.Properties.ROW, rowCount)
151
+ }
152
+ }
153
+
154
+ const PRE_DELETE = {
155
+ [usageQuota.Properties.APPS]: appPreDelete,
156
+ }
157
+
158
+ const POST_DELETE = {
159
+ [usageQuota.Properties.APPS]: appPostDelete,
160
+ }
161
+
162
+ const PRE_CREATE = {}
163
+
164
+ const POST_CREATE = {
165
+ [usageQuota.Properties.APPS]: appPostCreate,
166
+ }
@@ -0,0 +1,27 @@
1
+ const env = require("../../../environment")
2
+ const TestConfig = require("../../../tests/utilities/TestConfiguration")
3
+
4
+ const syncApps = jest.fn()
5
+ const syncRows = jest.fn()
6
+
7
+ jest.mock("../../usageQuotas/syncApps", () => ({ run: syncApps }) )
8
+ jest.mock("../../usageQuotas/syncRows", () => ({ run: syncRows }) )
9
+
10
+ const migrations = require("../../usageQuotas")
11
+
12
+ describe("run", () => {
13
+ let config = new TestConfig(false)
14
+
15
+ beforeEach(async () => {
16
+ await config.init()
17
+ env._set("USE_QUOTAS", 1)
18
+ })
19
+
20
+ afterAll(config.end)
21
+
22
+ it("runs the required migrations", async () => {
23
+ await migrations.run()
24
+ expect(syncApps).toHaveBeenCalledTimes(1)
25
+ expect(syncRows).toHaveBeenCalledTimes(1)
26
+ })
27
+ })
@@ -0,0 +1,37 @@
1
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy")
2
+ const TestConfig = require("../../../tests/utilities/TestConfiguration")
3
+ const { getUsageQuotaDoc, update, Properties } = require("../../../utilities/usageQuota")
4
+ const syncApps = require("../../usageQuotas/syncApps")
5
+ const env = require("../../../environment")
6
+
7
+ describe("syncApps", () => {
8
+ let config = new TestConfig(false)
9
+
10
+ beforeEach(async () => {
11
+ await config.init()
12
+ env._set("USE_QUOTAS", 1)
13
+ })
14
+
15
+ afterAll(config.end)
16
+
17
+ it("runs successfully", async () => {
18
+ // create the usage quota doc and mock usages
19
+ const db = getGlobalDB()
20
+ await getUsageQuotaDoc(db)
21
+ await update(Properties.APPS, 3)
22
+
23
+ let usageDoc = await getUsageQuotaDoc(db)
24
+ expect(usageDoc.usageQuota.apps).toEqual(3)
25
+
26
+ // create an extra app to test the migration
27
+ await config.createApp("quota-test")
28
+
29
+ // migrate
30
+ await syncApps.run()
31
+
32
+ // assert the migration worked
33
+ usageDoc = await getUsageQuotaDoc(db)
34
+ expect(usageDoc.usageQuota.apps).toEqual(2)
35
+ })
36
+ })
37
+
@@ -0,0 +1,43 @@
1
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy")
2
+ const TestConfig = require("../../../tests/utilities/TestConfiguration")
3
+ const { getUsageQuotaDoc, update, Properties } = require("../../../utilities/usageQuota")
4
+ const syncRows = require("../../usageQuotas/syncRows")
5
+ const env = require("../../../environment")
6
+
7
+ describe("syncRows", () => {
8
+ let config = new TestConfig(false)
9
+
10
+ beforeEach(async () => {
11
+ await config.init()
12
+ env._set("USE_QUOTAS", 1)
13
+ })
14
+
15
+ afterAll(config.end)
16
+
17
+ it("runs successfully", async () => {
18
+ // create the usage quota doc and mock usages
19
+ const db = getGlobalDB()
20
+ await getUsageQuotaDoc(db)
21
+ await update(Properties.ROW, 300)
22
+
23
+ let usageDoc = await getUsageQuotaDoc(db)
24
+ expect(usageDoc.usageQuota.rows).toEqual(300)
25
+
26
+ // app 1
27
+ await config.createTable()
28
+ await config.createRow()
29
+ // app 2
30
+ await config.createApp("second-app")
31
+ await config.createTable()
32
+ await config.createRow()
33
+ await config.createRow()
34
+
35
+ // migrate
36
+ await syncRows.run()
37
+
38
+ // assert the migration worked
39
+ usageDoc = await getUsageQuotaDoc(db)
40
+ expect(usageDoc.usageQuota.rows).toEqual(3)
41
+ })
42
+ })
43
+
@@ -0,0 +1,24 @@
1
+ const {
2
+ MIGRATIONS,
3
+ MIGRATION_DBS,
4
+ migrateIfRequired,
5
+ } = require("@budibase/backend-core/migrations")
6
+ const { useQuotas } = require("../../utilities/usageQuota")
7
+ const syncApps = require("./syncApps")
8
+ const syncRows = require("./syncRows")
9
+
10
+ exports.run = async () => {
11
+ if (!useQuotas()) {
12
+ return
13
+ }
14
+
15
+ // Jan 2022
16
+ await migrateIfRequired(
17
+ MIGRATION_DBS.GLOBAL_DB,
18
+ MIGRATIONS.QUOTAS_1,
19
+ async () => {
20
+ await syncApps.run()
21
+ await syncRows.run()
22
+ }
23
+ )
24
+ }
@@ -0,0 +1,18 @@
1
+ const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
2
+ const { getAllApps } = require("@budibase/backend-core/db")
3
+ const CouchDB = require("../../db")
4
+ const { getUsageQuotaDoc } = require("../../utilities/usageQuota")
5
+
6
+ exports.run = async () => {
7
+ const db = getGlobalDB()
8
+ // get app count
9
+ const devApps = await getAllApps(CouchDB, { dev: true })
10
+ const appCount = devApps ? devApps.length : 0
11
+
12
+ // sync app count
13
+ const tenantId = getTenantId()
14
+ console.log(`[Tenant: ${tenantId}] Syncing app count: ${appCount}`)
15
+ const usageDoc = await getUsageQuotaDoc(db)
16
+ usageDoc.usageQuota.apps = appCount
17
+ await db.put(usageDoc)
18
+ }
@@ -0,0 +1,21 @@
1
+ const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
2
+ const { getAllApps } = require("@budibase/backend-core/db")
3
+ const CouchDB = require("../../db")
4
+ const { getUsageQuotaDoc } = require("../../utilities/usageQuota")
5
+ const { getUniqueRows } = require("../../utilities/usageQuota/rows")
6
+
7
+ exports.run = async () => {
8
+ const db = getGlobalDB()
9
+ // get all rows in all apps
10
+ const allApps = await getAllApps(CouchDB, { all: true })
11
+ const appIds = allApps ? allApps.map(app => app.appId) : []
12
+ const rows = await getUniqueRows(appIds)
13
+ const rowCount = rows ? rows.length : 0
14
+
15
+ // sync row count
16
+ const tenantId = getTenantId()
17
+ console.log(`[Tenant: ${tenantId}] Syncing row count: ${rowCount}`)
18
+ const usageDoc = await getUsageQuotaDoc(db)
19
+ usageDoc.usageQuota.rows = rowCount
20
+ await db.put(usageDoc)
21
+ }