@budibase/server 1.0.47 → 1.0.49-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/builder/assets/{index.937b2767.js → index.82e12602.js} +234 -231
  2. package/builder/assets/index.83c0944f.css +1 -0
  3. package/builder/assets/{vendor.f9faf6ab.js → vendor.d526bfe8.js} +12 -12
  4. package/builder/index.html +3 -3
  5. package/coverage/clover.xml +2334 -2013
  6. package/coverage/coverage-final.json +100 -95
  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 +210 -126
  10. package/coverage/lcov-report/api/controllers/auth.js.html +18 -6
  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 +72 -36
  16. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/index.html +53 -53
  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/migrations.js.html +119 -0
  22. package/coverage/lcov-report/api/controllers/permission.js.html +15 -15
  23. package/coverage/lcov-report/api/controllers/query/index.html +1 -1
  24. package/coverage/lcov-report/api/controllers/query/index.js.html +19 -19
  25. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  26. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  27. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/external.js.html +16 -16
  29. package/coverage/lcov-report/api/controllers/row/index.html +48 -33
  30. package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
  31. package/coverage/lcov-report/api/controllers/row/internal.js.html +95 -158
  32. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +41 -17
  33. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +551 -0
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +39 -57
  35. package/coverage/lcov-report/api/controllers/screen.js.html +7 -7
  36. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  37. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +629 -0
  38. package/coverage/lcov-report/api/controllers/table/external.js.html +12 -12
  39. package/coverage/lcov-report/api/controllers/table/index.html +49 -34
  40. package/coverage/lcov-report/api/controllers/table/index.js.html +53 -77
  41. package/coverage/lcov-report/api/controllers/table/internal.js.html +59 -35
  42. package/coverage/lcov-report/api/controllers/table/utils.js.html +283 -76
  43. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  44. package/coverage/lcov-report/api/controllers/user.js.html +30 -24
  45. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  46. package/coverage/lcov-report/api/controllers/view/index.html +1 -1
  47. package/coverage/lcov-report/api/controllers/view/index.js.html +14 -14
  48. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  49. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  50. package/coverage/lcov-report/api/controllers/webhook.js.html +15 -15
  51. package/coverage/lcov-report/api/index.html +1 -1
  52. package/coverage/lcov-report/api/index.js.html +8 -8
  53. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +18 -18
  65. package/coverage/lcov-report/api/routes/index.js.html +3 -3
  66. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/{hosting.js.html → migrations.js.html} +17 -14
  70. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/static.js.html +17 -2
  78. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  83. package/coverage/lcov-report/automations/actions.js.html +24 -24
  84. package/coverage/lcov-report/automations/automationUtils.js.html +5 -5
  85. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  86. package/coverage/lcov-report/automations/index.html +1 -1
  87. package/coverage/lcov-report/automations/index.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  89. package/coverage/lcov-report/automations/steps/createRow.js.html +13 -19
  90. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  91. package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
  92. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  93. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  94. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  95. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  96. package/coverage/lcov-report/automations/steps/index.html +13 -13
  97. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  98. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  99. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  100. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  101. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  102. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  103. package/coverage/lcov-report/automations/steps/updateRow.js.html +6 -6
  104. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  105. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  106. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  108. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  109. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  110. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggers.js.html +18 -18
  115. package/coverage/lcov-report/automations/utils.js.html +32 -32
  116. package/coverage/lcov-report/constants/index.html +11 -11
  117. package/coverage/lcov-report/constants/index.js.html +68 -32
  118. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  119. package/coverage/lcov-report/constants/screens.js.html +4 -4
  120. package/coverage/lcov-report/db/client.js.html +18 -18
  121. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  122. package/coverage/lcov-report/db/index.html +15 -15
  123. package/coverage/lcov-report/db/index.js.html +3 -3
  124. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +18 -18
  125. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  126. package/coverage/lcov-report/db/linkedRows/index.js.html +38 -41
  127. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +15 -15
  128. package/coverage/lcov-report/db/newid.js.html +4 -4
  129. package/coverage/lcov-report/db/utils.js.html +86 -86
  130. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  131. package/coverage/lcov-report/events/index.html +1 -1
  132. package/coverage/lcov-report/events/index.js.html +5 -5
  133. package/coverage/lcov-report/events/utils.js.html +3 -3
  134. package/coverage/lcov-report/index.html +117 -102
  135. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  136. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  137. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  138. package/coverage/lcov-report/middleware/authorized.js.html +166 -64
  139. package/coverage/lcov-report/middleware/builder.js.html +8 -8
  140. package/coverage/lcov-report/middleware/currentapp.js.html +29 -29
  141. package/coverage/lcov-report/middleware/index.html +30 -30
  142. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  143. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  144. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  145. package/coverage/lcov-report/middleware/usageQuota.js.html +270 -42
  146. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  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 +27 -27
  164. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +115 -79
  165. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
  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/{api/controllers/hosting.js.html → utilities/usageQuota/usageQuoteReset.js.html} +36 -48
  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 +3665 -3040
  176. package/dist/api/controllers/application.js +61 -34
  177. package/dist/api/controllers/auth.js +4 -0
  178. package/dist/api/controllers/datasource.js +11 -0
  179. package/dist/api/controllers/migrations.js +21 -0
  180. package/dist/api/controllers/row/ExternalRequest.js +2 -1
  181. package/dist/api/controllers/row/internal.js +30 -53
  182. package/dist/api/controllers/row/internalSearch.js +12 -4
  183. package/dist/api/controllers/row/staticFormula.js +147 -0
  184. package/dist/api/controllers/row/utils.js +6 -8
  185. package/dist/api/controllers/static/index.js +59 -10
  186. package/dist/api/controllers/table/bulkFormula.js +160 -0
  187. package/dist/api/controllers/table/index.js +12 -9
  188. package/dist/api/controllers/table/internal.js +9 -0
  189. package/dist/api/controllers/table/utils.js +56 -14
  190. package/dist/api/controllers/user.js +2 -0
  191. package/dist/api/routes/index.js +2 -2
  192. package/dist/api/routes/migrations.js +9 -0
  193. package/dist/api/routes/static.js +2 -1
  194. package/dist/app.js +35 -5
  195. package/dist/automations/steps/createRow.js +2 -4
  196. package/dist/automations/steps/deleteRow.js +1 -4
  197. package/dist/constants/index.js +12 -5
  198. package/dist/db/linkedRows/index.js +4 -5
  199. package/dist/definitions/datasource.js +1 -0
  200. package/dist/environment.js +2 -0
  201. package/dist/integrations/base/sql.js +13 -6
  202. package/dist/integrations/googlesheets.js +340 -0
  203. package/dist/integrations/index.js +3 -0
  204. package/dist/integrations/utils.js +57 -8
  205. package/dist/middleware/authorized.js +55 -30
  206. package/dist/middleware/usageQuota.js +80 -13
  207. package/dist/migrations/functions/appUrls.js +37 -0
  208. package/dist/migrations/functions/quotas1.js +50 -0
  209. package/dist/migrations/functions/usageQuotas/index.js +20 -0
  210. package/dist/migrations/functions/usageQuotas/syncApps.js +32 -0
  211. package/dist/migrations/functions/usageQuotas/syncRows.js +35 -0
  212. package/dist/migrations/functions/userEmailViewCasing.js +24 -0
  213. package/dist/migrations/index.js +62 -0
  214. package/dist/package.json +8 -5
  215. package/dist/tests/utilities/TestConfiguration.js +13 -6
  216. package/dist/threads/query.js +4 -0
  217. package/dist/tsconfig.tsbuildinfo +1 -1
  218. package/dist/utilities/rowProcessor/index.js +18 -11
  219. package/dist/utilities/rowProcessor/utils.js +14 -4
  220. package/dist/utilities/{usageQuota.js → usageQuota/index.js} +44 -31
  221. package/dist/utilities/usageQuota/rows.js +77 -0
  222. package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
  223. package/dist/utilities/workerRequests.js +0 -20
  224. package/nodemon.json +1 -1
  225. package/package.json +9 -6
  226. package/src/api/controllers/application.js +52 -24
  227. package/src/api/controllers/auth.js +4 -0
  228. package/src/api/controllers/datasource.js +12 -0
  229. package/src/api/controllers/migrations.js +13 -0
  230. package/src/api/controllers/row/ExternalRequest.ts +1 -1
  231. package/src/api/controllers/row/internal.js +29 -50
  232. package/src/api/controllers/row/internalSearch.js +12 -4
  233. package/src/api/controllers/row/staticFormula.js +157 -0
  234. package/src/api/controllers/row/utils.js +6 -12
  235. package/src/api/controllers/static/index.js +63 -10
  236. package/src/api/controllers/table/bulkFormula.js +183 -0
  237. package/src/api/controllers/table/index.js +16 -24
  238. package/src/api/controllers/table/internal.js +9 -1
  239. package/src/api/controllers/table/utils.js +80 -11
  240. package/src/api/controllers/user.js +2 -0
  241. package/src/api/routes/index.js +2 -2
  242. package/src/api/routes/migrations.js +14 -0
  243. package/src/api/routes/static.js +5 -0
  244. package/src/api/routes/tests/application.spec.js +2 -2
  245. package/src/api/routes/tests/auth.spec.js +1 -2
  246. package/src/api/routes/tests/static.spec.js +98 -0
  247. package/src/app.ts +18 -5
  248. package/src/automations/steps/createRow.js +2 -4
  249. package/src/automations/steps/deleteRow.js +1 -4
  250. package/src/constants/index.js +17 -5
  251. package/src/db/linkedRows/index.js +4 -5
  252. package/src/definitions/common.ts +3 -0
  253. package/src/definitions/datasource.ts +3 -0
  254. package/src/environment.js +2 -0
  255. package/src/integrations/base/sql.ts +14 -7
  256. package/src/integrations/googlesheets.ts +353 -0
  257. package/src/integrations/index.ts +3 -0
  258. package/src/integrations/tests/sql.spec.js +16 -0
  259. package/src/integrations/utils.ts +71 -10
  260. package/src/middleware/authorized.js +64 -30
  261. package/src/middleware/tests/authorized.spec.js +6 -4
  262. package/src/middleware/tests/usageQuota.spec.js +18 -24
  263. package/src/middleware/usageQuota.js +91 -15
  264. package/src/migrations/functions/appUrls.ts +25 -0
  265. package/src/migrations/functions/quotas1.ts +20 -0
  266. package/src/migrations/functions/tests/appUrls.spec.js +29 -0
  267. package/src/migrations/functions/tests/quotas1.spec.js +27 -0
  268. package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
  269. package/src/migrations/functions/usageQuotas/index.ts +8 -0
  270. package/src/migrations/functions/usageQuotas/syncApps.ts +18 -0
  271. package/src/migrations/functions/usageQuotas/syncRows.ts +21 -0
  272. package/src/migrations/functions/usageQuotas/tests/syncApps.spec.js +37 -0
  273. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.js +43 -0
  274. package/src/migrations/functions/userEmailViewCasing.ts +13 -0
  275. package/src/migrations/index.ts +56 -0
  276. package/src/tests/utilities/TestConfiguration.js +14 -6
  277. package/src/threads/query.js +5 -0
  278. package/src/utilities/rowProcessor/index.js +24 -12
  279. package/src/utilities/rowProcessor/utils.js +23 -7
  280. package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
  281. package/src/utilities/usageQuota/index.js +92 -0
  282. package/src/utilities/usageQuota/rows.js +74 -0
  283. package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
  284. package/src/utilities/workerRequests.js +0 -23
  285. package/builder/assets/index.39e01193.css +0 -1
  286. package/dist/api/controllers/hosting.js +0 -30
  287. package/dist/api/routes/hosting.js +0 -11
  288. package/src/api/controllers/hosting.js +0 -22
  289. package/src/api/routes/hosting.js +0 -13
  290. package/src/api/routes/tests/hosting.spec.js +0 -36
  291. package/src/utilities/usageQuota.js +0 -73
@@ -2,13 +2,9 @@ const CouchDB = require("../../../db")
2
2
  const internal = require("./internal")
3
3
  const external = require("./external")
4
4
  const csvParser = require("../../../utilities/csvParser")
5
- const { isExternalTable } = require("../../../integrations/utils")
6
- const {
7
- getTableParams,
8
- getDatasourceParams,
9
- BudibaseInternalDB,
10
- } = require("../../../db/utils")
11
- const { getTable } = require("./utils")
5
+ const { isExternalTable, isSQL } = require("../../../integrations/utils")
6
+ const { getDatasourceParams } = require("../../../db/utils")
7
+ const { getTable, getAllInternalTables } = require("./utils")
12
8
 
13
9
  function pickApi({ tableId, table }) {
14
10
  if (table && !tableId) {
@@ -26,17 +22,7 @@ function pickApi({ tableId, table }) {
26
22
  exports.fetch = async function (ctx) {
27
23
  const db = new CouchDB(ctx.appId)
28
24
 
29
- const internalTables = await db.allDocs(
30
- getTableParams(null, {
31
- include_docs: true,
32
- })
33
- )
34
-
35
- const internal = internalTables.rows.map(row => ({
36
- ...row.doc,
37
- type: "internal",
38
- sourceId: BudibaseInternalDB._id,
39
- }))
25
+ const internal = await getAllInternalTables(ctx.appId)
40
26
 
41
27
  const externalTables = await db.allDocs(
42
28
  getDatasourceParams("plus", {
@@ -44,12 +30,18 @@ exports.fetch = async function (ctx) {
44
30
  })
45
31
  )
46
32
 
47
- const external = externalTables.rows.flatMap(row => {
48
- return Object.values(row.doc.entities || {}).map(entity => ({
49
- ...entity,
50
- type: "external",
51
- sourceId: row.doc._id,
52
- }))
33
+ const external = externalTables.rows.flatMap(tableDoc => {
34
+ let entities = tableDoc.doc.entities
35
+ if (entities) {
36
+ return Object.values(entities).map(entity => ({
37
+ ...entity,
38
+ type: "external",
39
+ sourceId: tableDoc.doc._id,
40
+ sql: isSQL(tableDoc.doc),
41
+ }))
42
+ } else {
43
+ return []
44
+ }
53
45
  })
54
46
 
55
47
  ctx.body = [...internal, ...external]
@@ -8,6 +8,9 @@ const {
8
8
  getTable,
9
9
  handleDataImport,
10
10
  } = require("./utils")
11
+ const usageQuota = require("../../../utilities/usageQuota")
12
+ const { cleanupAttachments } = require("../../../utilities/rowProcessor")
13
+ const { runStaticFormulaChecks } = require("./bulkFormula")
11
14
 
12
15
  exports.save = async function (ctx) {
13
16
  const appId = ctx.appId
@@ -103,7 +106,8 @@ exports.save = async function (ctx) {
103
106
  tableToSave._rev = result.rev
104
107
 
105
108
  tableToSave = await tableSaveFunctions.after(tableToSave)
106
-
109
+ // has to run after, make sure it has _id
110
+ await runStaticFormulaChecks(appId, tableToSave, { oldTable })
107
111
  return tableToSave
108
112
  }
109
113
 
@@ -119,6 +123,7 @@ exports.destroy = async function (ctx) {
119
123
  })
120
124
  )
121
125
  await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true })))
126
+ await usageQuota.update(usageQuota.Properties.ROW, -rows.rows.length)
122
127
 
123
128
  // update linked rows
124
129
  await linkRows.updateLinks({
@@ -139,6 +144,9 @@ exports.destroy = async function (ctx) {
139
144
  await db.deleteIndex(existingIndex)
140
145
  }
141
146
 
147
+ // has to run after, make sure it has _id
148
+ await runStaticFormulaChecks(appId, tableToDelete, { deletion: true })
149
+ await cleanupAttachments(appId, tableToDelete, { rows })
142
150
  return tableToDelete
143
151
  }
144
152
 
@@ -4,19 +4,46 @@ const {
4
4
  getRowParams,
5
5
  generateRowID,
6
6
  InternalTables,
7
+ getTableParams,
8
+ BudibaseInternalDB,
7
9
  } = require("../../../db/utils")
8
- const { isEqual } = require("lodash/fp")
10
+ const { isEqual } = require("lodash")
9
11
  const { AutoFieldSubTypes, FieldTypes } = require("../../../constants")
10
- const { inputProcessing } = require("../../../utilities/rowProcessor")
11
- const { USERS_TABLE_SCHEMA, SwitchableTypes } = require("../../../constants")
12
+ const {
13
+ inputProcessing,
14
+ cleanupAttachments,
15
+ } = require("../../../utilities/rowProcessor")
16
+ const {
17
+ USERS_TABLE_SCHEMA,
18
+ SwitchableTypes,
19
+ CanSwitchTypes,
20
+ } = require("../../../constants")
12
21
  const {
13
22
  isExternalTable,
14
23
  breakExternalTableId,
24
+ isSQL,
15
25
  } = require("../../../integrations/utils")
16
26
  const { getViews, saveView } = require("../view/utils")
17
27
  const viewTemplate = require("../view/viewBuilder")
28
+ const usageQuota = require("../../../utilities/usageQuota")
29
+ const { cloneDeep } = require("lodash/fp")
30
+
31
+ exports.clearColumns = async (appId, table, columnNames) => {
32
+ const db = new CouchDB(appId)
33
+ const rows = await db.allDocs(
34
+ getRowParams(table._id, null, {
35
+ include_docs: true,
36
+ })
37
+ )
38
+ return db.bulkDocs(
39
+ rows.rows.map(({ doc }) => {
40
+ columnNames.forEach(colName => delete doc[colName])
41
+ return doc
42
+ })
43
+ )
44
+ }
18
45
 
19
- exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
46
+ exports.checkForColumnUpdates = async (appId, db, oldTable, updatedTable) => {
20
47
  let updatedRows = []
21
48
  const rename = updatedTable._rename
22
49
  let deletedColumns = []
@@ -33,16 +60,20 @@ exports.checkForColumnUpdates = async (db, oldTable, updatedTable) => {
33
60
  include_docs: true,
34
61
  })
35
62
  )
36
- updatedRows = rows.rows.map(({ doc }) => {
63
+ const rawRows = rows.rows.map(({ doc }) => doc)
64
+ updatedRows = rawRows.map(row => {
65
+ row = cloneDeep(row)
37
66
  if (rename) {
38
- doc[rename.updated] = doc[rename.old]
39
- delete doc[rename.old]
67
+ row[rename.updated] = row[rename.old]
68
+ delete row[rename.old]
40
69
  } else if (deletedColumns.length !== 0) {
41
- deletedColumns.forEach(colName => delete doc[colName])
70
+ deletedColumns.forEach(colName => delete row[colName])
42
71
  }
43
- return doc
72
+ return row
44
73
  })
45
74
 
75
+ // cleanup any attachments from object storage for deleted attachment columns
76
+ await cleanupAttachments(appId, updatedTable, { oldTable, rows: rawRows })
46
77
  // Update views
47
78
  await exports.checkForViewUpdates(db, updatedTable, rename, deletedColumns)
48
79
  delete updatedTable._rename
@@ -111,7 +142,11 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
111
142
  finalData.push(row)
112
143
  }
113
144
 
145
+ await usageQuota.update(usageQuota.Properties.ROW, finalData.length, {
146
+ dryRun: true,
147
+ })
114
148
  await db.bulkDocs(finalData)
149
+ await usageQuota.update(usageQuota.Properties.ROW, finalData.length)
115
150
  let response = await db.put(table)
116
151
  table._rev = response._rev
117
152
  return table
@@ -199,6 +234,7 @@ class TableSaveFunctions {
199
234
  // when confirmed valid
200
235
  async mid(table) {
201
236
  let response = await exports.checkForColumnUpdates(
237
+ this.appId,
202
238
  this.db,
203
239
  this.oldTable,
204
240
  table
@@ -224,6 +260,20 @@ class TableSaveFunctions {
224
260
  }
225
261
  }
226
262
 
263
+ exports.getAllInternalTables = async appId => {
264
+ const db = new CouchDB(appId)
265
+ const internalTables = await db.allDocs(
266
+ getTableParams(null, {
267
+ include_docs: true,
268
+ })
269
+ )
270
+ return internalTables.rows.map(tableDoc => ({
271
+ ...tableDoc.doc,
272
+ type: "internal",
273
+ sourceId: BudibaseInternalDB._id,
274
+ }))
275
+ }
276
+
227
277
  exports.getAllExternalTables = async (appId, datasourceId) => {
228
278
  const db = new CouchDB(appId)
229
279
  const datasource = await db.get(datasourceId)
@@ -242,7 +292,9 @@ exports.getTable = async (appId, tableId) => {
242
292
  const db = new CouchDB(appId)
243
293
  if (isExternalTable(tableId)) {
244
294
  let { datasourceId, tableName } = breakExternalTableId(tableId)
245
- return exports.getExternalTable(appId, datasourceId, tableName)
295
+ const datasource = await db.get(datasourceId)
296
+ const table = await exports.getExternalTable(appId, datasourceId, tableName)
297
+ return { ...table, sql: isSQL(datasource) }
246
298
  } else {
247
299
  return db.get(tableId)
248
300
  }
@@ -340,6 +392,23 @@ exports.foreignKeyStructure = (keyName, meta = null) => {
340
392
  return structure
341
393
  }
342
394
 
395
+ exports.areSwitchableTypes = (type1, type2) => {
396
+ if (
397
+ SwitchableTypes.indexOf(type1) === -1 &&
398
+ SwitchableTypes.indexOf(type2) === -1
399
+ ) {
400
+ return false
401
+ }
402
+ for (let option of CanSwitchTypes) {
403
+ const index1 = option.indexOf(type1),
404
+ index2 = option.indexOf(type2)
405
+ if (index1 !== -1 && index2 !== -1 && index1 !== index2) {
406
+ return true
407
+ }
408
+ }
409
+ return false
410
+ }
411
+
343
412
  exports.hasTypeChanged = (table, oldTable) => {
344
413
  if (!oldTable) {
345
414
  return false
@@ -350,7 +419,7 @@ exports.hasTypeChanged = (table, oldTable) => {
350
419
  continue
351
420
  }
352
421
  const newType = table.schema[key].type
353
- if (oldType !== newType && SwitchableTypes.indexOf(oldType) === -1) {
422
+ if (oldType !== newType && !exports.areSwitchableTypes(oldType, newType)) {
354
423
  return true
355
424
  }
356
425
  }
@@ -167,6 +167,8 @@ exports.updateSelfMetadata = async function (ctx) {
167
167
  ctx.request.body._id = ctx.user._id
168
168
  // make sure no stale rev
169
169
  delete ctx.request.body._rev
170
+ // make sure no csrf token
171
+ delete ctx.request.body.csrfToken
170
172
  await exports.updateMetadata(ctx)
171
173
  }
172
174
 
@@ -20,11 +20,11 @@ const integrationRoutes = require("./integration")
20
20
  const permissionRoutes = require("./permission")
21
21
  const datasourceRoutes = require("./datasource")
22
22
  const queryRoutes = require("./query")
23
- const hostingRoutes = require("./hosting")
24
23
  const backupRoutes = require("./backup")
25
24
  const metadataRoutes = require("./metadata")
26
25
  const devRoutes = require("./dev")
27
26
  const cloudRoutes = require("./cloud")
27
+ const migrationRoutes = require("./migrations")
28
28
 
29
29
  exports.mainRoutes = [
30
30
  authRoutes,
@@ -46,7 +46,6 @@ exports.mainRoutes = [
46
46
  permissionRoutes,
47
47
  datasourceRoutes,
48
48
  queryRoutes,
49
- hostingRoutes,
50
49
  backupRoutes,
51
50
  metadataRoutes,
52
51
  devRoutes,
@@ -55,6 +54,7 @@ exports.mainRoutes = [
55
54
  // this could be breaking as koa may recognise other routes as this
56
55
  tableRoutes,
57
56
  rowRoutes,
57
+ migrationRoutes,
58
58
  ]
59
59
 
60
60
  exports.staticRoutes = staticRoutes
@@ -0,0 +1,14 @@
1
+ const Router = require("@koa/router")
2
+ const migrationsController = require("../controllers/migrations")
3
+ const router = Router()
4
+ const { internalApi } = require("@budibase/backend-core/auth")
5
+
6
+ router
7
+ .post("/api/migrations/run", internalApi, migrationsController.migrate)
8
+ .get(
9
+ "/api/migrations/definitions",
10
+ internalApi,
11
+ migrationsController.fetchDefinitions
12
+ )
13
+
14
+ module.exports = router
@@ -46,5 +46,10 @@ router
46
46
  )
47
47
  // TODO: this likely needs to be secured in some way
48
48
  .get("/:appId/:path*", controller.serveApp)
49
+ .post(
50
+ "/api/attachments/:datasourceId/url",
51
+ authorized(PermissionTypes.TABLE, PermissionLevels.READ),
52
+ controller.getSignedUploadURL
53
+ )
49
54
 
50
55
  module.exports = router
@@ -53,8 +53,8 @@ describe("/applications", () => {
53
53
 
54
54
  describe("fetch", () => {
55
55
  it("lists all applications", async () => {
56
- await config.createApp(request, "app1")
57
- await config.createApp(request, "app2")
56
+ await config.createApp("app1")
57
+ await config.createApp("app2")
58
58
 
59
59
  const res = await request
60
60
  .get(`/api/applications?status=${AppStatus.DEV}`)
@@ -13,10 +13,9 @@ describe("/authenticate", () => {
13
13
 
14
14
  describe("fetch self", () => {
15
15
  it("should be able to fetch self", async () => {
16
- const headers = await config.login()
17
16
  const res = await request
18
17
  .get(`/api/self`)
19
- .set(headers)
18
+ .set(config.defaultHeaders())
20
19
  .expect("Content-Type", /json/)
21
20
  .expect(200)
22
21
  expect(res.body._id).toEqual(generateUserMetadataID("us_uuid1"))
@@ -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
+ })
package/src/app.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // need to load environment first
2
2
  import { ExtendableContext } from "koa"
3
3
 
4
- const env = require("./environment")
4
+ import * as env from "./environment"
5
5
  const CouchDB = require("./db")
6
6
  require("@budibase/backend-core").init(CouchDB)
7
7
  const Koa = require("koa")
@@ -16,6 +16,7 @@ const Sentry = require("@sentry/node")
16
16
  const fileSystem = require("./utilities/fileSystem")
17
17
  const bullboard = require("./automations/bullboard")
18
18
  const redis = require("./utilities/redis")
19
+ import * as migrations from "./migrations"
19
20
 
20
21
  const app = new Koa()
21
22
 
@@ -84,13 +85,25 @@ module.exports = server.listen(env.PORT || 0, async () => {
84
85
  await automations.init()
85
86
  })
86
87
 
87
- process.on("uncaughtException", err => {
88
- console.error(err)
88
+ const shutdown = () => {
89
89
  server.close()
90
90
  server.destroy()
91
+ }
92
+
93
+ process.on("uncaughtException", err => {
94
+ console.error(err)
95
+ shutdown()
91
96
  })
92
97
 
93
98
  process.on("SIGTERM", () => {
94
- server.close()
95
- server.destroy()
99
+ shutdown()
96
100
  })
101
+
102
+ // run migrations on startup if not done via http
103
+ // not recommended in a clustered environment
104
+ if (!env.HTTP_MIGRATIONS) {
105
+ migrations.migrate().catch(err => {
106
+ console.error("Error performing migrations. Exiting.\n", err)
107
+ shutdown()
108
+ })
109
+ }
@@ -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,
@@ -45,19 +45,27 @@ exports.FieldTypes = {
45
45
  INTERNAL: "internal",
46
46
  }
47
47
 
48
- exports.SwitchableTypes = [
49
- exports.FieldTypes.STRING,
50
- exports.FieldTypes.OPTIONS,
51
- exports.FieldTypes.NUMBER,
52
- exports.FieldTypes.BOOLEAN,
48
+ exports.CanSwitchTypes = [
49
+ [exports.FieldTypes.JSON, exports.FieldTypes.ARRAY],
50
+ [exports.FieldTypes.STRING, exports.FieldTypes.OPTIONS],
51
+ [exports.FieldTypes.BOOLEAN, exports.FieldTypes.NUMBER],
53
52
  ]
54
53
 
54
+ exports.SwitchableTypes = exports.CanSwitchTypes.reduce((prev, current) =>
55
+ prev ? prev.concat(current) : current
56
+ )
57
+
55
58
  exports.RelationshipTypes = {
56
59
  ONE_TO_MANY: "one-to-many",
57
60
  MANY_TO_ONE: "many-to-one",
58
61
  MANY_TO_MANY: "many-to-many",
59
62
  }
60
63
 
64
+ exports.FormulaTypes = {
65
+ STATIC: "static",
66
+ DYNAMIC: "dynamic",
67
+ }
68
+
61
69
  exports.AuthTypes = {
62
70
  APP: "app",
63
71
  BUILDER: "builder",
@@ -75,6 +83,10 @@ exports.DataSourceOperation = {
75
83
  DELETE_TABLE: "DELETE_TABLE",
76
84
  }
77
85
 
86
+ exports.DatasourceAuthTypes = {
87
+ GOOGLE: "google",
88
+ }
89
+
78
90
  exports.SortDirection = {
79
91
  ASCENDING: "ASCENDING",
80
92
  DESCENDING: "DESCENDING",
@@ -72,7 +72,7 @@ async function getLinksForRows(appId, rows) {
72
72
  )
73
73
  }
74
74
 
75
- async function getFullLinkedDocs(ctx, appId, links) {
75
+ async function getFullLinkedDocs(appId, links) {
76
76
  // create DBs
77
77
  const db = new CouchDB(appId)
78
78
  const linkedRowIds = links.map(link => link.id)
@@ -146,13 +146,12 @@ exports.updateLinks = async function (args) {
146
146
  /**
147
147
  * Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
148
148
  * This is required for formula fields, this may only be utilised internally (for now).
149
- * @param {object} ctx The request which is looking for rows.
149
+ * @param {string} appId The ID of the app which this request is in the context of.
150
150
  * @param {object} table The table from which the rows originated.
151
151
  * @param {array<object>} rows The rows which are to be enriched.
152
152
  * @return {Promise<*>} returns the rows with all of the enriched relationships on it.
153
153
  */
154
- exports.attachFullLinkedDocs = async (ctx, table, rows) => {
155
- const appId = ctx.appId
154
+ exports.attachFullLinkedDocs = async (appId, table, rows) => {
156
155
  const linkedTableIds = getLinkedTableIDs(table)
157
156
  if (linkedTableIds.length === 0) {
158
157
  return rows
@@ -166,7 +165,7 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
166
165
  // clear any existing links that could be dupe'd
167
166
  rows = clearRelationshipFields(table, rows)
168
167
  // now get the docs and combine into the rows
169
- let linked = await getFullLinkedDocs(ctx, appId, links)
168
+ let linked = await getFullLinkedDocs(appId, links)
170
169
  const linkedTables = []
171
170
  for (let row of rows) {
172
171
  for (let link of links.filter(link => link.thisId === row._id)) {
@@ -17,6 +17,8 @@ export interface FieldSchema {
17
17
  autocolumn?: boolean
18
18
  throughFrom?: string
19
19
  throughTo?: string
20
+ formula?: string
21
+ formulaType?: string
20
22
  main?: boolean
21
23
  meta?: {
22
24
  toTable: string
@@ -46,6 +48,7 @@ export interface Table extends Base {
46
48
  schema: TableSchema
47
49
  primaryDisplay?: string
48
50
  sourceId?: string
51
+ relatedFormula?: string[]
49
52
  constrained?: string[]
50
53
  }
51
54
 
@@ -47,6 +47,7 @@ export enum SourceNames {
47
47
  ARANGODB = "ARANGODB",
48
48
  REST = "REST",
49
49
  ORACLE = "ORACLE",
50
+ GOOGLE_SHEETS = "GOOGLE_SHEETS",
50
51
  }
51
52
 
52
53
  export enum IncludeRelationships {
@@ -86,6 +87,8 @@ export interface ExtraQueryConfig {
86
87
  export interface Integration {
87
88
  docs: string
88
89
  plus?: boolean
90
+ auth?: { type: string }
91
+ relationships?: boolean
89
92
  description: string
90
93
  friendlyName: string
91
94
  datasource: {}
@@ -38,10 +38,12 @@ 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,
44
45
  MULTI_TENANCY: process.env.MULTI_TENANCY,
46
+ HTTP_MIGRATIONS: process.env.HTTP_MIGRATIONS,
45
47
  // environment
46
48
  NODE_ENV: process.env.NODE_ENV,
47
49
  JEST_WORKER_ID: process.env.JEST_WORKER_ID,