@budibase/server 0.9.186 → 0.9.190-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 (309) hide show
  1. package/Dockerfile +7 -1
  2. package/LICENSE +1 -1
  3. package/__mocks__/mssql.ts +1 -1
  4. package/__mocks__/oracledb.ts +31 -0
  5. package/__mocks__/pg.ts +3 -0
  6. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  7. package/builder/assets/index.43f4c913.js +1316 -0
  8. package/builder/assets/index.7d405e74.css +1 -0
  9. package/builder/assets/oracle.66592424.png +0 -0
  10. package/builder/assets/vendor.470042a4.js +152 -0
  11. package/builder/assets/vendor.5e1fe644.css +1 -0
  12. package/builder/index.html +4 -4
  13. package/coverage/clover.xml +1520 -1087
  14. package/coverage/coverage-final.json +93 -89
  15. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  16. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  17. package/coverage/lcov-report/api/controllers/application.js.html +64 -13
  18. package/coverage/lcov-report/api/controllers/auth.js.html +19 -10
  19. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  20. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  23. package/coverage/lcov-report/api/controllers/datasource.js.html +232 -28
  24. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  25. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  26. package/coverage/lcov-report/api/controllers/index.html +91 -91
  27. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  30. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  31. package/coverage/lcov-report/api/controllers/query.js.html +53 -209
  32. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  33. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  34. package/coverage/lcov-report/api/controllers/row/external.js.html +17 -8
  35. package/coverage/lcov-report/api/controllers/row/index.html +26 -26
  36. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  37. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  38. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  39. package/coverage/lcov-report/api/controllers/row/utils.js.html +21 -30
  40. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  41. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  42. package/coverage/lcov-report/api/controllers/table/external.js.html +1001 -0
  43. package/coverage/lcov-report/api/controllers/table/index.html +56 -26
  44. package/coverage/lcov-report/api/controllers/table/index.js.html +80 -350
  45. package/coverage/lcov-report/api/controllers/table/internal.js.html +545 -0
  46. package/coverage/lcov-report/api/controllers/table/utils.js.html +175 -52
  47. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  48. package/coverage/lcov-report/api/controllers/user.js.html +390 -33
  49. package/coverage/lcov-report/api/controllers/view/exporters.js.html +19 -4
  50. package/coverage/lcov-report/api/controllers/view/index.html +22 -22
  51. package/coverage/lcov-report/api/controllers/view/index.js.html +52 -13
  52. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  53. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  54. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  55. package/coverage/lcov-report/api/index.html +1 -1
  56. package/coverage/lcov-report/api/index.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  68. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/index.html +4 -4
  70. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  76. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  77. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  78. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  82. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  83. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  84. package/coverage/lcov-report/api/routes/user.js.html +17 -2
  85. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  86. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  87. package/coverage/lcov-report/automations/actions.js.html +2 -2
  88. package/coverage/lcov-report/automations/automationUtils.js.html +4 -4
  89. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  90. package/coverage/lcov-report/automations/index.html +35 -50
  91. package/coverage/lcov-report/automations/index.js.html +2 -2
  92. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  94. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  96. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  97. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  98. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  99. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/index.html +14 -14
  101. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  103. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  104. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  105. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  106. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  107. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  108. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  109. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  110. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  113. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  114. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  115. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  116. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  117. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  118. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  119. package/coverage/lcov-report/automations/utils.js.html +42 -12
  120. package/coverage/lcov-report/constants/index.html +5 -5
  121. package/coverage/lcov-report/constants/index.js.html +87 -21
  122. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  123. package/coverage/lcov-report/constants/screens.js.html +1 -1
  124. package/coverage/lcov-report/db/client.js.html +2 -2
  125. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  126. package/coverage/lcov-report/db/index.html +2 -2
  127. package/coverage/lcov-report/db/index.js.html +1 -1
  128. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  129. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  130. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  131. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  132. package/coverage/lcov-report/db/newid.js.html +3 -3
  133. package/coverage/lcov-report/db/utils.js.html +57 -57
  134. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  135. package/coverage/lcov-report/events/index.html +6 -6
  136. package/coverage/lcov-report/events/index.js.html +1 -1
  137. package/coverage/lcov-report/events/utils.js.html +5 -5
  138. package/coverage/lcov-report/index.html +108 -93
  139. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  140. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  141. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  142. package/coverage/lcov-report/middleware/authorized.js.html +58 -34
  143. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  144. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  145. package/coverage/lcov-report/middleware/index.html +27 -27
  146. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  147. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  148. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  149. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  150. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  151. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +90 -33
  152. package/coverage/lcov-report/threads/index.html +141 -0
  153. package/coverage/lcov-report/threads/index.js.html +278 -0
  154. package/coverage/lcov-report/threads/query.js.html +278 -0
  155. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  156. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  157. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  158. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  159. package/coverage/lcov-report/utilities/global.js.html +26 -11
  160. package/coverage/lcov-report/utilities/index.html +48 -48
  161. package/coverage/lcov-report/utilities/index.js.html +47 -14
  162. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  163. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  164. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  165. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  166. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  167. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  168. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  169. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  170. package/coverage/lcov-report/utilities/security.js.html +3 -3
  171. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  172. package/coverage/lcov-report/utilities/users.js.html +1 -1
  173. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  174. package/coverage/lcov.info +2558 -1787
  175. package/dist/api/controllers/application.js +15 -1
  176. package/dist/api/controllers/auth.js +3 -3
  177. package/dist/api/controllers/datasource.js +67 -16
  178. package/dist/api/controllers/deploy/index.js +2 -0
  179. package/dist/api/controllers/dev.js +4 -1
  180. package/dist/api/controllers/query.js +30 -58
  181. package/dist/api/controllers/row/ExternalRequest.js +37 -14
  182. package/dist/api/controllers/row/external.js +3 -1
  183. package/dist/api/controllers/row/utils.js +6 -12
  184. package/dist/api/controllers/table/external.js +249 -0
  185. package/dist/api/controllers/table/index.js +49 -123
  186. package/dist/api/controllers/table/internal.js +150 -0
  187. package/dist/api/controllers/table/utils.js +62 -28
  188. package/dist/api/controllers/user.js +123 -11
  189. package/dist/api/controllers/view/exporters.js +4 -0
  190. package/dist/api/controllers/view/index.js +14 -2
  191. package/dist/api/routes/query.js +1 -1
  192. package/dist/api/routes/table.js +7 -1
  193. package/dist/api/routes/user.js +2 -1
  194. package/dist/app.js +2 -11
  195. package/dist/automations/bullboard.js +37 -10
  196. package/dist/automations/triggers.js +7 -3
  197. package/dist/automations/utils.js +11 -2
  198. package/dist/constants/index.js +19 -0
  199. package/dist/definitions/datasource.js +5 -0
  200. package/dist/environment.js +13 -0
  201. package/dist/integrations/base/IntegrationBase.js +2 -0
  202. package/dist/integrations/base/datasourcePlus.js +2 -0
  203. package/dist/integrations/base/sql.js +338 -180
  204. package/dist/integrations/base/sqlTable.js +143 -0
  205. package/dist/integrations/base/utils.js +30 -0
  206. package/dist/integrations/index.js +6 -0
  207. package/dist/integrations/microsoftSqlServer.js +117 -9
  208. package/dist/integrations/mysql.js +14 -84
  209. package/dist/integrations/oracle.js +345 -0
  210. package/dist/integrations/postgres.js +35 -28
  211. package/dist/integrations/utils.js +71 -9
  212. package/dist/middleware/authorized.js +22 -11
  213. package/dist/middleware/builder.js +4 -1
  214. package/dist/package.json +13 -8
  215. package/dist/tests/utilities/TestConfiguration.js +2 -1
  216. package/dist/{automations/thread.js → threads/automation.js} +26 -8
  217. package/dist/threads/index.js +64 -0
  218. package/dist/threads/query.js +64 -0
  219. package/dist/tsconfig.tsbuildinfo +1 -1
  220. package/dist/utilities/csvParser.js +46 -5
  221. package/dist/utilities/global.js +6 -2
  222. package/dist/utilities/index.js +11 -0
  223. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  224. package/dist/utilities/scriptRunner.js +4 -1
  225. package/package.json +14 -9
  226. package/scripts/dev/manage.js +1 -0
  227. package/scripts/integrations/mssql/data/Dockerfile +9 -0
  228. package/scripts/integrations/mssql/data/entrypoint.sh +24 -0
  229. package/scripts/integrations/mssql/data/setup.sql +54 -0
  230. package/scripts/integrations/mssql/docker-compose.yaml +12 -0
  231. package/scripts/integrations/mssql/reset.sh +3 -0
  232. package/scripts/integrations/oracle/docker-compose.yml +19 -0
  233. package/scripts/integrations/oracle/instantclient/linux/x86-64/basiclite-21.4.zip +0 -0
  234. package/scripts/integrations/oracle/instantclient/linux/x86-64/install.sh +23 -0
  235. package/scripts/integrations/oracle/oracle.md +90 -0
  236. package/scripts/integrations/postgres/docker-compose.yml +3 -3
  237. package/scripts/likeCypress.ts +33 -0
  238. package/src/api/controllers/application.js +18 -1
  239. package/src/api/controllers/auth.js +3 -0
  240. package/src/api/controllers/datasource.js +84 -16
  241. package/src/api/controllers/deploy/index.js +2 -0
  242. package/src/api/controllers/dev.js +4 -1
  243. package/src/api/controllers/query.js +29 -81
  244. package/src/api/controllers/row/ExternalRequest.ts +47 -16
  245. package/src/api/controllers/row/external.js +4 -1
  246. package/src/api/controllers/row/utils.js +8 -11
  247. package/src/api/controllers/table/external.js +307 -0
  248. package/src/api/controllers/table/index.js +47 -137
  249. package/src/api/controllers/table/internal.js +155 -0
  250. package/src/api/controllers/table/utils.js +74 -33
  251. package/src/api/controllers/user.js +132 -13
  252. package/src/api/controllers/view/exporters.js +5 -0
  253. package/src/api/controllers/view/index.js +15 -2
  254. package/src/api/routes/query.js +1 -0
  255. package/src/api/routes/table.js +11 -0
  256. package/src/api/routes/tests/datasource.spec.js +2 -2
  257. package/src/api/routes/tests/misc.spec.js +5 -1
  258. package/src/api/routes/tests/query.spec.js +0 -1
  259. package/src/api/routes/user.js +5 -0
  260. package/src/app.ts +2 -10
  261. package/src/automations/bullboard.js +28 -11
  262. package/src/automations/tests/automation.spec.js +3 -4
  263. package/src/automations/triggers.js +7 -3
  264. package/src/automations/utils.js +12 -2
  265. package/src/constants/index.js +22 -0
  266. package/src/definitions/common.ts +7 -1
  267. package/src/definitions/datasource.ts +10 -3
  268. package/src/environment.js +15 -0
  269. package/src/integrations/airtable.ts +2 -1
  270. package/src/integrations/arangodb.ts +2 -1
  271. package/src/integrations/base/IntegrationBase.ts +6 -0
  272. package/src/integrations/base/datasourcePlus.ts +9 -0
  273. package/src/integrations/base/sql.ts +362 -222
  274. package/src/integrations/base/sqlTable.ts +180 -0
  275. package/src/integrations/base/utils.ts +22 -0
  276. package/src/integrations/couchdb.ts +2 -1
  277. package/src/integrations/dynamodb.ts +2 -1
  278. package/src/integrations/elasticsearch.ts +2 -1
  279. package/src/integrations/index.ts +7 -0
  280. package/src/integrations/microsoftSqlServer.ts +145 -13
  281. package/src/integrations/mongodb.ts +2 -1
  282. package/src/integrations/mysql.ts +20 -94
  283. package/src/integrations/oracle.ts +445 -0
  284. package/src/integrations/postgres.ts +45 -35
  285. package/src/integrations/rest.ts +2 -1
  286. package/src/integrations/s3.ts +2 -1
  287. package/src/integrations/tests/microsoftSqlServer.spec.js +22 -15
  288. package/src/integrations/tests/oracle.spec.js +94 -0
  289. package/src/integrations/tests/postgres.spec.js +4 -0
  290. package/src/integrations/utils.ts +74 -8
  291. package/src/middleware/authorized.js +26 -18
  292. package/src/middleware/builder.js +4 -1
  293. package/src/middleware/tests/authorized.spec.js +2 -0
  294. package/src/tests/utilities/TestConfiguration.js +2 -1
  295. package/src/{automations/thread.js → threads/automation.js} +27 -8
  296. package/src/threads/index.js +66 -0
  297. package/src/threads/query.js +66 -0
  298. package/src/utilities/csvParser.js +48 -5
  299. package/src/utilities/global.js +7 -2
  300. package/src/utilities/index.js +11 -0
  301. package/src/utilities/queue/inMemoryQueue.js +7 -0
  302. package/src/utilities/scriptRunner.js +4 -1
  303. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  304. package/src/utilities/tests/csvParser.spec.js +3 -0
  305. package/tsconfig.json +1 -1
  306. package/builder/assets/index.10556cc1.js +0 -201
  307. package/builder/assets/index.7469e1e4.css +0 -29
  308. package/builder/assets/vendor.278a305c.js +0 -9
  309. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -8,7 +8,7 @@ const {
8
8
  const { isEqual } = require("lodash/fp")
9
9
  const { AutoFieldSubTypes, FieldTypes } = require("../../../constants")
10
10
  const { inputProcessing } = require("../../../utilities/rowProcessor")
11
- const { USERS_TABLE_SCHEMA } = require("../../../constants")
11
+ const { USERS_TABLE_SCHEMA, SwitchableTypes } = require("../../../constants")
12
12
  const {
13
13
  isExternalTable,
14
14
  breakExternalTableId,
@@ -72,43 +72,47 @@ exports.makeSureTableUpToDate = (table, tableToSave) => {
72
72
  }
73
73
 
74
74
  exports.handleDataImport = async (appId, user, table, dataImport) => {
75
+ if (!dataImport || !dataImport.csvString) {
76
+ return table
77
+ }
75
78
  const db = new CouchDB(appId)
76
- if (dataImport && dataImport.csvString) {
77
- // Populate the table with rows imported from CSV in a bulk update
78
- const data = await csvParser.transform(dataImport)
79
-
80
- let finalData = []
81
- for (let i = 0; i < data.length; i++) {
82
- let row = data[i]
83
- row._id = generateRowID(table._id)
84
- row.tableId = table._id
85
- const processed = inputProcessing(user, table, row, {
86
- noAutoRelationships: true,
87
- })
88
- table = processed.table
89
- row = processed.row
90
-
91
- for (let [fieldName, schema] of Object.entries(table.schema)) {
92
- // check whether the options need to be updated for inclusion as part of the data import
93
- if (
94
- schema.type === FieldTypes.OPTIONS &&
95
- (!schema.constraints.inclusion ||
96
- schema.constraints.inclusion.indexOf(row[fieldName]) === -1)
97
- ) {
98
- schema.constraints.inclusion = [
99
- ...schema.constraints.inclusion,
100
- row[fieldName],
101
- ]
102
- }
103
- }
79
+ // Populate the table with rows imported from CSV in a bulk update
80
+ const data = await csvParser.transform({
81
+ ...dataImport,
82
+ existingTable: table,
83
+ })
84
+
85
+ let finalData = []
86
+ for (let i = 0; i < data.length; i++) {
87
+ let row = data[i]
88
+ row._id = generateRowID(table._id)
89
+ row.tableId = table._id
90
+ const processed = inputProcessing(user, table, row, {
91
+ noAutoRelationships: true,
92
+ })
93
+ table = processed.table
94
+ row = processed.row
104
95
 
105
- finalData.push(row)
96
+ for (let [fieldName, schema] of Object.entries(table.schema)) {
97
+ // check whether the options need to be updated for inclusion as part of the data import
98
+ if (
99
+ schema.type === FieldTypes.OPTIONS &&
100
+ (!schema.constraints.inclusion ||
101
+ schema.constraints.inclusion.indexOf(row[fieldName]) === -1)
102
+ ) {
103
+ schema.constraints.inclusion = [
104
+ ...schema.constraints.inclusion,
105
+ row[fieldName],
106
+ ]
107
+ }
106
108
  }
107
109
 
108
- await db.bulkDocs(finalData)
109
- let response = await db.put(table)
110
- table._rev = response._rev
110
+ finalData.push(row)
111
111
  }
112
+
113
+ await db.bulkDocs(finalData)
114
+ let response = await db.put(table)
115
+ table._rev = response._rev
112
116
  return table
113
117
  }
114
118
 
@@ -315,4 +319,41 @@ exports.checkForViewUpdates = async (db, table, rename, deletedColumns) => {
315
319
  }
316
320
  }
317
321
 
322
+ exports.generateForeignKey = (column, relatedTable) => {
323
+ return `fk_${relatedTable.name}_${column.fieldName}`
324
+ }
325
+
326
+ exports.generateJunctionTableName = (column, table, relatedTable) => {
327
+ return `jt_${table.name}_${relatedTable.name}_${column.name}_${column.fieldName}`
328
+ }
329
+
330
+ exports.foreignKeyStructure = (keyName, meta = null) => {
331
+ const structure = {
332
+ type: FieldTypes.NUMBER,
333
+ constraints: {},
334
+ name: keyName,
335
+ }
336
+ if (meta) {
337
+ structure.meta = meta
338
+ }
339
+ return structure
340
+ }
341
+
342
+ exports.hasTypeChanged = (table, oldTable) => {
343
+ if (!oldTable) {
344
+ return false
345
+ }
346
+ for (let [key, field] of Object.entries(oldTable.schema)) {
347
+ const oldType = field.type
348
+ if (!table.schema[key]) {
349
+ continue
350
+ }
351
+ const newType = table.schema[key].type
352
+ if (oldType !== newType && SwitchableTypes.indexOf(oldType) === -1) {
353
+ return true
354
+ }
355
+ }
356
+ return false
357
+ }
358
+
318
359
  exports.TableSaveFunctions = TableSaveFunctions
@@ -4,27 +4,144 @@ const {
4
4
  getUserMetadataParams,
5
5
  } = require("../../db/utils")
6
6
  const { InternalTables } = require("../../db/utils")
7
- const { getGlobalUsers } = require("../../utilities/global")
7
+ const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global")
8
8
  const { getFullUser } = require("../../utilities/users")
9
+ const { isEqual } = require("lodash")
10
+ const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles")
11
+ const { getDevelopmentAppID, getDeployedAppIDs } = require("@budibase/auth/db")
12
+ const { doesDatabaseExist } = require("../../utilities")
13
+ const { UserStatus } = require("@budibase/auth/constants")
9
14
 
10
- function removeGlobalProps(user) {
11
- // make sure to always remove some of the global user props
15
+ async function rawMetadata(db) {
16
+ return (
17
+ await db.allDocs(
18
+ getUserMetadataParams(null, {
19
+ include_docs: true,
20
+ })
21
+ )
22
+ ).rows.map(row => row.doc)
23
+ }
24
+
25
+ function combineMetadataAndUser(user, metadata) {
26
+ // skip users with no access
27
+ if (user.roleId === BUILTIN_ROLE_IDS.PUBLIC) {
28
+ return null
29
+ }
30
+ delete user._rev
31
+ const metadataId = generateUserMetadataID(user._id)
32
+ const newDoc = {
33
+ ...user,
34
+ _id: metadataId,
35
+ tableId: InternalTables.USER_METADATA,
36
+ }
37
+ const found = Array.isArray(metadata)
38
+ ? metadata.find(doc => doc._id === metadataId)
39
+ : metadata
40
+ // copy rev over for the purposes of equality check
41
+ if (found) {
42
+ newDoc._rev = found._rev
43
+ }
44
+ if (found == null || !isEqual(newDoc, found)) {
45
+ return {
46
+ ...found,
47
+ ...newDoc,
48
+ }
49
+ }
50
+ return null
51
+ }
52
+
53
+ exports.syncGlobalUsers = async appId => {
54
+ // sync user metadata
55
+ const db = new CouchDB(appId)
56
+ const [users, metadata] = await Promise.all([
57
+ getGlobalUsers(appId),
58
+ rawMetadata(db),
59
+ ])
60
+ const toWrite = []
61
+ for (let user of users) {
62
+ const combined = await combineMetadataAndUser(user, metadata)
63
+ if (combined) {
64
+ toWrite.push(combined)
65
+ }
66
+ }
67
+ await db.bulkDocs(toWrite)
68
+ }
69
+
70
+ exports.syncUser = async function (ctx) {
71
+ let deleting = false,
72
+ user
73
+ const userId = ctx.params.id
74
+ try {
75
+ user = await getRawGlobalUser(userId)
76
+ } catch (err) {
77
+ if (err && err.status === 404) {
78
+ user = {}
79
+ deleting = true
80
+ } else {
81
+ throw err
82
+ }
83
+ }
84
+ const roles = user.roles
85
+ // remove props which aren't useful to metadata
12
86
  delete user.password
87
+ delete user.forceResetPassword
13
88
  delete user.roles
14
- delete user.builder
15
- return user
89
+ // run through all production appIDs in the users roles
90
+ let prodAppIds
91
+ // if they are a builder then get all production app IDs
92
+ if ((user.builder && user.builder.global) || deleting) {
93
+ prodAppIds = await getDeployedAppIDs(CouchDB)
94
+ } else {
95
+ prodAppIds = Object.entries(roles)
96
+ .filter(entry => entry[1] !== BUILTIN_ROLE_IDS.PUBLIC)
97
+ .map(([appId]) => appId)
98
+ }
99
+ for (let prodAppId of prodAppIds) {
100
+ const roleId = roles[prodAppId]
101
+ const devAppId = getDevelopmentAppID(prodAppId)
102
+ for (let appId of [prodAppId, devAppId]) {
103
+ if (!(await doesDatabaseExist(appId))) {
104
+ continue
105
+ }
106
+ const db = new CouchDB(appId)
107
+ const metadataId = generateUserMetadataID(userId)
108
+ let metadata
109
+ try {
110
+ metadata = await db.get(metadataId)
111
+ } catch (err) {
112
+ if (deleting) {
113
+ continue
114
+ }
115
+ metadata = {
116
+ tableId: InternalTables.USER_METADATA,
117
+ }
118
+ }
119
+ // assign the roleId for the metadata doc
120
+ if (roleId) {
121
+ metadata.roleId = roleId
122
+ }
123
+ let combined = !deleting
124
+ ? combineMetadataAndUser(user, metadata)
125
+ : {
126
+ ...metadata,
127
+ status: UserStatus.INACTIVE,
128
+ metadata: BUILTIN_ROLE_IDS.PUBLIC,
129
+ }
130
+ // if its null then there was no updates required
131
+ if (combined) {
132
+ await db.put(combined)
133
+ }
134
+ }
135
+ }
136
+ ctx.body = {
137
+ message: "User synced.",
138
+ }
16
139
  }
17
140
 
18
141
  exports.fetchMetadata = async function (ctx) {
19
142
  const database = new CouchDB(ctx.appId)
20
143
  const global = await getGlobalUsers(ctx.appId)
21
- const metadata = (
22
- await database.allDocs(
23
- getUserMetadataParams(null, {
24
- include_docs: true,
25
- })
26
- )
27
- ).rows.map(row => row.doc)
144
+ const metadata = await rawMetadata(database)
28
145
  const users = []
29
146
  for (let user of global) {
30
147
  // find the metadata that matches up to the global ID
@@ -52,7 +169,9 @@ exports.updateSelfMetadata = async function (ctx) {
52
169
  exports.updateMetadata = async function (ctx) {
53
170
  const appId = ctx.appId
54
171
  const db = new CouchDB(appId)
55
- const user = removeGlobalProps(ctx.request.body)
172
+ const user = ctx.request.body
173
+ // this isn't applicable to the user
174
+ delete user.roles
56
175
  const metadata = {
57
176
  tableId: InternalTables.USER_METADATA,
58
177
  ...user,
@@ -16,3 +16,8 @@ exports.csv = function (headers, rows) {
16
16
  exports.json = function (headers, rows) {
17
17
  return JSON.stringify(rows, undefined, 2)
18
18
  }
19
+
20
+ exports.ExportFormats = {
21
+ CSV: "csv",
22
+ JSON: "json",
23
+ }
@@ -4,6 +4,7 @@ const { apiFileReturn } = require("../../../utilities/fileSystem")
4
4
  const exporters = require("./exporters")
5
5
  const { saveView, getView, getViews, deleteView } = require("./utils")
6
6
  const { fetchView } = require("../row")
7
+ const { getTable } = require("../table/utils")
7
8
 
8
9
  exports.fetch = async ctx => {
9
10
  const db = new CouchDB(ctx.appId)
@@ -56,7 +57,7 @@ exports.exportView = async ctx => {
56
57
  const view = await getView(db, viewName)
57
58
 
58
59
  const format = ctx.query.format
59
- if (!format) {
60
+ if (!format || !Object.values(exporters.ExportFormats).includes(format)) {
60
61
  ctx.throw(400, "Format must be specified, either csv or json")
61
62
  }
62
63
 
@@ -80,10 +81,22 @@ exports.exportView = async ctx => {
80
81
  let schema = view && view.meta && view.meta.schema
81
82
  if (!schema) {
82
83
  const tableId = ctx.params.tableId || view.meta.tableId
83
- const table = await db.get(tableId)
84
+ const table = await getTable(ctx.appId, tableId)
84
85
  schema = table.schema
85
86
  }
86
87
 
88
+ // make sure no "undefined" entries appear in the CSV
89
+ if (format === exporters.ExportFormats.CSV) {
90
+ const schemaKeys = Object.keys(schema)
91
+ for (let key of schemaKeys) {
92
+ for (let row of ctx.body) {
93
+ if (row[key] == null) {
94
+ row[key] = ""
95
+ }
96
+ }
97
+ }
98
+ }
99
+
87
100
  // Export part
88
101
  let headers = Object.keys(schema)
89
102
  const exporter = exporters[format]
@@ -66,6 +66,7 @@ router
66
66
  )
67
67
  .get(
68
68
  "/api/queries/:queryId",
69
+ paramResource("queryId"),
69
70
  authorized(PermissionTypes.QUERY, PermissionLevels.READ),
70
71
  queryController.find
71
72
  )
@@ -53,5 +53,16 @@ router
53
53
  authorized(BUILDER),
54
54
  tableController.destroy
55
55
  )
56
+ // this is currently builder only, but in the future
57
+ // it could be carried out by an end user in app,
58
+ // however some thought will need to be had about
59
+ // implications for automations (triggers)
60
+ // new trigger type, bulk rows created
61
+ .post(
62
+ "/api/tables/:tableId/import",
63
+ paramResource("tableId"),
64
+ authorized(BUILDER),
65
+ tableController.bulkImport
66
+ )
56
67
 
57
68
  module.exports = router
@@ -26,8 +26,8 @@ describe("/datasources", () => {
26
26
  .expect('Content-Type', /json/)
27
27
  .expect(200)
28
28
 
29
- expect(res.res.statusMessage).toEqual("Datasource saved successfully.")
30
- expect(res.body.name).toEqual("Test")
29
+ expect(res.body.datasource.name).toEqual("Test")
30
+ expect(res.body.errors).toBeUndefined()
31
31
  })
32
32
  })
33
33
 
@@ -75,7 +75,11 @@ describe("run misc tests", () => {
75
75
  },
76
76
  })
77
77
  const dataImport = {
78
- csvString: "a,b,c,d\n1,2,3,4"
78
+ csvString: "a,b,c,d\n1,2,3,4",
79
+ schema: {},
80
+ }
81
+ for (let col of ["a", "b", "c", "d"]) {
82
+ dataImport.schema[col] = { type: "string" }
79
83
  }
80
84
  await tableUtils.handleDataImport(
81
85
  config.getAppId(),
@@ -1,7 +1,6 @@
1
1
  // mock out postgres for this
2
2
  jest.mock("pg")
3
3
 
4
- const { findLastKey } = require("lodash/fp")
5
4
  const setup = require("./utilities")
6
5
  const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
7
6
  const { basicQuery, basicDatasource } = setup.structures
@@ -34,5 +34,10 @@ router
34
34
  authorized(PermissionTypes.USER, PermissionLevels.WRITE),
35
35
  controller.destroyMetadata
36
36
  )
37
+ .post(
38
+ "/api/users/metadata/sync/:id",
39
+ authorized(PermissionTypes.USER, PermissionLevels.WRITE),
40
+ controller.syncUser
41
+ )
37
42
 
38
43
  module.exports = router
package/src/app.ts CHANGED
@@ -41,16 +41,8 @@ app.use(
41
41
  )
42
42
 
43
43
  if (!env.isTest()) {
44
- const bullApp = bullboard.init()
45
- app.use(async (ctx: ExtendableContext, next: () => any) => {
46
- if (ctx.path.startsWith(bullboard.pathPrefix)) {
47
- ctx.status = 200
48
- ctx.respond = false
49
- bullApp(ctx.req, ctx.res)
50
- } else {
51
- await next()
52
- }
53
- })
44
+ const plugin = bullboard.init()
45
+ app.use(plugin)
54
46
  }
55
47
 
56
48
  app.context.eventEmitter = eventEmitter
@@ -1,6 +1,6 @@
1
- const { createBullBoard } = require("bull-board")
2
- const { BullAdapter } = require("bull-board/bullAdapter")
3
- const express = require("express")
1
+ const { createBullBoard } = require("@bull-board/api")
2
+ const { BullAdapter } = require("@bull-board/api/bullAdapter")
3
+ const { KoaAdapter } = require("@bull-board/koa")
4
4
  const env = require("../environment")
5
5
  const Queue = env.isTest()
6
6
  ? require("../utilities/queue/inMemoryQueue")
@@ -9,23 +9,40 @@ const { JobQueues } = require("../constants")
9
9
  const { utils } = require("@budibase/auth/redis")
10
10
  const { opts, redisProtocolUrl } = utils.getRedisOptions()
11
11
 
12
- const redisConfig = redisProtocolUrl || { redis: opts }
13
- let automationQueue = new Queue(JobQueues.AUTOMATIONS, redisConfig)
12
+ const CLEANUP_PERIOD_MS = 60 * 1000
13
+ const queueConfig = redisProtocolUrl || { redis: opts }
14
+ let cleanupInternal = null
14
15
 
15
- exports.pathPrefix = "/bulladmin"
16
+ let automationQueue = new Queue(JobQueues.AUTOMATIONS, queueConfig)
17
+
18
+ async function cleanup() {
19
+ await automationQueue.clean(CLEANUP_PERIOD_MS, "completed")
20
+ }
21
+
22
+ const PATH_PREFIX = "/bulladmin"
16
23
 
17
24
  exports.init = () => {
18
- const expressApp = express()
25
+ // cleanup the events every 5 minutes
26
+ if (!cleanupInternal) {
27
+ cleanupInternal = setInterval(cleanup, CLEANUP_PERIOD_MS)
28
+ // fire off an initial cleanup
29
+ cleanup().catch(err => {
30
+ console.error(`Unable to cleanup automation queue initially - ${err}`)
31
+ })
32
+ }
19
33
  // Set up queues for bull board admin
20
34
  const queues = [automationQueue]
21
35
  const adapters = []
36
+ const serverAdapter = new KoaAdapter()
22
37
  for (let queue of queues) {
23
38
  adapters.push(new BullAdapter(queue))
24
39
  }
25
- const { router } = createBullBoard(adapters)
26
-
27
- expressApp.use(exports.pathPrefix, router)
28
- return expressApp
40
+ createBullBoard({
41
+ queues: adapters,
42
+ serverAdapter,
43
+ })
44
+ serverAdapter.setBasePath(PATH_PREFIX)
45
+ return serverAdapter.registerPlugin()
29
46
  }
30
47
 
31
48
  exports.queue = automationQueue
@@ -1,5 +1,5 @@
1
1
  jest.mock("../../utilities/usageQuota")
2
- jest.mock("../thread")
2
+ jest.mock("../../threads/automation")
3
3
  jest.mock("../../utilities/redis", () => ({
4
4
  init: jest.fn(),
5
5
  checkTestFlag: () => {
@@ -11,8 +11,7 @@ jest.spyOn(global.console, "error")
11
11
 
12
12
  require("../../environment")
13
13
  const automation = require("../index")
14
- const usageQuota = require("../../utilities/usageQuota")
15
- const thread = require("../thread")
14
+ const thread = require("../../threads/automation")
16
15
  const triggers = require("../triggers")
17
16
  const { basicAutomation } = require("../../tests/utilities/structures")
18
17
  const { wait } = require("../../utilities")
@@ -62,7 +61,7 @@ describe("Run through some parts of the automations system", () => {
62
61
  }
63
62
  }
64
63
  }
65
- }))
64
+ }), expect.any(Function))
66
65
  })
67
66
 
68
67
  it("should be able to clean inputs with the utilities", () => {
@@ -11,6 +11,10 @@ const utils = require("./utils")
11
11
  const env = require("../environment")
12
12
 
13
13
  const TRIGGER_DEFINITIONS = definitions
14
+ const JOB_OPTS = {
15
+ removeOnComplete: true,
16
+ removeOnFail: true,
17
+ }
14
18
 
15
19
  async function queueRelevantRowAutomations(event, eventType) {
16
20
  if (event.appId == null) {
@@ -47,7 +51,7 @@ async function queueRelevantRowAutomations(event, eventType) {
47
51
  automationTrigger.inputs &&
48
52
  automationTrigger.inputs.tableId === event.row.tableId
49
53
  ) {
50
- await queue.add({ automation, event })
54
+ await queue.add({ automation, event }, JOB_OPTS)
51
55
  }
52
56
  }
53
57
  }
@@ -86,7 +90,7 @@ exports.externalTrigger = async function (
86
90
  automation.definition.trigger != null &&
87
91
  automation.definition.trigger.stepId === definitions.APP.stepId &&
88
92
  automation.definition.trigger.stepId === "APP" &&
89
- !checkTestFlag(automation._id)
93
+ !(await checkTestFlag(automation._id))
90
94
  ) {
91
95
  // values are likely to be submitted as strings, so we shall convert to correct type
92
96
  const coercedFields = {}
@@ -100,7 +104,7 @@ exports.externalTrigger = async function (
100
104
  if (getResponses) {
101
105
  return utils.processEvent({ data })
102
106
  } else {
103
- return queue.add(data)
107
+ return queue.add(data, JOB_OPTS)
104
108
  }
105
109
  }
106
110
 
@@ -1,4 +1,4 @@
1
- const runner = require("./thread")
1
+ const { Thread, ThreadType } = require("../threads")
2
2
  const { definitions } = require("./triggerInfo")
3
3
  const webhooks = require("../api/controllers/webhook")
4
4
  const CouchDB = require("../db")
@@ -10,11 +10,12 @@ const { getDeployedAppID } = require("@budibase/auth/db")
10
10
 
11
11
  const WH_STEP_ID = definitions.WEBHOOK.stepId
12
12
  const CRON_STEP_ID = definitions.CRON.stepId
13
+ const Runner = new Thread(ThreadType.AUTOMATION)
13
14
 
14
15
  exports.processEvent = async job => {
15
16
  try {
16
17
  // need to actually await these so that an error can be captured properly
17
- return await runner(job)
18
+ return await Runner.run(job)
18
19
  } catch (err) {
19
20
  console.error(
20
21
  `${job.data.automation.appId} automation ${job.data.automation._id} was unable to run - ${err}`
@@ -162,3 +163,12 @@ exports.checkForWebhooks = async ({ appId, oldAuto, newAuto }) => {
162
163
  }
163
164
  return newAuto
164
165
  }
166
+
167
+ /**
168
+ * When removing an app/unpublishing it need to make sure automations are cleaned up (cron).
169
+ * @param appId {string} the app that is being removed.
170
+ * @return {Promise<void>} clean is complete if this succeeds.
171
+ */
172
+ exports.cleanupAutomations = async appId => {
173
+ await exports.disableAllCrons(appId)
174
+ }
@@ -45,6 +45,13 @@ 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,
53
+ ]
54
+
48
55
  exports.RelationshipTypes = {
49
56
  ONE_TO_MANY: "one-to-many",
50
57
  MANY_TO_ONE: "many-to-one",
@@ -62,6 +69,10 @@ exports.DataSourceOperation = {
62
69
  READ: "READ",
63
70
  UPDATE: "UPDATE",
64
71
  DELETE: "DELETE",
72
+ BULK_CREATE: "BULK_CREATE",
73
+ CREATE_TABLE: "CREATE_TABLE",
74
+ UPDATE_TABLE: "UPDATE_TABLE",
75
+ DELETE_TABLE: "DELETE_TABLE",
65
76
  }
66
77
 
67
78
  exports.SortDirection = {
@@ -152,5 +163,16 @@ exports.MetadataTypes = {
152
163
  AUTOMATION_TEST_HISTORY: "automationTestHistory",
153
164
  }
154
165
 
166
+ exports.InvalidColumns = {
167
+ ID: "_id",
168
+ REV: "_rev",
169
+ TABLE_ID: "tableId",
170
+ }
171
+
172
+ exports.BuildSchemaErrors = {
173
+ NO_KEY: "no_key",
174
+ INVALID_COLUMN: "invalid_column",
175
+ }
176
+
155
177
  // pass through the list from the auth/core lib
156
178
  exports.ObjectStoreBuckets = ObjectStoreBuckets
@@ -17,6 +17,11 @@ export interface FieldSchema {
17
17
  autocolumn?: boolean
18
18
  throughFrom?: string
19
19
  throughTo?: string
20
+ main?: boolean
21
+ meta?: {
22
+ toTable: string
23
+ toKey: string
24
+ }
20
25
  constraints?: {
21
26
  type?: string
22
27
  email?: boolean
@@ -36,11 +41,12 @@ export interface TableSchema {
36
41
  export interface Table extends Base {
37
42
  type?: string
38
43
  views?: {}
39
- name?: string
44
+ name: string
40
45
  primary?: string[]
41
46
  schema: TableSchema
42
47
  primaryDisplay?: string
43
48
  sourceId?: string
49
+ constrained?: string[]
44
50
  }
45
51
 
46
52
  export interface Row extends Base {