@budibase/server 0.9.185-alpha.0 → 0.9.185-alpha.12

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 (257) hide show
  1. package/Dockerfile +1 -1
  2. package/builder/assets/bb-space-man.5be51a45.svg +290 -0
  3. package/builder/assets/index.4a7c5636.css +1 -0
  4. package/builder/assets/index.708945dd.js +1316 -0
  5. package/builder/assets/vendor.470042a4.js +152 -0
  6. package/builder/assets/vendor.5e1fe644.css +1 -0
  7. package/builder/index.html +4 -4
  8. package/coverage/clover.xml +1060 -928
  9. package/coverage/coverage-final.json +90 -88
  10. package/coverage/lcov-report/api/controllers/analytics.js.html +2 -2
  11. package/coverage/lcov-report/api/controllers/apikeys.js.html +2 -2
  12. package/coverage/lcov-report/api/controllers/application.js.html +43 -13
  13. package/coverage/lcov-report/api/controllers/auth.js.html +7 -7
  14. package/coverage/lcov-report/api/controllers/automation.js.html +3 -3
  15. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  16. package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/component.js.html +4 -4
  18. package/coverage/lcov-report/api/controllers/datasource.js.html +31 -7
  19. package/coverage/lcov-report/api/controllers/dev.js.html +16 -7
  20. package/coverage/lcov-report/api/controllers/hosting.js.html +10 -10
  21. package/coverage/lcov-report/api/controllers/index.html +75 -75
  22. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/layout.js.html +3 -3
  24. package/coverage/lcov-report/api/controllers/metadata.js.html +3 -3
  25. package/coverage/lcov-report/api/controllers/permission.js.html +3 -3
  26. package/coverage/lcov-report/api/controllers/query.js.html +48 -210
  27. package/coverage/lcov-report/api/controllers/role.js.html +9 -9
  28. package/coverage/lcov-report/api/controllers/routing.js.html +3 -3
  29. package/coverage/lcov-report/api/controllers/row/external.js.html +12 -6
  30. package/coverage/lcov-report/api/controllers/row/index.html +18 -18
  31. package/coverage/lcov-report/api/controllers/row/index.js.html +2 -2
  32. package/coverage/lcov-report/api/controllers/row/internal.js.html +9 -9
  33. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +2 -2
  34. package/coverage/lcov-report/api/controllers/row/utils.js.html +2 -2
  35. package/coverage/lcov-report/api/controllers/screen.js.html +2 -2
  36. package/coverage/lcov-report/api/controllers/script.js.html +3 -3
  37. package/coverage/lcov-report/api/controllers/table/external.js.html +65 -8
  38. package/coverage/lcov-report/api/controllers/table/index.html +42 -42
  39. package/coverage/lcov-report/api/controllers/table/index.js.html +66 -12
  40. package/coverage/lcov-report/api/controllers/table/internal.js.html +49 -10
  41. package/coverage/lcov-report/api/controllers/table/utils.js.html +57 -45
  42. package/coverage/lcov-report/api/controllers/templates.js.html +4 -4
  43. package/coverage/lcov-report/api/controllers/user.js.html +33 -18
  44. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  45. package/coverage/lcov-report/api/controllers/view/index.html +9 -9
  46. package/coverage/lcov-report/api/controllers/view/index.js.html +5 -5
  47. package/coverage/lcov-report/api/controllers/view/utils.js.html +11 -11
  48. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +3 -3
  49. package/coverage/lcov-report/api/controllers/webhook.js.html +4 -4
  50. package/coverage/lcov-report/api/index.html +1 -1
  51. package/coverage/lcov-report/api/index.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  56. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/dev.js.html +2 -2
  63. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/index.html +4 -4
  65. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  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/permission.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/query.js.html +5 -2
  71. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  73. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  74. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  75. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  76. package/coverage/lcov-report/api/routes/static.js.html +2 -2
  77. package/coverage/lcov-report/api/routes/table.js.html +35 -2
  78. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  79. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  80. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  81. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  82. package/coverage/lcov-report/automations/actions.js.html +2 -2
  83. package/coverage/lcov-report/automations/automationUtils.js.html +3 -3
  84. package/coverage/lcov-report/automations/bullboard.js.html +71 -20
  85. package/coverage/lcov-report/automations/index.html +33 -48
  86. package/coverage/lcov-report/automations/index.js.html +2 -2
  87. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  90. package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/discord.js.html +3 -3
  92. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/executeScript.js.html +3 -3
  94. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  95. package/coverage/lcov-report/automations/steps/index.html +14 -14
  96. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  97. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +3 -3
  98. package/coverage/lcov-report/automations/steps/queryRows.js.html +3 -3
  99. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  100. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  101. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  102. package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
  103. package/coverage/lcov-report/automations/steps/utils.js.html +7 -7
  104. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggerInfo/app.js.html +2 -2
  106. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +2 -2
  107. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  108. package/coverage/lcov-report/automations/triggerInfo/index.js.html +8 -8
  109. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +2 -2
  110. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +2 -2
  111. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +2 -2
  112. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +2 -2
  113. package/coverage/lcov-report/automations/triggers.js.html +22 -10
  114. package/coverage/lcov-report/automations/utils.js.html +42 -12
  115. package/coverage/lcov-report/constants/index.html +1 -1
  116. package/coverage/lcov-report/constants/index.js.html +5 -2
  117. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  118. package/coverage/lcov-report/constants/screens.js.html +1 -1
  119. package/coverage/lcov-report/db/client.js.html +2 -2
  120. package/coverage/lcov-report/db/inMemoryView.js.html +2 -2
  121. package/coverage/lcov-report/db/index.html +2 -2
  122. package/coverage/lcov-report/db/index.js.html +1 -1
  123. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +6 -6
  124. package/coverage/lcov-report/db/linkedRows/index.html +10 -10
  125. package/coverage/lcov-report/db/linkedRows/index.js.html +5 -5
  126. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +6 -6
  127. package/coverage/lcov-report/db/newid.js.html +1 -1
  128. package/coverage/lcov-report/db/utils.js.html +1 -1
  129. package/coverage/lcov-report/events/AutomationEmitter.js.html +6 -6
  130. package/coverage/lcov-report/events/index.html +6 -6
  131. package/coverage/lcov-report/events/index.js.html +1 -1
  132. package/coverage/lcov-report/events/utils.js.html +5 -5
  133. package/coverage/lcov-report/index.html +94 -79
  134. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  135. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  136. package/coverage/lcov-report/middleware/appInfo.js.html +2 -2
  137. package/coverage/lcov-report/middleware/authorized.js.html +5 -5
  138. package/coverage/lcov-report/middleware/builder.js.html +16 -7
  139. package/coverage/lcov-report/middleware/currentapp.js.html +6 -6
  140. package/coverage/lcov-report/middleware/index.html +21 -21
  141. package/coverage/lcov-report/middleware/joi-validator.js.html +2 -2
  142. package/coverage/lcov-report/middleware/resourceId.js.html +18 -18
  143. package/coverage/lcov-report/middleware/selfhost.js.html +2 -2
  144. package/coverage/lcov-report/middleware/usageQuota.js.html +4 -4
  145. package/coverage/lcov-report/middleware/utils.js.html +1 -1
  146. package/coverage/lcov-report/{automations/thread.js.html → threads/automation.js.html} +83 -32
  147. package/coverage/lcov-report/threads/index.html +141 -0
  148. package/coverage/lcov-report/threads/index.js.html +260 -0
  149. package/coverage/lcov-report/threads/query.js.html +269 -0
  150. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  151. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  152. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  153. package/coverage/lcov-report/utilities/csvParser.js.html +144 -15
  154. package/coverage/lcov-report/utilities/global.js.html +2 -2
  155. package/coverage/lcov-report/utilities/index.html +34 -34
  156. package/coverage/lcov-report/utilities/index.js.html +12 -9
  157. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +30 -9
  158. package/coverage/lcov-report/utilities/queue/index.html +14 -14
  159. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  160. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  161. package/coverage/lcov-report/utilities/rowProcessor/index.html +4 -4
  162. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +2 -2
  163. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +3 -3
  164. package/coverage/lcov-report/utilities/scriptRunner.js.html +16 -7
  165. package/coverage/lcov-report/utilities/security.js.html +3 -3
  166. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  167. package/coverage/lcov-report/utilities/users.js.html +1 -1
  168. package/coverage/lcov-report/utilities/workerRequests.js.html +5 -5
  169. package/coverage/lcov.info +1753 -1527
  170. package/dist/api/controllers/application.js +11 -1
  171. package/dist/api/controllers/datasource.js +6 -2
  172. package/dist/api/controllers/deploy/index.js +2 -0
  173. package/dist/api/controllers/dev.js +4 -1
  174. package/dist/api/controllers/query.js +27 -57
  175. package/dist/api/controllers/row/ExternalRequest.js +2 -2
  176. package/dist/api/controllers/row/external.js +1 -0
  177. package/dist/api/controllers/table/external.js +17 -0
  178. package/dist/api/controllers/table/index.js +21 -2
  179. package/dist/api/controllers/table/internal.js +10 -1
  180. package/dist/api/controllers/table/utils.js +28 -27
  181. package/dist/api/controllers/user.js +10 -6
  182. package/dist/api/routes/query.js +1 -1
  183. package/dist/api/routes/table.js +7 -1
  184. package/dist/app.js +2 -11
  185. package/dist/automations/bullboard.js +37 -10
  186. package/dist/automations/triggers.js +7 -3
  187. package/dist/automations/utils.js +11 -2
  188. package/dist/constants/index.js +1 -0
  189. package/dist/definitions/datasource.js +1 -0
  190. package/dist/integrations/base/IntegrationBase.js +2 -0
  191. package/dist/integrations/base/sql.js +48 -8
  192. package/dist/integrations/base/sqlTable.js +1 -2
  193. package/dist/integrations/mysql.js +3 -1
  194. package/dist/integrations/postgres.js +2 -2
  195. package/dist/middleware/builder.js +4 -1
  196. package/dist/package.json +7 -6
  197. package/dist/{automations/thread.js → threads/automation.js} +23 -7
  198. package/dist/threads/index.js +58 -0
  199. package/dist/threads/query.js +61 -0
  200. package/dist/tsconfig.tsbuildinfo +1 -1
  201. package/dist/utilities/csvParser.js +46 -5
  202. package/dist/utilities/index.js +1 -0
  203. package/dist/utilities/queue/inMemoryQueue.js +8 -0
  204. package/dist/utilities/scriptRunner.js +4 -1
  205. package/package.json +8 -7
  206. package/scripts/likeCypress.ts +33 -0
  207. package/src/api/controllers/application.js +11 -1
  208. package/src/api/controllers/datasource.js +10 -2
  209. package/src/api/controllers/deploy/index.js +2 -0
  210. package/src/api/controllers/dev.js +4 -1
  211. package/src/api/controllers/query.js +26 -80
  212. package/src/api/controllers/row/ExternalRequest.ts +6 -2
  213. package/src/api/controllers/row/external.js +2 -0
  214. package/src/api/controllers/table/external.js +19 -0
  215. package/src/api/controllers/table/index.js +20 -2
  216. package/src/api/controllers/table/internal.js +14 -1
  217. package/src/api/controllers/table/utils.js +36 -32
  218. package/src/api/controllers/user.js +15 -10
  219. package/src/api/routes/query.js +1 -0
  220. package/src/api/routes/table.js +11 -0
  221. package/src/api/routes/tests/misc.spec.js +5 -1
  222. package/src/app.ts +2 -10
  223. package/src/automations/bullboard.js +28 -11
  224. package/src/automations/tests/automation.spec.js +3 -4
  225. package/src/automations/triggers.js +7 -3
  226. package/src/automations/utils.js +12 -2
  227. package/src/constants/index.js +1 -0
  228. package/src/definitions/datasource.ts +3 -2
  229. package/src/integrations/airtable.ts +2 -1
  230. package/src/integrations/arangodb.ts +2 -1
  231. package/src/integrations/base/IntegrationBase.ts +6 -0
  232. package/src/integrations/base/datasourcePlus.ts +2 -1
  233. package/src/integrations/base/sql.ts +51 -9
  234. package/src/integrations/base/sqlTable.ts +1 -4
  235. package/src/integrations/couchdb.ts +2 -1
  236. package/src/integrations/dynamodb.ts +2 -1
  237. package/src/integrations/elasticsearch.ts +2 -1
  238. package/src/integrations/mongodb.ts +2 -1
  239. package/src/integrations/mysql.ts +1 -1
  240. package/src/integrations/postgres.ts +5 -5
  241. package/src/integrations/rest.ts +2 -1
  242. package/src/integrations/s3.ts +2 -1
  243. package/src/middleware/builder.js +4 -1
  244. package/src/{automations/thread.js → threads/automation.js} +24 -7
  245. package/src/threads/index.js +60 -0
  246. package/src/threads/query.js +63 -0
  247. package/src/utilities/csvParser.js +48 -5
  248. package/src/utilities/index.js +1 -0
  249. package/src/utilities/queue/inMemoryQueue.js +7 -0
  250. package/src/utilities/scriptRunner.js +4 -1
  251. package/src/utilities/tests/__snapshots__/csvParser.spec.js.snap +0 -6
  252. package/src/utilities/tests/csvParser.spec.js +3 -0
  253. package/tsconfig.json +1 -1
  254. package/builder/assets/index.0e6a5c20.js +0 -201
  255. package/builder/assets/index.cf21e4d2.css +0 -29
  256. package/builder/assets/vendor.278a305c.js +0 -9
  257. package/builder/assets/vendor.d75d5eb7.css +0 -1
@@ -97,6 +97,7 @@ exports.syncUser = async function (ctx) {
97
97
  .map(([appId]) => appId)
98
98
  }
99
99
  for (let prodAppId of prodAppIds) {
100
+ const roleId = roles[prodAppId]
100
101
  const devAppId = getDevelopmentAppID(prodAppId)
101
102
  for (let appId of [prodAppId, devAppId]) {
102
103
  if (!(await doesDatabaseExist(appId))) {
@@ -115,17 +116,21 @@ exports.syncUser = async function (ctx) {
115
116
  tableId: InternalTables.USER_METADATA,
116
117
  }
117
118
  }
118
- let combined
119
- if (deleting) {
120
- combined = {
121
- ...metadata,
122
- status: UserStatus.INACTIVE,
123
- metadata: BUILTIN_ROLE_IDS.PUBLIC,
124
- }
125
- } else {
126
- combined = combineMetadataAndUser(user, metadata)
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)
127
133
  }
128
- await db.put(combined)
129
134
  }
130
135
  }
131
136
  ctx.body = {
@@ -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
@@ -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(),
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
+ }
@@ -69,6 +69,7 @@ exports.DataSourceOperation = {
69
69
  READ: "READ",
70
70
  UPDATE: "UPDATE",
71
71
  DELETE: "DELETE",
72
+ BULK_CREATE: "BULK_CREATE",
72
73
  CREATE_TABLE: "CREATE_TABLE",
73
74
  UPDATE_TABLE: "UPDATE_TABLE",
74
75
  DELETE_TABLE: "DELETE_TABLE",
@@ -1,10 +1,11 @@
1
- import { Table } from "./common"
1
+ import { Row, Table } from "./common"
2
2
 
3
3
  export enum Operation {
4
4
  CREATE = "CREATE",
5
5
  READ = "READ",
6
6
  UPDATE = "UPDATE",
7
7
  DELETE = "DELETE",
8
+ BULK_CREATE = "BULK_CREATE",
8
9
  CREATE_TABLE = "CREATE_TABLE",
9
10
  UPDATE_TABLE = "UPDATE_TABLE",
10
11
  DELETE_TABLE = "DELETE_TABLE",
@@ -144,7 +145,7 @@ export interface QueryJson {
144
145
  filters?: SearchFilters
145
146
  sort?: SortJson
146
147
  paginate?: PaginationJson
147
- body?: object
148
+ body?: Row | Row[]
148
149
  table?: Table
149
150
  meta?: {
150
151
  table?: Table
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module AirtableModule {
8
9
  const Airtable = require("airtable")
@@ -73,7 +74,7 @@ module AirtableModule {
73
74
  },
74
75
  }
75
76
 
76
- class AirtableIntegration {
77
+ class AirtableIntegration implements IntegrationBase {
77
78
  private config: AirtableConfig
78
79
  private client: any
79
80
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module ArangoModule {
8
9
  const { Database, aql } = require("arangojs")
@@ -55,7 +56,7 @@ module ArangoModule {
55
56
  },
56
57
  }
57
58
 
58
- class ArangoDBIntegration {
59
+ class ArangoDBIntegration implements IntegrationBase {
59
60
  private config: ArangodbConfig
60
61
  private client: any
61
62
 
@@ -0,0 +1,6 @@
1
+ export interface IntegrationBase {
2
+ create?(query: any): Promise<[any]>
3
+ read?(query: any): Promise<[any]>
4
+ update?(query: any): Promise<[any]>
5
+ delete?(query: any): Promise<[any]>
6
+ }
@@ -1,6 +1,7 @@
1
1
  import { Table } from "../../definitions/common"
2
+ import { IntegrationBase } from "./IntegrationBase"
2
3
 
3
- export interface DatasourcePlus {
4
+ export interface DatasourcePlus extends IntegrationBase {
4
5
  tables: Record<string, Table>
5
6
  schemaErrors: Record<string, string>
6
7
 
@@ -13,22 +13,50 @@ import SqlTableQueryBuilder from "./sqlTable"
13
13
  const BASE_LIMIT = 5000
14
14
 
15
15
  type KnexQuery = Knex.QueryBuilder | Knex
16
+ // these are invalid dates sent by the client, need to convert them to a real max date
17
+ const MIN_ISO_DATE = "0000-00-00T00:00:00.000Z"
18
+ const MAX_ISO_DATE = "9999-00-00T00:00:00.000Z"
19
+
20
+ function parse(input: any) {
21
+ if (Array.isArray(input)) {
22
+ return JSON.stringify(input)
23
+ }
24
+ if (typeof input !== "string") {
25
+ return input
26
+ }
27
+ if (input === MAX_ISO_DATE) {
28
+ return new Date(8640000000000000)
29
+ }
30
+ if (input === MIN_ISO_DATE) {
31
+ return new Date(-8640000000000000)
32
+ }
33
+ if (isIsoDateString(input)) {
34
+ return new Date(input)
35
+ }
36
+ return input
37
+ }
16
38
 
17
39
  function parseBody(body: any) {
18
40
  for (let [key, value] of Object.entries(body)) {
19
- if (Array.isArray(value)) {
20
- body[key] = JSON.stringify(value)
21
- }
22
- if (typeof value !== "string") {
23
- continue
24
- }
25
- if (isIsoDateString(value)) {
26
- body[key] = new Date(value)
27
- }
41
+ body[key] = parse(value)
28
42
  }
29
43
  return body
30
44
  }
31
45
 
46
+ function parseFilters(filters: SearchFilters): SearchFilters {
47
+ for (let [key, value] of Object.entries(filters)) {
48
+ let parsed
49
+ if (typeof value === "object") {
50
+ parsed = parseFilters(value)
51
+ } else {
52
+ parsed = parse(value)
53
+ }
54
+ // @ts-ignore
55
+ filters[key] = parsed
56
+ }
57
+ return filters
58
+ }
59
+
32
60
  class InternalBuilder {
33
61
  private readonly client: string
34
62
 
@@ -53,6 +81,7 @@ class InternalBuilder {
53
81
  if (!filters) {
54
82
  return query
55
83
  }
84
+ filters = parseFilters(filters)
56
85
  // if all or specified in filters, then everything is an or
57
86
  const allOr = filters.allOr
58
87
  if (filters.oneOf) {
@@ -179,6 +208,16 @@ class InternalBuilder {
179
208
  }
180
209
  }
181
210
 
211
+ bulkCreate(knex: Knex, json: QueryJson): KnexQuery {
212
+ const { endpoint, body } = json
213
+ let query: KnexQuery = knex(endpoint.entityId)
214
+ if (!Array.isArray(body)) {
215
+ return query
216
+ }
217
+ const parsedBody = body.map(row => parseBody(row))
218
+ return query.insert(parsedBody)
219
+ }
220
+
182
221
  read(knex: Knex, json: QueryJson, limit: number): KnexQuery {
183
222
  let { endpoint, resource, filters, sort, paginate, relationships } = json
184
223
  const tableName = endpoint.entityId
@@ -294,6 +333,9 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
294
333
  case Operation.DELETE:
295
334
  query = builder.delete(client, json, opts)
296
335
  break
336
+ case Operation.BULK_CREATE:
337
+ query = builder.bulkCreate(client, json)
338
+ break
297
339
  case Operation.CREATE_TABLE:
298
340
  case Operation.UPDATE_TABLE:
299
341
  case Operation.DELETE_TABLE:
@@ -29,10 +29,7 @@ function generateSchema(
29
29
  for (let [key, column] of Object.entries(table.schema)) {
30
30
  // skip things that are already correct
31
31
  const oldColumn = oldTable ? oldTable.schema[key] : null
32
- if (
33
- (oldColumn && oldColumn.type) ||
34
- (primaryKey === key && !isJunction)
35
- ) {
32
+ if ((oldColumn && oldColumn.type) || (primaryKey === key && !isJunction)) {
36
33
  continue
37
34
  }
38
35
  switch (column.type) {
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module CouchDBModule {
8
9
  const PouchDB = require("pouchdb")
@@ -50,7 +51,7 @@ module CouchDBModule {
50
51
  },
51
52
  }
52
53
 
53
- class CouchDBIntegration {
54
+ class CouchDBIntegration implements IntegrationBase {
54
55
  private config: CouchDBConfig
55
56
  private client: any
56
57
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module DynamoModule {
8
9
  const AWS = require("aws-sdk")
@@ -113,7 +114,7 @@ module DynamoModule {
113
114
  },
114
115
  }
115
116
 
116
- class DynamoDBIntegration {
117
+ class DynamoDBIntegration implements IntegrationBase {
117
118
  private config: DynamoDBConfig
118
119
  private client: any
119
120
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module ElasticsearchModule {
8
9
  const { Client } = require("@elastic/elasticsearch")
@@ -74,7 +75,7 @@ module ElasticsearchModule {
74
75
  },
75
76
  }
76
77
 
77
- class ElasticSearchIntegration {
78
+ class ElasticSearchIntegration implements IntegrationBase {
78
79
  private config: ElasticsearchConfig
79
80
  private client: any
80
81
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module MongoDBModule {
8
9
  const { MongoClient } = require("mongodb")
@@ -62,7 +63,7 @@ module MongoDBModule {
62
63
  },
63
64
  }
64
65
 
65
- class MongoIntegration {
66
+ class MongoIntegration implements IntegrationBase {
66
67
  private config: MongoDBConfig
67
68
  private client: any
68
69
 
@@ -184,7 +184,7 @@ module MySQLModule {
184
184
  return results.length ? results : [{ created: true }]
185
185
  }
186
186
 
187
- read(query: SqlQuery | string) {
187
+ async read(query: SqlQuery | string) {
188
188
  return internalQuery(this.client, getSqlQuery(query))
189
189
  }
190
190
 
@@ -130,7 +130,7 @@ module PostgresModule {
130
130
  public tables: Record<string, Table> = {}
131
131
  public schemaErrors: Record<string, string> = {}
132
132
 
133
- COLUMNS_SQL!: string
133
+ COLUMNS_SQL!: string
134
134
 
135
135
  PRIMARY_KEYS_SQL = `
136
136
  select tc.table_schema, tc.table_name, kc.column_name as primary_key
@@ -165,11 +165,11 @@ module PostgresModule {
165
165
 
166
166
  setSchema() {
167
167
  if (!this.config.schema) {
168
- this.config.schema = 'public'
168
+ this.config.schema = "public"
169
169
  }
170
- this.client.on('connect', (client: any) => {
171
- client.query(`SET search_path TO ${this.config.schema}`);
172
- });
170
+ this.client.on("connect", (client: any) => {
171
+ client.query(`SET search_path TO ${this.config.schema}`)
172
+ })
173
173
  this.COLUMNS_SQL = `select * from information_schema.columns where table_schema = '${this.config.schema}'`
174
174
  }
175
175
 
@@ -3,6 +3,7 @@ import {
3
3
  DatasourceFieldTypes,
4
4
  QueryTypes,
5
5
  } from "../definitions/datasource"
6
+ import { IntegrationBase } from "./base/IntegrationBase"
6
7
 
7
8
  module RestModule {
8
9
  const fetch = require("node-fetch")
@@ -131,7 +132,7 @@ module RestModule {
131
132
  },
132
133
  }
133
134
 
134
- class RestIntegration {
135
+ class RestIntegration implements IntegrationBase {
135
136
  private config: RestConfig
136
137
  private headers: {
137
138
  [key: string]: string
@@ -1,4 +1,5 @@
1
1
  import { Integration, QueryTypes } from "../definitions/datasource"
2
+ import { IntegrationBase } from "./base/IntegrationBase"
2
3
 
3
4
  module S3Module {
4
5
  const AWS = require("aws-sdk")
@@ -42,7 +43,7 @@ module S3Module {
42
43
  },
43
44
  }
44
45
 
45
- class S3Integration {
46
+ class S3Integration implements IntegrationBase {
46
47
  private readonly config: S3Config
47
48
  private client: any
48
49
  private connectionPromise: Promise<any>
@@ -8,6 +8,7 @@ const {
8
8
  const CouchDB = require("../db")
9
9
  const { DocumentTypes } = require("../db/utils")
10
10
  const { PermissionTypes } = require("@budibase/auth/permissions")
11
+ const { app: appCache } = require("@budibase/auth/cache")
11
12
 
12
13
  const DEBOUNCE_TIME_SEC = 30
13
14
 
@@ -50,7 +51,9 @@ async function updateAppUpdatedAt(ctx) {
50
51
  const db = new CouchDB(appId)
51
52
  const metadata = await db.get(DocumentTypes.APP_METADATA)
52
53
  metadata.updatedAt = new Date().toISOString()
53
- await db.put(metadata)
54
+ const response = await db.put(metadata)
55
+ metadata._rev = response.rev
56
+ await appCache.invalidateAppMetadata(appId, metadata)
54
57
  // set a new debounce record with a short TTL
55
58
  await setDebounce(appId, DEBOUNCE_TIME_SEC)
56
59
  }