@budibase/server 1.0.49 → 1.0.50-alpha.0

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 (381) hide show
  1. package/__mocks__/arangojs.ts +1 -1
  2. package/__mocks__/aws-sdk.ts +4 -4
  3. package/__mocks__/mongodb.ts +4 -5
  4. package/__mocks__/mssql.ts +3 -3
  5. package/__mocks__/node-fetch.ts +2 -1
  6. package/__mocks__/pg.ts +3 -5
  7. package/builder/assets/index.c0cc369d.css +6 -0
  8. package/builder/assets/{index.2c37968e.js → index.ff2bad21.js} +252 -249
  9. package/builder/assets/{vendor.f9faf6ab.js → vendor.5ad9695a.js} +202 -106
  10. package/builder/index.html +3 -3
  11. package/coverage/clover.xml +3105 -2814
  12. package/coverage/coverage-final.json +106 -101
  13. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/application.js.html +257 -152
  16. package/coverage/lcov-report/api/controllers/auth.js.html +22 -13
  17. package/coverage/lcov-report/api/controllers/automation.js.html +39 -69
  18. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/cloud.js.html +8 -11
  20. package/coverage/lcov-report/api/controllers/component.js.html +13 -16
  21. package/coverage/lcov-report/api/controllers/datasource.js.html +81 -51
  22. package/coverage/lcov-report/api/controllers/dev.js.html +6 -6
  23. package/coverage/lcov-report/api/controllers/index.html +78 -78
  24. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  25. package/coverage/lcov-report/api/controllers/layout.js.html +9 -9
  26. package/coverage/lcov-report/api/controllers/metadata.js.html +6 -21
  27. package/coverage/lcov-report/api/controllers/migrations.js.html +119 -0
  28. package/coverage/lcov-report/api/controllers/permission.js.html +19 -19
  29. package/coverage/lcov-report/api/controllers/query/index.html +10 -10
  30. package/coverage/lcov-report/api/controllers/query/index.js.html +38 -35
  31. package/coverage/lcov-report/api/controllers/query/validation.js.html +6 -6
  32. package/coverage/lcov-report/api/controllers/role.js.html +16 -16
  33. package/coverage/lcov-report/api/controllers/routing.js.html +7 -10
  34. package/coverage/lcov-report/api/controllers/row/external.js.html +48 -141
  35. package/coverage/lcov-report/api/controllers/row/index.html +55 -40
  36. package/coverage/lcov-report/api/controllers/row/index.js.html +26 -26
  37. package/coverage/lcov-report/api/controllers/row/internal.js.html +118 -226
  38. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +52 -34
  39. package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +548 -0
  40. package/coverage/lcov-report/api/controllers/row/utils.js.html +47 -62
  41. package/coverage/lcov-report/api/controllers/screen.js.html +15 -21
  42. package/coverage/lcov-report/api/controllers/script.js.html +4 -4
  43. package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +599 -0
  44. package/coverage/lcov-report/api/controllers/table/external.js.html +25 -34
  45. package/coverage/lcov-report/api/controllers/table/index.html +58 -43
  46. package/coverage/lcov-report/api/controllers/table/index.js.html +58 -82
  47. package/coverage/lcov-report/api/controllers/table/internal.js.html +81 -66
  48. package/coverage/lcov-report/api/controllers/table/utils.js.html +218 -110
  49. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  50. package/coverage/lcov-report/api/controllers/user.js.html +79 -76
  51. package/coverage/lcov-report/api/controllers/view/exporters.js.html +4 -4
  52. package/coverage/lcov-report/api/controllers/view/index.html +16 -16
  53. package/coverage/lcov-report/api/controllers/view/index.js.html +27 -33
  54. package/coverage/lcov-report/api/controllers/view/utils.js.html +35 -20
  55. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +7 -7
  56. package/coverage/lcov-report/api/controllers/webhook.js.html +34 -28
  57. package/coverage/lcov-report/api/index.html +1 -1
  58. package/coverage/lcov-report/api/index.js.html +8 -8
  59. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/index.html +18 -18
  71. package/coverage/lcov-report/api/routes/index.js.html +3 -3
  72. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/{hosting.js.html → migrations.js.html} +17 -14
  76. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  82. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  83. package/coverage/lcov-report/api/routes/static.js.html +17 -2
  84. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  85. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  86. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  87. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  88. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  89. package/coverage/lcov-report/automations/actions.js.html +24 -24
  90. package/coverage/lcov-report/automations/automationUtils.js.html +7 -10
  91. package/coverage/lcov-report/automations/bullboard.js.html +16 -16
  92. package/coverage/lcov-report/automations/index.html +18 -18
  93. package/coverage/lcov-report/automations/index.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/bash.js.html +6 -6
  95. package/coverage/lcov-report/automations/steps/createRow.js.html +13 -22
  96. package/coverage/lcov-report/automations/steps/delay.js.html +4 -4
  97. package/coverage/lcov-report/automations/steps/deleteRow.js.html +11 -20
  98. package/coverage/lcov-report/automations/steps/discord.js.html +7 -7
  99. package/coverage/lcov-report/automations/steps/executeQuery.js.html +6 -6
  100. package/coverage/lcov-report/automations/steps/executeScript.js.html +6 -6
  101. package/coverage/lcov-report/automations/steps/filter.js.html +7 -7
  102. package/coverage/lcov-report/automations/steps/index.html +13 -13
  103. package/coverage/lcov-report/automations/steps/integromat.js.html +5 -5
  104. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +8 -8
  105. package/coverage/lcov-report/automations/steps/queryRows.js.html +10 -10
  106. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +5 -5
  107. package/coverage/lcov-report/automations/steps/serverLog.js.html +3 -3
  108. package/coverage/lcov-report/automations/steps/slack.js.html +5 -5
  109. package/coverage/lcov-report/automations/steps/updateRow.js.html +7 -7
  110. package/coverage/lcov-report/automations/steps/utils.js.html +3 -3
  111. package/coverage/lcov-report/automations/steps/zapier.js.html +5 -5
  112. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  114. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  115. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  116. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  117. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  118. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  119. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  120. package/coverage/lcov-report/automations/triggers.js.html +61 -55
  121. package/coverage/lcov-report/automations/utils.js.html +54 -42
  122. package/coverage/lcov-report/constants/index.html +5 -5
  123. package/coverage/lcov-report/constants/index.js.html +53 -26
  124. package/coverage/lcov-report/constants/layouts.js.html +5 -5
  125. package/coverage/lcov-report/constants/screens.js.html +4 -4
  126. package/coverage/lcov-report/db/client.js.html +18 -18
  127. package/coverage/lcov-report/db/inMemoryView.js.html +7 -7
  128. package/coverage/lcov-report/db/index.html +15 -15
  129. package/coverage/lcov-report/db/index.js.html +3 -3
  130. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +25 -37
  131. package/coverage/lcov-report/db/linkedRows/index.html +27 -27
  132. package/coverage/lcov-report/db/linkedRows/index.js.html +51 -96
  133. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +42 -42
  134. package/coverage/lcov-report/db/newid.js.html +4 -4
  135. package/coverage/lcov-report/db/utils.js.html +87 -87
  136. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  137. package/coverage/lcov-report/events/index.html +1 -1
  138. package/coverage/lcov-report/events/index.js.html +5 -5
  139. package/coverage/lcov-report/events/utils.js.html +3 -3
  140. package/coverage/lcov-report/index.html +135 -120
  141. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  142. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  143. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  144. package/coverage/lcov-report/middleware/authorized.js.html +173 -65
  145. package/coverage/lcov-report/middleware/builder.js.html +10 -10
  146. package/coverage/lcov-report/middleware/currentapp.js.html +95 -83
  147. package/coverage/lcov-report/middleware/index.html +38 -38
  148. package/coverage/lcov-report/middleware/joi-validator.js.html +3 -3
  149. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  150. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  151. package/coverage/lcov-report/middleware/usageQuota.js.html +281 -53
  152. package/coverage/lcov-report/middleware/utils.js.html +2 -2
  153. package/coverage/lcov-report/threads/automation.js.html +30 -24
  154. package/coverage/lcov-report/threads/index.html +26 -26
  155. package/coverage/lcov-report/threads/index.js.html +10 -10
  156. package/coverage/lcov-report/threads/query.js.html +39 -24
  157. package/coverage/lcov-report/threads/utils.js.html +14 -14
  158. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  159. package/coverage/lcov-report/utilities/budibaseDir.js.html +7 -7
  160. package/coverage/lcov-report/utilities/centralPath.js.html +4 -4
  161. package/coverage/lcov-report/utilities/csvParser.js.html +6 -6
  162. package/coverage/lcov-report/utilities/global.js.html +58 -49
  163. package/coverage/lcov-report/utilities/index.html +37 -37
  164. package/coverage/lcov-report/utilities/index.js.html +43 -73
  165. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +8 -8
  166. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  167. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  168. package/coverage/lcov-report/utilities/routing/index.js.html +7 -7
  169. package/coverage/lcov-report/utilities/rowProcessor/index.html +27 -27
  170. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +97 -103
  171. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +75 -27
  172. package/coverage/lcov-report/utilities/scriptRunner.js.html +5 -5
  173. package/coverage/lcov-report/utilities/security.js.html +8 -8
  174. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  175. package/coverage/lcov-report/utilities/usageQuota/index.html +141 -0
  176. package/coverage/lcov-report/utilities/usageQuota/index.js.html +359 -0
  177. package/coverage/lcov-report/utilities/usageQuota/rows.js.html +305 -0
  178. package/coverage/lcov-report/{api/controllers/hosting.js.html → utilities/usageQuota/usageQuoteReset.js.html} +36 -48
  179. package/coverage/lcov-report/utilities/users.js.html +9 -9
  180. package/coverage/lcov-report/utilities/workerRequests.js.html +43 -112
  181. package/coverage/lcov.info +5010 -4425
  182. package/dist/api/controllers/application.js +90 -60
  183. package/dist/api/controllers/auth.js +8 -5
  184. package/dist/api/controllers/automation.js +14 -19
  185. package/dist/api/controllers/cloud.js +2 -3
  186. package/dist/api/controllers/component.js +3 -4
  187. package/dist/api/controllers/datasource.js +20 -10
  188. package/dist/api/controllers/deploy/Deployment.js +3 -6
  189. package/dist/api/controllers/deploy/index.js +12 -13
  190. package/dist/api/controllers/dev.js +5 -5
  191. package/dist/api/controllers/layout.js +3 -3
  192. package/dist/api/controllers/metadata.js +4 -4
  193. package/dist/api/controllers/migrations.js +21 -0
  194. package/dist/api/controllers/permission.js +4 -4
  195. package/dist/api/controllers/query/import/index.js +4 -6
  196. package/dist/api/controllers/query/index.js +11 -10
  197. package/dist/api/controllers/role.js +5 -5
  198. package/dist/api/controllers/routing.js +5 -6
  199. package/dist/api/controllers/row/ExternalRequest.js +90 -67
  200. package/dist/api/controllers/row/external.js +14 -22
  201. package/dist/api/controllers/row/internal.js +55 -93
  202. package/dist/api/controllers/row/internalSearch.js +23 -17
  203. package/dist/api/controllers/row/staticFormula.js +147 -0
  204. package/dist/api/controllers/row/utils.js +13 -14
  205. package/dist/api/controllers/screen.js +5 -7
  206. package/dist/api/controllers/static/index.js +62 -16
  207. package/dist/api/controllers/table/bulkFormula.js +159 -0
  208. package/dist/api/controllers/table/external.js +7 -10
  209. package/dist/api/controllers/table/index.js +16 -13
  210. package/dist/api/controllers/table/internal.js +22 -16
  211. package/dist/api/controllers/table/utils.js +62 -35
  212. package/dist/api/controllers/user.js +43 -43
  213. package/dist/api/controllers/view/index.js +8 -10
  214. package/dist/api/controllers/view/utils.js +9 -4
  215. package/dist/api/controllers/webhook.js +10 -8
  216. package/dist/api/routes/index.js +2 -2
  217. package/dist/api/routes/migrations.js +9 -0
  218. package/dist/api/routes/static.js +2 -1
  219. package/dist/api/routes/tests/utilities/TestFunctions.js +37 -17
  220. package/dist/app.js +35 -5
  221. package/dist/automations/automationUtils.js +2 -3
  222. package/dist/automations/steps/createRow.js +3 -5
  223. package/dist/automations/steps/deleteRow.js +1 -4
  224. package/dist/automations/steps/updateRow.js +1 -1
  225. package/dist/automations/triggers.js +27 -25
  226. package/dist/automations/utils.js +10 -5
  227. package/dist/constants/index.js +7 -0
  228. package/dist/db/linkedRows/LinkController.js +3 -7
  229. package/dist/db/linkedRows/index.js +16 -27
  230. package/dist/db/linkedRows/linkUtils.js +6 -6
  231. package/dist/db/views/staticViews.js +9 -10
  232. package/dist/definitions/datasource.js +1 -0
  233. package/dist/environment.js +4 -1
  234. package/dist/integrations/base/sql.js +62 -21
  235. package/dist/integrations/googlesheets.js +340 -0
  236. package/dist/integrations/index.js +3 -0
  237. package/dist/integrations/utils.js +60 -9
  238. package/dist/middleware/authorized.js +57 -30
  239. package/dist/middleware/builder.js +2 -2
  240. package/dist/middleware/currentapp.js +41 -37
  241. package/dist/middleware/usageQuota.js +82 -15
  242. package/dist/migrations/functions/appUrls.js +46 -0
  243. package/dist/migrations/functions/quotas1.js +50 -0
  244. package/dist/migrations/functions/usageQuotas/index.js +20 -0
  245. package/dist/migrations/functions/usageQuotas/syncApps.js +29 -0
  246. package/dist/migrations/functions/usageQuotas/syncRows.js +33 -0
  247. package/dist/migrations/functions/userEmailViewCasing.js +24 -0
  248. package/dist/migrations/index.js +62 -0
  249. package/dist/package.json +8 -5
  250. package/dist/tests/utilities/TestConfiguration.js +80 -50
  251. package/dist/threads/automation.js +13 -11
  252. package/dist/threads/query.js +15 -11
  253. package/dist/tsconfig.tsbuildinfo +1 -1
  254. package/dist/utilities/fileSystem/index.js +4 -3
  255. package/dist/utilities/global.js +15 -12
  256. package/dist/utilities/index.js +7 -17
  257. package/dist/utilities/routing/index.js +5 -5
  258. package/dist/utilities/rowProcessor/index.js +23 -17
  259. package/dist/utilities/rowProcessor/utils.js +14 -4
  260. package/dist/utilities/{usageQuota.js → usageQuota/index.js} +45 -31
  261. package/dist/utilities/usageQuota/rows.js +78 -0
  262. package/dist/utilities/usageQuota/usageQuoteReset.js +16 -0
  263. package/dist/utilities/users.js +3 -3
  264. package/dist/utilities/workerRequests.js +4 -24
  265. package/nodemon.json +1 -1
  266. package/package.json +9 -6
  267. package/scripts/integrations/mssql/data/Dockerfile +1 -1
  268. package/scripts/integrations/mssql/data/setup.sql +17 -4
  269. package/scripts/integrations/postgres/init.sql +11 -6
  270. package/scripts/likeCypress.ts +1 -1
  271. package/src/api/controllers/application.js +85 -50
  272. package/src/api/controllers/auth.js +8 -5
  273. package/src/api/controllers/automation.js +13 -23
  274. package/src/api/controllers/cloud.js +2 -3
  275. package/src/api/controllers/component.js +3 -4
  276. package/src/api/controllers/datasource.js +21 -11
  277. package/src/api/controllers/deploy/Deployment.js +3 -7
  278. package/src/api/controllers/deploy/index.js +20 -13
  279. package/src/api/controllers/dev.js +5 -5
  280. package/src/api/controllers/layout.js +3 -3
  281. package/src/api/controllers/metadata.js +4 -9
  282. package/src/api/controllers/migrations.js +13 -0
  283. package/src/api/controllers/permission.js +4 -4
  284. package/src/api/controllers/query/import/index.ts +4 -6
  285. package/src/api/controllers/query/import/tests/index.spec.js +2 -1
  286. package/src/api/controllers/query/index.js +11 -10
  287. package/src/api/controllers/role.js +5 -5
  288. package/src/api/controllers/routing.js +5 -6
  289. package/src/api/controllers/row/ExternalRequest.ts +67 -43
  290. package/src/api/controllers/row/external.js +27 -58
  291. package/src/api/controllers/row/internal.js +54 -90
  292. package/src/api/controllers/row/internalSearch.js +23 -17
  293. package/src/api/controllers/row/staticFormula.js +156 -0
  294. package/src/api/controllers/row/utils.js +13 -18
  295. package/src/api/controllers/screen.js +5 -7
  296. package/src/api/controllers/static/index.js +66 -15
  297. package/src/api/controllers/table/bulkFormula.js +173 -0
  298. package/src/api/controllers/table/external.js +7 -10
  299. package/src/api/controllers/table/index.js +20 -28
  300. package/src/api/controllers/table/internal.js +24 -19
  301. package/src/api/controllers/table/utils.js +78 -42
  302. package/src/api/controllers/user.js +46 -45
  303. package/src/api/controllers/view/index.js +8 -10
  304. package/src/api/controllers/view/utils.js +9 -4
  305. package/src/api/controllers/webhook.js +10 -8
  306. package/src/api/routes/index.js +2 -2
  307. package/src/api/routes/migrations.js +14 -0
  308. package/src/api/routes/static.js +5 -0
  309. package/src/api/routes/tests/application.spec.js +2 -2
  310. package/src/api/routes/tests/auth.spec.js +1 -2
  311. package/src/api/routes/tests/automation.spec.js +1 -0
  312. package/src/api/routes/tests/misc.spec.js +0 -1
  313. package/src/api/routes/tests/routing.spec.js +21 -12
  314. package/src/api/routes/tests/row.spec.js +7 -4
  315. package/src/api/routes/tests/static.spec.js +98 -0
  316. package/src/api/routes/tests/utilities/TestFunctions.js +39 -17
  317. package/src/app.ts +18 -5
  318. package/src/automations/automationUtils.js +2 -3
  319. package/src/automations/steps/createRow.js +2 -5
  320. package/src/automations/steps/deleteRow.js +1 -4
  321. package/src/automations/steps/updateRow.js +1 -1
  322. package/src/automations/triggers.js +33 -31
  323. package/src/automations/utils.js +9 -5
  324. package/src/constants/index.js +9 -0
  325. package/src/db/linkedRows/LinkController.js +3 -7
  326. package/src/db/linkedRows/index.js +16 -31
  327. package/src/db/linkedRows/linkUtils.js +6 -6
  328. package/src/db/tests/linkController.spec.js +0 -1
  329. package/src/db/tests/linkTests.spec.js +5 -6
  330. package/src/db/views/staticViews.js +8 -10
  331. package/src/definitions/common.ts +3 -0
  332. package/src/definitions/datasource.ts +3 -0
  333. package/src/environment.js +4 -1
  334. package/src/integrations/base/sql.ts +75 -29
  335. package/src/integrations/googlesheets.ts +353 -0
  336. package/src/integrations/index.ts +3 -0
  337. package/src/integrations/tests/sql.spec.js +16 -0
  338. package/src/integrations/utils.ts +75 -12
  339. package/src/middleware/authorized.js +66 -30
  340. package/src/middleware/builder.js +2 -2
  341. package/src/middleware/currentapp.js +50 -46
  342. package/src/middleware/tests/authorized.spec.js +13 -6
  343. package/src/middleware/tests/currentapp.spec.js +6 -0
  344. package/src/middleware/tests/usageQuota.spec.js +18 -24
  345. package/src/middleware/usageQuota.js +93 -17
  346. package/src/migrations/functions/appUrls.ts +34 -0
  347. package/src/migrations/functions/quotas1.ts +20 -0
  348. package/src/migrations/functions/tests/appUrls.spec.js +29 -0
  349. package/src/migrations/functions/tests/quotas1.spec.js +27 -0
  350. package/src/migrations/functions/tests/userEmailViewCasing.spec.js +25 -0
  351. package/src/migrations/functions/usageQuotas/index.ts +8 -0
  352. package/src/migrations/functions/usageQuotas/syncApps.ts +18 -0
  353. package/src/migrations/functions/usageQuotas/syncRows.ts +22 -0
  354. package/src/migrations/functions/usageQuotas/tests/syncApps.spec.js +37 -0
  355. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.js +43 -0
  356. package/src/migrations/functions/userEmailViewCasing.ts +13 -0
  357. package/src/migrations/index.ts +56 -0
  358. package/src/module.d.ts +3 -0
  359. package/src/tests/utilities/TestConfiguration.js +82 -55
  360. package/src/threads/automation.js +17 -15
  361. package/src/threads/query.js +17 -12
  362. package/src/utilities/fileSystem/index.js +4 -3
  363. package/src/utilities/global.js +15 -12
  364. package/src/utilities/index.js +7 -17
  365. package/src/utilities/routing/index.js +5 -5
  366. package/src/utilities/rowProcessor/index.js +25 -27
  367. package/src/utilities/rowProcessor/utils.js +23 -7
  368. package/src/utilities/tests/usageQuota/usageQuota.spec.js +72 -0
  369. package/src/utilities/usageQuota/index.js +93 -0
  370. package/src/utilities/usageQuota/rows.js +75 -0
  371. package/src/utilities/usageQuota/usageQuoteReset.js +18 -0
  372. package/src/utilities/users.js +3 -3
  373. package/src/utilities/workerRequests.js +4 -27
  374. package/tsconfig.json +2 -1
  375. package/builder/assets/index.39e01193.css +0 -1
  376. package/dist/api/controllers/hosting.js +0 -30
  377. package/dist/api/routes/hosting.js +0 -11
  378. package/src/api/controllers/hosting.js +0 -22
  379. package/src/api/routes/hosting.js +0 -13
  380. package/src/api/routes/tests/hosting.spec.js +0 -36
  381. package/src/utilities/usageQuota.js +0 -73
@@ -0,0 +1,353 @@
1
+ import {
2
+ DatasourceFieldTypes,
3
+ Integration,
4
+ QueryJson,
5
+ QueryTypes,
6
+ } from "../definitions/datasource"
7
+ import { OAuth2Client } from "google-auth-library"
8
+ import { DatasourcePlus } from "./base/datasourcePlus"
9
+ import { Row, Table, TableSchema } from "../definitions/common"
10
+ import { buildExternalTableId } from "./utils"
11
+ import { DataSourceOperation, FieldTypes } from "../constants"
12
+ import { GoogleSpreadsheet } from "google-spreadsheet"
13
+ import { table } from "console"
14
+
15
+ module GoogleSheetsModule {
16
+ const { getGlobalDB } = require("@budibase/backend-core/tenancy")
17
+ const { getScopedConfig } = require("@budibase/backend-core/db")
18
+ const { Configs } = require("@budibase/backend-core/constants")
19
+
20
+ interface GoogleSheetsConfig {
21
+ spreadsheetId: string
22
+ auth: OAuthClientConfig
23
+ }
24
+
25
+ interface OAuthClientConfig {
26
+ appId: string
27
+ accessToken: string
28
+ refreshToken: string
29
+ }
30
+
31
+ const SCHEMA: Integration = {
32
+ plus: true,
33
+ auth: {
34
+ type: "google",
35
+ },
36
+ relationships: false,
37
+ docs: "https://developers.google.com/sheets/api/quickstart/nodejs",
38
+ description:
39
+ "Create and collaborate on online spreadsheets in real-time and from any device. ",
40
+ friendlyName: "Google Sheets",
41
+ datasource: {
42
+ spreadsheetId: {
43
+ type: DatasourceFieldTypes.STRING,
44
+ required: true,
45
+ },
46
+ },
47
+ query: {
48
+ create: {
49
+ type: QueryTypes.FIELDS,
50
+ fields: {
51
+ sheet: {
52
+ type: DatasourceFieldTypes.STRING,
53
+ required: true,
54
+ },
55
+ row: {
56
+ type: QueryTypes.JSON,
57
+ required: true,
58
+ },
59
+ },
60
+ },
61
+ read: {
62
+ type: QueryTypes.FIELDS,
63
+ fields: {
64
+ sheet: {
65
+ type: DatasourceFieldTypes.STRING,
66
+ required: true,
67
+ },
68
+ },
69
+ },
70
+ update: {
71
+ type: QueryTypes.FIELDS,
72
+ fields: {
73
+ sheet: {
74
+ type: DatasourceFieldTypes.STRING,
75
+ required: true,
76
+ },
77
+ rowIndex: {
78
+ type: DatasourceFieldTypes.STRING,
79
+ required: true,
80
+ },
81
+ row: {
82
+ type: QueryTypes.JSON,
83
+ required: true,
84
+ },
85
+ },
86
+ },
87
+ delete: {
88
+ type: QueryTypes.FIELDS,
89
+ fields: {
90
+ sheet: {
91
+ type: DatasourceFieldTypes.STRING,
92
+ required: true,
93
+ },
94
+ rowIndex: {
95
+ type: DatasourceFieldTypes.NUMBER,
96
+ required: true,
97
+ },
98
+ },
99
+ },
100
+ },
101
+ }
102
+
103
+ class GoogleSheetsIntegration implements DatasourcePlus {
104
+ private readonly config: GoogleSheetsConfig
105
+ private client: any
106
+ public tables: Record<string, Table> = {}
107
+ public schemaErrors: Record<string, string> = {}
108
+
109
+ constructor(config: GoogleSheetsConfig) {
110
+ this.config = config
111
+ const spreadsheetId = this.cleanSpreadsheetUrl(this.config.spreadsheetId)
112
+ this.client = new GoogleSpreadsheet(spreadsheetId)
113
+ }
114
+
115
+ /**
116
+ * Pull the spreadsheet ID out from a valid google sheets URL
117
+ * @param spreadsheetId - the URL or standard spreadsheetId of the google sheet
118
+ * @returns spreadsheet Id of the google sheet
119
+ */
120
+ cleanSpreadsheetUrl(spreadsheetId: string) {
121
+ if (!spreadsheetId) {
122
+ throw new Error(
123
+ "You must set a spreadsheet ID in your configuration to fetch tables."
124
+ )
125
+ }
126
+ const parts = spreadsheetId.split("/")
127
+ return parts.length > 5 ? parts[5] : spreadsheetId
128
+ }
129
+
130
+ async connect() {
131
+ try {
132
+ // Initialise oAuth client
133
+ const db = getGlobalDB()
134
+ const googleConfig = await getScopedConfig(db, {
135
+ type: Configs.GOOGLE,
136
+ })
137
+ const oauthClient = new OAuth2Client({
138
+ clientId: googleConfig.clientID,
139
+ clientSecret: googleConfig.clientSecret,
140
+ })
141
+ oauthClient.credentials.access_token = this.config.auth.accessToken
142
+ oauthClient.credentials.refresh_token = this.config.auth.refreshToken
143
+ this.client.useOAuth2Client(oauthClient)
144
+ await this.client.loadInfo()
145
+ } catch (err) {
146
+ console.error("Error connecting to google sheets", err)
147
+ throw err
148
+ }
149
+ }
150
+
151
+ async buildSchema(datasourceId: string) {
152
+ await this.connect()
153
+ const sheets = await this.client.sheetsByIndex
154
+ const tables: Record<string, Table> = {}
155
+ for (let sheet of sheets) {
156
+ // must fetch rows to determine schema
157
+ await sheet.getRows()
158
+ // build schema
159
+ const schema: TableSchema = {}
160
+
161
+ // build schema from headers
162
+ for (let header of sheet.headerValues) {
163
+ schema[header] = {
164
+ name: header,
165
+ type: FieldTypes.STRING,
166
+ }
167
+ }
168
+
169
+ // create tables
170
+ tables[sheet.title] = {
171
+ _id: buildExternalTableId(datasourceId, sheet.title),
172
+ name: sheet.title,
173
+ primary: ["rowNumber"],
174
+ schema,
175
+ }
176
+ }
177
+
178
+ this.tables = tables
179
+ }
180
+
181
+ async query(json: QueryJson) {
182
+ const sheet = json.endpoint.entityId
183
+
184
+ const handlers = {
185
+ [DataSourceOperation.CREATE]: () =>
186
+ this.create({ sheet, row: json.body }),
187
+ [DataSourceOperation.READ]: () => this.read({ sheet }),
188
+ [DataSourceOperation.UPDATE]: () =>
189
+ this.update({
190
+ // exclude the header row and zero index
191
+ rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
192
+ sheet,
193
+ row: json.body,
194
+ }),
195
+ [DataSourceOperation.DELETE]: () =>
196
+ this.delete({
197
+ // exclude the header row and zero index
198
+ rowIndex: json.extra?.idFilter?.equal?.rowNumber - 2,
199
+ sheet,
200
+ }),
201
+ [DataSourceOperation.CREATE_TABLE]: () =>
202
+ this.createTable(json?.table?.name),
203
+ [DataSourceOperation.UPDATE_TABLE]: () => this.updateTable(json.table),
204
+ [DataSourceOperation.DELETE_TABLE]: () =>
205
+ this.deleteTable(json?.table?.name),
206
+ }
207
+
208
+ const internalQueryMethod = handlers[json.endpoint.operation]
209
+
210
+ return await internalQueryMethod()
211
+ }
212
+
213
+ buildRowObject(headers: string[], values: string[], rowNumber: number) {
214
+ const rowObject: { rowNumber: number; [key: string]: any } = { rowNumber }
215
+ for (let i = 0; i < headers.length; i++) {
216
+ rowObject._id = rowNumber
217
+ rowObject[headers[i]] = values[i]
218
+ }
219
+ return rowObject
220
+ }
221
+
222
+ async createTable(name?: string) {
223
+ try {
224
+ await this.connect()
225
+ const sheet = await this.client.addSheet({ title: name })
226
+ return sheet
227
+ } catch (err) {
228
+ console.error("Error creating new table in google sheets", err)
229
+ throw err
230
+ }
231
+ }
232
+
233
+ async updateTable(table?: any) {
234
+ try {
235
+ await this.connect()
236
+ const sheet = await this.client.sheetsByTitle[table.name]
237
+ await sheet.loadHeaderRow()
238
+
239
+ if (table._rename) {
240
+ const headers = []
241
+ for (let header of sheet.headerValues) {
242
+ if (header === table._rename.old) {
243
+ headers.push(table._rename.updated)
244
+ } else {
245
+ headers.push(header)
246
+ }
247
+ }
248
+ await sheet.setHeaderRow(headers)
249
+ } else {
250
+ let newField = Object.keys(table.schema).find(
251
+ key => !sheet.headerValues.includes(key)
252
+ )
253
+ await sheet.setHeaderRow([...sheet.headerValues, newField])
254
+ }
255
+ } catch (err) {
256
+ console.error("Error updating table in google sheets", err)
257
+ throw err
258
+ }
259
+ }
260
+
261
+ async deleteTable(sheet: any) {
262
+ try {
263
+ await this.connect()
264
+ const sheetToDelete = await this.client.sheetsByTitle[sheet]
265
+ return await sheetToDelete.delete()
266
+ } catch (err) {
267
+ console.error("Error deleting table in google sheets", err)
268
+ throw err
269
+ }
270
+ }
271
+
272
+ async create(query: { sheet: string; row: any }) {
273
+ try {
274
+ await this.connect()
275
+ const sheet = await this.client.sheetsByTitle[query.sheet]
276
+ const rowToInsert =
277
+ typeof query.row === "string" ? JSON.parse(query.row) : query.row
278
+ const row = await sheet.addRow(rowToInsert)
279
+ return [
280
+ this.buildRowObject(sheet.headerValues, row._rawData, row._rowNumber),
281
+ ]
282
+ } catch (err) {
283
+ console.error("Error writing to google sheets", err)
284
+ throw err
285
+ }
286
+ }
287
+
288
+ async read(query: { sheet: string }) {
289
+ try {
290
+ await this.connect()
291
+ const sheet = await this.client.sheetsByTitle[query.sheet]
292
+ const rows = await sheet.getRows()
293
+ const headerValues = sheet.headerValues
294
+ const response = []
295
+ for (let row of rows) {
296
+ response.push(
297
+ this.buildRowObject(headerValues, row._rawData, row._rowNumber)
298
+ )
299
+ }
300
+ return response
301
+ } catch (err) {
302
+ console.error("Error reading from google sheets", err)
303
+ throw err
304
+ }
305
+ }
306
+
307
+ async update(query: { sheet: string; rowIndex: number; row: any }) {
308
+ try {
309
+ await this.connect()
310
+ const sheet = await this.client.sheetsByTitle[query.sheet]
311
+ const rows = await sheet.getRows()
312
+ const row = rows[query.rowIndex]
313
+ if (row) {
314
+ const updateValues = query.row
315
+ for (let key in updateValues) {
316
+ row[key] = updateValues[key]
317
+ }
318
+ await row.save()
319
+ return [
320
+ this.buildRowObject(
321
+ sheet.headerValues,
322
+ row._rawData,
323
+ row._rowNumber
324
+ ),
325
+ ]
326
+ } else {
327
+ throw new Error("Row does not exist.")
328
+ }
329
+ } catch (err) {
330
+ console.error("Error reading from google sheets", err)
331
+ throw err
332
+ }
333
+ }
334
+
335
+ async delete(query: { sheet: string; rowIndex: number }) {
336
+ await this.connect()
337
+ const sheet = await this.client.sheetsByTitle[query.sheet]
338
+ const rows = await sheet.getRows()
339
+ const row = rows[query.rowIndex]
340
+ if (row) {
341
+ await row.delete()
342
+ return [{ deleted: query.rowIndex }]
343
+ } else {
344
+ throw new Error("Row does not exist.")
345
+ }
346
+ }
347
+ }
348
+
349
+ module.exports = {
350
+ schema: SCHEMA,
351
+ integration: GoogleSheetsIntegration,
352
+ }
353
+ }
@@ -9,6 +9,7 @@ const airtable = require("./airtable")
9
9
  const mysql = require("./mysql")
10
10
  const arangodb = require("./arangodb")
11
11
  const rest = require("./rest")
12
+ const googlesheets = require("./googlesheets")
12
13
  const { SourceNames } = require("../definitions/datasource")
13
14
 
14
15
  const DEFINITIONS = {
@@ -23,6 +24,7 @@ const DEFINITIONS = {
23
24
  [SourceNames.MYSQL]: mysql.schema,
24
25
  [SourceNames.ARANGODB]: arangodb.schema,
25
26
  [SourceNames.REST]: rest.schema,
27
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.schema,
26
28
  }
27
29
 
28
30
  const INTEGRATIONS = {
@@ -37,6 +39,7 @@ const INTEGRATIONS = {
37
39
  [SourceNames.MYSQL]: mysql.integration,
38
40
  [SourceNames.ARANGODB]: arangodb.integration,
39
41
  [SourceNames.REST]: rest.integration,
42
+ [SourceNames.GOOGLE_SHEETS]: googlesheets.integration,
40
43
  }
41
44
 
42
45
  // optionally add oracle integration if the oracle binary can be installed
@@ -119,6 +119,22 @@ describe("SQL query builder", () => {
119
119
  })
120
120
  })
121
121
 
122
+ it("should allow filtering on a related field", () => {
123
+ const query = sql._query(generateReadJson({
124
+ filters: {
125
+ equal: {
126
+ age: 10,
127
+ "task.name": "task 1",
128
+ },
129
+ },
130
+ }))
131
+ // order of bindings changes because relationship filters occur outside inner query
132
+ expect(query).toEqual({
133
+ bindings: [10, limit, "task 1"],
134
+ sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."age" = $1 limit $2) as "${TABLE_NAME}" where "task"."name" = $3`
135
+ })
136
+ })
137
+
122
138
  it("should test an create statement", () => {
123
139
  const query = sql._query(generateCreateJson(TABLE_NAME, {
124
140
  name: "Michael",
@@ -1,6 +1,5 @@
1
- import { SqlQuery } from "../definitions/datasource"
1
+ import { SourceNames, SqlQuery } from "../definitions/datasource"
2
2
  import { Datasource, Table } from "../definitions/common"
3
- import { SourceNames } from "../definitions/datasource"
4
3
  import { DocumentTypes, SEPARATOR } from "../db/utils"
5
4
  import { FieldTypes, BuildSchemaErrors, InvalidColumns } from "../constants"
6
5
 
@@ -53,7 +52,10 @@ export function buildExternalTableId(datasourceId: string, tableName: string) {
53
52
  return `${datasourceId}${DOUBLE_SEPARATOR}${tableName}`
54
53
  }
55
54
 
56
- export function breakExternalTableId(tableId: string) {
55
+ export function breakExternalTableId(tableId: string | undefined) {
56
+ if (!tableId) {
57
+ return {}
58
+ }
57
59
  const parts = tableId.split(DOUBLE_SEPARATOR)
58
60
  let tableName = parts.pop()
59
61
  // if they need joined
@@ -127,7 +129,12 @@ export function isSQL(datasource: Datasource): boolean {
127
129
  if (!datasource || !datasource.source) {
128
130
  return false
129
131
  }
130
- const SQL = [SourceNames.POSTGRES, SourceNames.SQL_SERVER, SourceNames.MYSQL]
132
+ const SQL = [
133
+ SourceNames.POSTGRES,
134
+ SourceNames.SQL_SERVER,
135
+ SourceNames.MYSQL,
136
+ SourceNames.ORACLE,
137
+ ]
131
138
  return SQL.indexOf(datasource.source) !== -1
132
139
  }
133
140
 
@@ -139,11 +146,60 @@ export function isIsoDateString(str: string) {
139
146
  return d.toISOString() === str
140
147
  }
141
148
 
142
- // add the existing relationships from the entities if they exist, to prevent them from being overridden
149
+ /**
150
+ * This function will determine whether a column is a relationship and whether it
151
+ * is currently valid. The reason for the validity check is that tables can be deleted
152
+ * outside of Budibase control and if this is the case it will break Budibase relationships.
153
+ * The tableIds is a list passed down from the main finalise tables function, which is
154
+ * based on the tables that have just been fetched. This will only really be used on subsequent
155
+ * fetches to the first one - if the user is periodically refreshing Budibase knowledge of tables.
156
+ * @param column The column to check, to see if it is a valid relationship.
157
+ * @param tableIds The IDs of the tables which currently exist.
158
+ */
159
+ function shouldCopyRelationship(
160
+ column: { type: string; tableId?: string },
161
+ tableIds: [string]
162
+ ) {
163
+ return (
164
+ column.type === FieldTypes.LINK &&
165
+ column.tableId &&
166
+ tableIds.includes(column.tableId)
167
+ )
168
+ }
169
+
170
+ /**
171
+ * Similar function to the shouldCopyRelationship function, but instead this looks for options and boolean
172
+ * types. It is possible to switch a string -> options and a number -> boolean (and vice versus) need to make
173
+ * sure that these get copied over when tables are fetched. Also checks whether they are still valid, if a
174
+ * column has changed type in the external database then copying it over may not be possible.
175
+ * @param column The column to check for options or boolean type.
176
+ * @param fetchedColumn The fetched column to check for the type in the external database.
177
+ */
178
+ function shouldCopySpecialColumn(
179
+ column: { type: string },
180
+ fetchedColumn: { type: string } | undefined
181
+ ) {
182
+ return (
183
+ column.type === FieldTypes.OPTIONS ||
184
+ column.type === FieldTypes.ARRAY ||
185
+ ((!fetchedColumn || fetchedColumn.type === FieldTypes.NUMBER) &&
186
+ column.type === FieldTypes.BOOLEAN)
187
+ )
188
+ }
189
+
190
+ /**
191
+ * Looks for columns which need to be copied over into the new table definitions, like relationships
192
+ * and options types.
193
+ * @param tableName The name of the table which is being checked.
194
+ * @param table The specific table which is being checked.
195
+ * @param entities All the tables that existed before - the old table definitions.
196
+ * @param tableIds The IDs of the tables which exist now, to check if anything has been removed.
197
+ */
143
198
  function copyExistingPropsOver(
144
199
  tableName: string,
145
200
  table: Table,
146
- entities: { [key: string]: any }
201
+ entities: { [key: string]: any },
202
+ tableIds: [string]
147
203
  ) {
148
204
  if (entities && entities[tableName]) {
149
205
  if (entities[tableName].primaryDisplay) {
@@ -154,12 +210,10 @@ function copyExistingPropsOver(
154
210
  if (!existingTableSchema.hasOwnProperty(key)) {
155
211
  continue
156
212
  }
213
+ const column = existingTableSchema[key]
157
214
  if (
158
- existingTableSchema[key].type === FieldTypes.LINK ||
159
- existingTableSchema[key].type === FieldTypes.OPTIONS ||
160
- existingTableSchema[key].type === FieldTypes.ARRAY ||
161
- ((!table.schema[key] || table.schema[key].type === FieldTypes.NUMBER) &&
162
- existingTableSchema[key].type === FieldTypes.BOOLEAN)
215
+ shouldCopyRelationship(column, tableIds) ||
216
+ shouldCopySpecialColumn(column, table.schema[key])
163
217
  ) {
164
218
  table.schema[key] = existingTableSchema[key]
165
219
  }
@@ -168,6 +222,13 @@ function copyExistingPropsOver(
168
222
  return table
169
223
  }
170
224
 
225
+ /**
226
+ * Look through the final table definitions to see if anything needs to be
227
+ * copied over from the old and if any errors have occurred mark them so
228
+ * that the user can be made aware.
229
+ * @param tables The list of tables that have been retrieved from the external database.
230
+ * @param entities The old list of tables, if there was any to look for definitions in.
231
+ */
171
232
  export function finaliseExternalTables(
172
233
  tables: { [key: string]: any },
173
234
  entities: { [key: string]: any }
@@ -175,6 +236,8 @@ export function finaliseExternalTables(
175
236
  const invalidColumns = Object.values(InvalidColumns)
176
237
  let finalTables: { [key: string]: any } = {}
177
238
  const errors: { [key: string]: string } = {}
239
+ // @ts-ignore
240
+ const tableIds: [string] = Object.values(tables).map(table => table._id)
178
241
  for (let [name, table] of Object.entries(tables)) {
179
242
  const schemaFields = Object.keys(table.schema)
180
243
  // make sure every table has a key
@@ -186,7 +249,7 @@ export function finaliseExternalTables(
186
249
  continue
187
250
  }
188
251
  // make sure all previous props have been added back
189
- finalTables[name] = copyExistingPropsOver(name, table, entities)
252
+ finalTables[name] = copyExistingPropsOver(name, table, entities, tableIds)
190
253
  }
191
254
  // sort the tables by name
192
255
  finalTables = Object.entries(finalTables)
@@ -9,11 +9,60 @@ const {
9
9
  } = require("@budibase/backend-core/permissions")
10
10
  const builderMiddleware = require("./builder")
11
11
  const { isWebhookEndpoint } = require("./utils")
12
+ const { buildCsrfMiddleware } = require("@budibase/backend-core/auth")
13
+ const { getAppId } = require("@budibase/backend-core/context")
12
14
 
13
15
  function hasResource(ctx) {
14
16
  return ctx.resourceId != null
15
17
  }
16
18
 
19
+ const csrf = buildCsrfMiddleware()
20
+
21
+ /**
22
+ * Apply authorization to the requested resource:
23
+ * - If this is a builder resource the user must be a builder.
24
+ * - Builders can access all resources.
25
+ * - Otherwise the user must have the required role.
26
+ */
27
+ const checkAuthorized = async (ctx, resourceRoles, permType, permLevel) => {
28
+ // check if this is a builder api and the user is not a builder
29
+ const isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global
30
+ const isBuilderApi = permType === PermissionTypes.BUILDER
31
+ if (isBuilderApi && !isBuilder) {
32
+ return ctx.throw(403, "Not Authorized")
33
+ }
34
+
35
+ // check for resource authorization
36
+ if (!isBuilder) {
37
+ await checkAuthorizedResource(ctx, resourceRoles, permType, permLevel)
38
+ }
39
+ }
40
+
41
+ const checkAuthorizedResource = async (
42
+ ctx,
43
+ resourceRoles,
44
+ permType,
45
+ permLevel
46
+ ) => {
47
+ // get the user's roles
48
+ const roleId = ctx.roleId || BUILTIN_ROLE_IDS.PUBLIC
49
+ const userRoles = await getUserRoleHierarchy(roleId, {
50
+ idOnly: false,
51
+ })
52
+ const permError = "User does not have permission"
53
+ // check if the user has the required role
54
+ if (resourceRoles.length > 0) {
55
+ // deny access if the user doesn't have the required resource role
56
+ const found = userRoles.find(role => resourceRoles.indexOf(role._id) !== -1)
57
+ if (!found) {
58
+ ctx.throw(403, permError)
59
+ }
60
+ // fallback to the base permissions when no resource roles are found
61
+ } else if (!doesHaveBasePermission(permType, permLevel, userRoles)) {
62
+ ctx.throw(403, permError)
63
+ }
64
+ }
65
+
17
66
  module.exports =
18
67
  (permType, permLevel = null) =>
19
68
  async (ctx, next) => {
@@ -31,40 +80,27 @@ module.exports =
31
80
  // to find API endpoints which are builder focused
32
81
  await builderMiddleware(ctx, permType)
33
82
 
34
- const isAuthed = ctx.isAuthenticated
35
- // builders for now have permission to do anything
36
- let isBuilder = ctx.user && ctx.user.builder && ctx.user.builder.global
37
- const isBuilderApi = permType === PermissionTypes.BUILDER
38
- if (isBuilder) {
39
- return next()
40
- } else if (isBuilderApi && !isBuilder) {
41
- return ctx.throw(403, "Not Authorized")
83
+ // get the resource roles
84
+ let resourceRoles = []
85
+ const appId = getAppId()
86
+ if (appId && hasResource(ctx)) {
87
+ resourceRoles = await getRequiredResourceRole(permLevel, ctx)
42
88
  }
43
89
 
44
- // need to check this first, in-case public access, don't check authed until last
45
- const roleId = ctx.roleId || BUILTIN_ROLE_IDS.PUBLIC
46
- const hierarchy = await getUserRoleHierarchy(ctx.appId, roleId, {
47
- idOnly: false,
48
- })
49
- const permError = "User does not have permission"
50
- let possibleRoleIds = []
51
- if (hasResource(ctx)) {
52
- possibleRoleIds = await getRequiredResourceRole(ctx.appId, permLevel, ctx)
53
- }
54
- // check if we found a role, if not fallback to base permissions
55
- if (possibleRoleIds.length > 0) {
56
- const found = hierarchy.find(
57
- role => possibleRoleIds.indexOf(role._id) !== -1
58
- )
59
- return found ? next() : ctx.throw(403, permError)
60
- } else if (!doesHaveBasePermission(permType, permLevel, hierarchy)) {
61
- ctx.throw(403, permError)
90
+ // if the resource is public, proceed
91
+ const isPublicResource = resourceRoles.includes(BUILTIN_ROLE_IDS.PUBLIC)
92
+ if (isPublicResource) {
93
+ return next()
62
94
  }
63
95
 
64
- // if they are not authed, then anything using the authorized middleware will fail
65
- if (!isAuthed) {
66
- ctx.throw(403, "Session not authenticated")
96
+ // check authenticated
97
+ if (!ctx.isAuthenticated) {
98
+ return ctx.throw(403, "Session not authenticated")
67
99
  }
68
100
 
69
- return next()
101
+ // check authorized
102
+ await checkAuthorized(ctx, resourceRoles, permType, permLevel)
103
+
104
+ // csrf protection
105
+ return csrf(ctx, next)
70
106
  }
@@ -5,7 +5,7 @@ const {
5
5
  checkDebounce,
6
6
  setDebounce,
7
7
  } = require("../utilities/redis")
8
- const CouchDB = require("../db")
8
+ const { getDB } = require("@budibase/backend-core/db")
9
9
  const { DocumentTypes } = require("../db/utils")
10
10
  const { PermissionTypes } = require("@budibase/backend-core/permissions")
11
11
  const { app: appCache } = require("@budibase/backend-core/cache")
@@ -48,7 +48,7 @@ async function updateAppUpdatedAt(ctx) {
48
48
  if (ctx.method === "GET" || (await checkDebounce(appId))) {
49
49
  return
50
50
  }
51
- const db = new CouchDB(appId)
51
+ const db = getDB(appId)
52
52
  const metadata = await db.get(DocumentTypes.APP_METADATA)
53
53
  metadata.updatedAt = new Date().toISOString()
54
54
  const response = await db.put(metadata)