@budibase/server 2.5.9 → 2.5.10-alpha.1

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 (198) hide show
  1. package/builder/assets/index.24635afb.js +1794 -0
  2. package/builder/assets/index.4eae16b2.css +6 -0
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/application.js +3 -4
  5. package/dist/api/controllers/automation.js +13 -7
  6. package/dist/api/controllers/datasource.js +1 -1
  7. package/dist/api/controllers/dev.js +1 -1
  8. package/dist/api/controllers/ops.js +40 -0
  9. package/dist/api/controllers/plugin/index.js +6 -37
  10. package/dist/api/controllers/query/index.js +2 -2
  11. package/dist/api/controllers/row/ExternalRequest.js +21 -14
  12. package/dist/api/controllers/row/internal.js +5 -2
  13. package/dist/api/controllers/row/utils.js +2 -2
  14. package/dist/api/controllers/table/index.js +2 -2
  15. package/dist/api/controllers/table/utils.js +9 -3
  16. package/dist/api/controllers/user.js +1 -83
  17. package/dist/api/controllers/view/exporters.js +3 -1
  18. package/dist/api/index.js +1 -2
  19. package/dist/api/routes/index.js +2 -2
  20. package/dist/api/routes/{cloud.js → ops.js} +19 -6
  21. package/dist/api/routes/user.js +0 -1
  22. package/dist/app.js +4 -13
  23. package/dist/automations/actions.js +32 -6
  24. package/dist/automations/index.js +3 -2
  25. package/dist/automations/steps/bash.js +6 -6
  26. package/dist/automations/steps/createRow.js +11 -11
  27. package/dist/automations/steps/delay.js +3 -3
  28. package/dist/automations/steps/deleteRow.js +8 -8
  29. package/dist/automations/steps/discord.js +8 -8
  30. package/dist/automations/steps/executeQuery.js +9 -9
  31. package/dist/automations/steps/executeScript.js +6 -6
  32. package/dist/automations/steps/filter.js +6 -6
  33. package/dist/automations/steps/integromat.js +10 -10
  34. package/dist/automations/steps/loop.js +9 -9
  35. package/dist/automations/steps/outgoingWebhook.js +10 -10
  36. package/dist/automations/steps/queryRows.js +14 -14
  37. package/dist/automations/steps/sendSmtpEmail.js +9 -9
  38. package/dist/automations/steps/serverLog.js +4 -4
  39. package/dist/automations/steps/slack.js +6 -6
  40. package/dist/automations/steps/updateRow.js +11 -11
  41. package/dist/automations/steps/zapier.js +9 -9
  42. package/dist/automations/triggerInfo/app.js +5 -5
  43. package/dist/automations/triggerInfo/cron.js +4 -4
  44. package/dist/automations/triggerInfo/rowDeleted.js +5 -5
  45. package/dist/automations/triggerInfo/rowSaved.js +7 -7
  46. package/dist/automations/triggerInfo/rowUpdated.js +7 -7
  47. package/dist/automations/triggerInfo/webhook.js +6 -6
  48. package/dist/db/utils.js +3 -2
  49. package/dist/environment.js +0 -1
  50. package/dist/events/docUpdates/index.js +17 -0
  51. package/dist/events/docUpdates/processors.js +18 -0
  52. package/dist/events/docUpdates/syncUsers.js +49 -0
  53. package/dist/events/index.js +3 -0
  54. package/dist/integrations/base/sqlTable.js +9 -2
  55. package/dist/integrations/index.js +3 -3
  56. package/dist/integrations/microsoftSqlServer.js +5 -2
  57. package/dist/integrations/mysql.js +5 -3
  58. package/dist/integrations/postgres.js +7 -5
  59. package/dist/integrations/redis.js +7 -0
  60. package/dist/integrations/rest.js +4 -0
  61. package/dist/migrations/functions/syncQuotas.js +2 -0
  62. package/dist/migrations/functions/usageQuotas/syncApps.js +1 -2
  63. package/dist/migrations/functions/usageQuotas/syncRows.js +1 -2
  64. package/dist/migrations/functions/usageQuotas/syncUsers.js +21 -0
  65. package/dist/sdk/app/applications/sync.js +117 -23
  66. package/dist/sdk/app/backups/exports.js +14 -38
  67. package/dist/sdk/index.js +2 -0
  68. package/dist/sdk/plugins/index.js +27 -0
  69. package/dist/sdk/plugins/plugins.js +53 -0
  70. package/dist/sdk/users/utils.js +21 -4
  71. package/dist/startup.js +31 -28
  72. package/dist/threads/automation.js +16 -5
  73. package/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/dist/utilities/csv.js +33 -0
  75. package/dist/utilities/fileSystem/plugin.js +33 -23
  76. package/dist/utilities/global.js +17 -12
  77. package/dist/utilities/rowProcessor/utils.js +4 -5
  78. package/dist/utilities/schema.js +5 -1
  79. package/dist/watch.js +2 -2
  80. package/dist/websockets/client.js +14 -0
  81. package/dist/websockets/grid.js +60 -0
  82. package/dist/websockets/index.js +17 -0
  83. package/dist/websockets/websocket.js +78 -0
  84. package/package.json +16 -16
  85. package/scripts/dev/manage.js +2 -0
  86. package/scripts/integrations/mssql/data/entrypoint.sh +1 -0
  87. package/scripts/integrations/mssql/data/setup.sql +17 -17
  88. package/scripts/integrations/mysql/init.sql +1 -1
  89. package/scripts/integrations/postgres/init.sql +1 -0
  90. package/src/api/controllers/application.ts +4 -4
  91. package/src/api/controllers/automation.ts +12 -6
  92. package/src/api/controllers/datasource.ts +15 -5
  93. package/src/api/controllers/dev.ts +2 -2
  94. package/src/api/controllers/ops.ts +32 -0
  95. package/src/api/controllers/plugin/index.ts +8 -45
  96. package/src/api/controllers/query/index.ts +2 -2
  97. package/src/api/controllers/row/ExternalRequest.ts +21 -12
  98. package/src/api/controllers/row/internal.ts +13 -11
  99. package/src/api/controllers/row/utils.ts +4 -4
  100. package/src/api/controllers/table/index.ts +2 -2
  101. package/src/api/controllers/table/utils.ts +10 -3
  102. package/src/api/controllers/user.ts +10 -96
  103. package/src/api/controllers/view/exporters.ts +3 -1
  104. package/src/api/index.ts +2 -4
  105. package/src/api/routes/index.ts +2 -2
  106. package/src/api/routes/ops.ts +30 -0
  107. package/src/api/routes/tests/automation.spec.js +7 -4
  108. package/src/api/routes/tests/user.spec.js +48 -37
  109. package/src/api/routes/user.ts +0 -5
  110. package/src/app.ts +4 -15
  111. package/src/automations/actions.ts +56 -24
  112. package/src/automations/index.ts +1 -1
  113. package/src/automations/steps/bash.ts +10 -7
  114. package/src/automations/steps/createRow.ts +15 -12
  115. package/src/automations/steps/delay.ts +6 -4
  116. package/src/automations/steps/deleteRow.ts +12 -9
  117. package/src/automations/steps/discord.ts +10 -8
  118. package/src/automations/steps/executeQuery.ts +13 -10
  119. package/src/automations/steps/executeScript.ts +10 -7
  120. package/src/automations/steps/filter.ts +8 -6
  121. package/src/automations/steps/integromat.ts +12 -10
  122. package/src/automations/steps/loop.ts +16 -10
  123. package/src/automations/steps/outgoingWebhook.ts +14 -11
  124. package/src/automations/steps/queryRows.ts +18 -15
  125. package/src/automations/steps/sendSmtpEmail.ts +11 -9
  126. package/src/automations/steps/serverLog.ts +6 -4
  127. package/src/automations/steps/slack.ts +8 -6
  128. package/src/automations/steps/updateRow.ts +15 -12
  129. package/src/automations/steps/zapier.ts +11 -9
  130. package/src/automations/tests/utilities/index.ts +2 -2
  131. package/src/automations/triggerInfo/app.ts +8 -5
  132. package/src/automations/triggerInfo/cron.ts +7 -4
  133. package/src/automations/triggerInfo/rowDeleted.ts +8 -5
  134. package/src/automations/triggerInfo/rowSaved.ts +10 -7
  135. package/src/automations/triggerInfo/rowUpdated.ts +10 -7
  136. package/src/automations/triggerInfo/webhook.ts +9 -6
  137. package/src/db/utils.ts +1 -0
  138. package/src/environment.ts +0 -1
  139. package/src/events/docUpdates/index.ts +1 -0
  140. package/src/events/docUpdates/processors.ts +14 -0
  141. package/src/events/docUpdates/syncUsers.ts +35 -0
  142. package/src/events/index.ts +1 -0
  143. package/src/integration-test/postgres.spec.ts +3 -1
  144. package/src/integrations/base/sqlTable.ts +9 -2
  145. package/src/integrations/index.ts +3 -3
  146. package/src/integrations/microsoftSqlServer.ts +5 -2
  147. package/src/integrations/mysql.ts +5 -3
  148. package/src/integrations/postgres.ts +7 -5
  149. package/src/integrations/redis.ts +8 -0
  150. package/src/integrations/rest.ts +3 -0
  151. package/src/migrations/functions/syncQuotas.ts +2 -0
  152. package/src/migrations/functions/usageQuotas/syncApps.ts +2 -3
  153. package/src/migrations/functions/usageQuotas/syncRows.ts +2 -3
  154. package/src/migrations/functions/usageQuotas/syncUsers.ts +9 -0
  155. package/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +2 -2
  156. package/src/migrations/functions/usageQuotas/tests/syncUsers.spec.ts +26 -0
  157. package/src/migrations/index.ts +1 -0
  158. package/src/sdk/app/applications/sync.ts +129 -22
  159. package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
  160. package/src/sdk/app/backups/exports.ts +17 -41
  161. package/src/sdk/index.ts +2 -0
  162. package/src/sdk/plugins/index.ts +5 -0
  163. package/src/sdk/plugins/plugins.ts +41 -0
  164. package/src/sdk/users/tests/utils.spec.ts +1 -32
  165. package/src/sdk/users/utils.ts +23 -5
  166. package/src/startup.ts +36 -34
  167. package/src/tests/jestEnv.ts +0 -1
  168. package/src/tests/jestSetup.ts +0 -1
  169. package/src/tests/utilities/TestConfiguration.ts +28 -0
  170. package/src/tests/utilities/structures.ts +25 -17
  171. package/src/threads/automation.ts +18 -6
  172. package/src/utilities/csv.ts +22 -0
  173. package/src/utilities/fileSystem/plugin.ts +13 -4
  174. package/src/utilities/global.ts +21 -16
  175. package/src/utilities/rowProcessor/utils.ts +9 -10
  176. package/src/utilities/schema.ts +8 -0
  177. package/src/utilities/tests/csv.spec.ts +33 -0
  178. package/src/watch.ts +2 -2
  179. package/src/websockets/client.ts +11 -0
  180. package/src/websockets/grid.ts +55 -0
  181. package/src/websockets/index.ts +14 -0
  182. package/src/websockets/websocket.ts +83 -0
  183. package/tsconfig.build.json +3 -5
  184. package/tsconfig.json +2 -1
  185. package/builder/assets/index.0b358332.js +0 -1817
  186. package/builder/assets/index.7f9a008b.css +0 -6
  187. package/dist/api/controllers/cloud.js +0 -130
  188. package/dist/elasticApm.js +0 -14
  189. package/dist/package.json +0 -180
  190. package/dist/websocket.js +0 -22
  191. package/scripts/likeCypress.ts +0 -35
  192. package/src/api/controllers/cloud.ts +0 -119
  193. package/src/api/routes/cloud.ts +0 -18
  194. package/src/api/routes/tests/cloud.spec.ts +0 -54
  195. package/src/elasticApm.ts +0 -10
  196. package/src/migrations/functions/tests/syncQuotas.spec.js +0 -26
  197. package/src/tests/logging.ts +0 -34
  198. package/src/websocket.ts +0 -26
@@ -1,98 +1,12 @@
1
1
  import { generateUserMetadataID, generateUserFlagID } from "../../db/utils"
2
2
  import { InternalTables } from "../../db/utils"
3
- import { getGlobalUsers, getRawGlobalUser } from "../../utilities/global"
3
+ import { getGlobalUsers } from "../../utilities/global"
4
4
  import { getFullUser } from "../../utilities/users"
5
- import {
6
- context,
7
- roles as rolesCore,
8
- db as dbCore,
9
- } from "@budibase/backend-core"
10
- import { BBContext, Ctx, SyncUserRequest, User } from "@budibase/types"
5
+ import { context } from "@budibase/backend-core"
6
+ import { UserCtx } from "@budibase/types"
11
7
  import sdk from "../../sdk"
12
8
 
13
- export async function syncUser(ctx: Ctx<SyncUserRequest>) {
14
- let deleting = false,
15
- user: User | any
16
- const userId = ctx.params.id
17
-
18
- const previousUser = ctx.request.body?.previousUser
19
-
20
- try {
21
- user = (await getRawGlobalUser(userId)) as User
22
- } catch (err: any) {
23
- if (err && err.status === 404) {
24
- user = {}
25
- deleting = true
26
- } else {
27
- throw err
28
- }
29
- }
30
-
31
- let previousApps = previousUser
32
- ? Object.keys(previousUser.roles).map(appId => appId)
33
- : []
34
-
35
- const roles = deleting ? {} : user.roles
36
- // remove props which aren't useful to metadata
37
- delete user.password
38
- delete user.forceResetPassword
39
- delete user.roles
40
- // run through all production appIDs in the users roles
41
- let prodAppIds
42
- // if they are a builder then get all production app IDs
43
- if ((user.builder && user.builder.global) || deleting) {
44
- prodAppIds = await dbCore.getProdAppIDs()
45
- } else {
46
- prodAppIds = Object.entries(roles)
47
- .filter(entry => entry[1] !== rolesCore.BUILTIN_ROLE_IDS.PUBLIC)
48
- .map(([appId]) => appId)
49
- }
50
- for (let prodAppId of new Set([...prodAppIds, ...previousApps])) {
51
- const roleId = roles[prodAppId]
52
- const deleteFromApp = !roleId
53
- const devAppId = dbCore.getDevelopmentAppID(prodAppId)
54
- for (let appId of [prodAppId, devAppId]) {
55
- if (!(await dbCore.dbExists(appId))) {
56
- continue
57
- }
58
- await context.doInAppContext(appId, async () => {
59
- const db = context.getAppDB()
60
- const metadataId = generateUserMetadataID(userId)
61
- let metadata
62
- try {
63
- metadata = await db.get(metadataId)
64
- } catch (err) {
65
- if (deleteFromApp) {
66
- return
67
- }
68
- metadata = {
69
- tableId: InternalTables.USER_METADATA,
70
- }
71
- }
72
-
73
- if (deleteFromApp) {
74
- await db.remove(metadata)
75
- return
76
- }
77
-
78
- // assign the roleId for the metadata doc
79
- if (roleId) {
80
- metadata.roleId = roleId
81
- }
82
- let combined = sdk.users.combineMetadataAndUser(user, metadata)
83
- // if its null then there was no updates required
84
- if (combined) {
85
- await db.put(combined)
86
- }
87
- })
88
- }
89
- }
90
- ctx.body = {
91
- message: "User synced.",
92
- }
93
- }
94
-
95
- export async function fetchMetadata(ctx: BBContext) {
9
+ export async function fetchMetadata(ctx: UserCtx) {
96
10
  const global = await getGlobalUsers()
97
11
  const metadata = await sdk.users.rawUserMetadata()
98
12
  const users = []
@@ -111,7 +25,7 @@ export async function fetchMetadata(ctx: BBContext) {
111
25
  ctx.body = users
112
26
  }
113
27
 
114
- export async function updateSelfMetadata(ctx: BBContext) {
28
+ export async function updateSelfMetadata(ctx: UserCtx) {
115
29
  // overwrite the ID with current users
116
30
  ctx.request.body._id = ctx.user?._id
117
31
  // make sure no stale rev
@@ -121,7 +35,7 @@ export async function updateSelfMetadata(ctx: BBContext) {
121
35
  await updateMetadata(ctx)
122
36
  }
123
37
 
124
- export async function updateMetadata(ctx: BBContext) {
38
+ export async function updateMetadata(ctx: UserCtx) {
125
39
  const db = context.getAppDB()
126
40
  const user = ctx.request.body
127
41
  // this isn't applicable to the user
@@ -133,7 +47,7 @@ export async function updateMetadata(ctx: BBContext) {
133
47
  ctx.body = await db.put(metadata)
134
48
  }
135
49
 
136
- export async function destroyMetadata(ctx: BBContext) {
50
+ export async function destroyMetadata(ctx: UserCtx) {
137
51
  const db = context.getAppDB()
138
52
  try {
139
53
  const dbUser = await db.get(ctx.params.id)
@@ -146,11 +60,11 @@ export async function destroyMetadata(ctx: BBContext) {
146
60
  }
147
61
  }
148
62
 
149
- export async function findMetadata(ctx: BBContext) {
63
+ export async function findMetadata(ctx: UserCtx) {
150
64
  ctx.body = await getFullUser(ctx, ctx.params.id)
151
65
  }
152
66
 
153
- export async function setFlag(ctx: BBContext) {
67
+ export async function setFlag(ctx: UserCtx) {
154
68
  const userId = ctx.user?._id
155
69
  const { flag, value } = ctx.request.body
156
70
  if (!flag) {
@@ -169,7 +83,7 @@ export async function setFlag(ctx: BBContext) {
169
83
  ctx.body = { message: "Flag set successfully" }
170
84
  }
171
85
 
172
- export async function getFlags(ctx: BBContext) {
86
+ export async function getFlags(ctx: UserCtx) {
173
87
  const userId = ctx.user?._id
174
88
  const docId = generateUserFlagID(userId!)
175
89
  const db = context.getAppDB()
@@ -10,7 +10,9 @@ export function csv(headers: string[], rows: Row[]) {
10
10
  val =
11
11
  typeof val === "object" && !(val instanceof Date)
12
12
  ? `"${JSON.stringify(val).replace(/"/g, "'")}"`
13
- : `"${val}"`
13
+ : val !== undefined
14
+ ? `"${val}"`
15
+ : ""
14
16
  return val.trim()
15
17
  })
16
18
  .join(",")}`
package/src/api/index.ts CHANGED
@@ -1,10 +1,8 @@
1
1
  import Router from "@koa/router"
2
- import { auth, middleware } from "@budibase/backend-core"
2
+ import { auth, middleware, env as envCore } from "@budibase/backend-core"
3
3
  import currentApp from "../middleware/currentapp"
4
4
  import zlib from "zlib"
5
5
  import { mainRoutes, staticRoutes, publicRoutes } from "./routes"
6
- import pkg from "../../package.json"
7
- import env from "../environment"
8
6
  import { middleware as pro } from "@budibase/pro"
9
7
  export { shutdown } from "./routes/public"
10
8
  const compress = require("koa-compress")
@@ -12,7 +10,7 @@ const compress = require("koa-compress")
12
10
  export const router: Router = new Router()
13
11
 
14
12
  router.get("/health", ctx => (ctx.status = 200))
15
- router.get("/version", ctx => (ctx.body = pkg.version))
13
+ router.get("/version", ctx => (ctx.body = envCore.VERSION))
16
14
 
17
15
  router.use(middleware.errorHandling)
18
16
 
@@ -22,9 +22,9 @@ import queryRoutes from "./query"
22
22
  import backupRoutes from "./backup"
23
23
  import metadataRoutes from "./metadata"
24
24
  import devRoutes from "./dev"
25
- import cloudRoutes from "./cloud"
26
25
  import migrationRoutes from "./migrations"
27
26
  import pluginRoutes from "./plugin"
27
+ import opsRoutes from "./ops"
28
28
  import Router from "@koa/router"
29
29
  import { api as pro } from "@budibase/pro"
30
30
 
@@ -59,10 +59,10 @@ export const mainRoutes: Router[] = [
59
59
  queryRoutes,
60
60
  metadataRoutes,
61
61
  devRoutes,
62
- cloudRoutes,
63
62
  rowRoutes,
64
63
  migrationRoutes,
65
64
  pluginRoutes,
65
+ opsRoutes,
66
66
  scheduleRoutes,
67
67
  environmentVariableRoutes,
68
68
  // these need to be handled last as they still use /api/:tableId
@@ -0,0 +1,30 @@
1
+ import Router from "@koa/router"
2
+ import * as controller from "../controllers/ops"
3
+ import { middleware } from "@budibase/backend-core"
4
+ import Joi from "joi"
5
+
6
+ export function logsValidator() {
7
+ return middleware.joiValidator.body(
8
+ Joi.object({
9
+ message: Joi.string().required(),
10
+ data: Joi.object(),
11
+ })
12
+ )
13
+ }
14
+
15
+ export function errorValidator() {
16
+ return middleware.joiValidator.body(
17
+ Joi.object({
18
+ message: Joi.string().required(),
19
+ })
20
+ )
21
+ }
22
+
23
+ const router: Router = new Router()
24
+
25
+ router
26
+ .post("/api/ops/log", logsValidator(), controller.log)
27
+ .post("/api/ops/error", errorValidator(), controller.error)
28
+ .post("/api/ops/alert", errorValidator(), controller.alert)
29
+
30
+ export default router
@@ -7,7 +7,7 @@ const {
7
7
  const setup = require("./utilities")
8
8
  const { basicAutomation, newAutomation, automationTrigger, automationStep } = setup.structures
9
9
  const MAX_RETRIES = 4
10
- const { TRIGGER_DEFINITIONS, ACTION_DEFINITIONS } = require("../../../automations")
10
+ const { TRIGGER_DEFINITIONS, BUILTIN_ACTION_DEFINITIONS } = require("../../../automations")
11
11
  const { events } = require("@budibase/backend-core")
12
12
 
13
13
 
@@ -19,11 +19,14 @@ describe("/automations", () => {
19
19
 
20
20
  afterAll(setup.afterAll)
21
21
 
22
- // For some reason this cannot be a beforeAll or the test "tests the automation successfully" fail
23
- beforeEach(async () => {
22
+ beforeAll(async () => {
24
23
  await config.init()
25
24
  })
26
25
 
26
+ beforeEach(() => {
27
+ events.automation.deleted.mockClear()
28
+ })
29
+
27
30
  describe("get definitions", () => {
28
31
  it("returns a list of definitions for actions", async () => {
29
32
  const res = await request
@@ -52,7 +55,7 @@ describe("/automations", () => {
52
55
  .expect('Content-Type', /json/)
53
56
  .expect(200)
54
57
 
55
- let definitionsLength = Object.keys(ACTION_DEFINITIONS).length
58
+ let definitionsLength = Object.keys(BUILTIN_ACTION_DEFINITIONS).length
56
59
  definitionsLength-- // OUTGOING_WEBHOOK is deprecated
57
60
 
58
61
  expect(Object.keys(res.body.action).length).toBeGreaterThanOrEqual(definitionsLength)
@@ -57,6 +57,7 @@ describe("/users", () => {
57
57
  it("should be able to update the user", async () => {
58
58
  const user = await config.createUser({ id: `us_update${utils.newid()}` })
59
59
  user.roleId = BUILTIN_ROLE_IDS.BASIC
60
+ delete user._rev
60
61
  const res = await request
61
62
  .put(`/api/users/metadata`)
62
63
  .set(config.defaultHeaders())
@@ -65,6 +66,46 @@ describe("/users", () => {
65
66
  .expect("Content-Type", /json/)
66
67
  expect(res.body.ok).toEqual(true)
67
68
  })
69
+
70
+ it("should be able to update the user multiple times", async () => {
71
+ const user = await config.createUser()
72
+ delete user._rev
73
+
74
+ const res1 = await request
75
+ .put(`/api/users/metadata`)
76
+ .set(config.defaultHeaders())
77
+ .send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC })
78
+ .expect(200)
79
+ .expect("Content-Type", /json/)
80
+
81
+ const res = await request
82
+ .put(`/api/users/metadata`)
83
+ .set(config.defaultHeaders())
84
+ .send({ ...user, _rev: res1.body.rev, roleId: BUILTIN_ROLE_IDS.POWER })
85
+ .expect(200)
86
+ .expect("Content-Type", /json/)
87
+
88
+ expect(res.body.ok).toEqual(true)
89
+ })
90
+
91
+ it("should require the _rev field for multiple updates", async () => {
92
+ const user = await config.createUser()
93
+ delete user._rev
94
+
95
+ await request
96
+ .put(`/api/users/metadata`)
97
+ .set(config.defaultHeaders())
98
+ .send({ ...user, roleId: BUILTIN_ROLE_IDS.BASIC })
99
+ .expect(200)
100
+ .expect("Content-Type", /json/)
101
+
102
+ await request
103
+ .put(`/api/users/metadata`)
104
+ .set(config.defaultHeaders())
105
+ .send({ ...user, roleId: BUILTIN_ROLE_IDS.POWER })
106
+ .expect(409)
107
+ .expect("Content-Type", /json/)
108
+ })
68
109
  })
69
110
 
70
111
  describe("destroy", () => {
@@ -92,6 +133,7 @@ describe("/users", () => {
92
133
  expect(res.body.tableId).toBeDefined()
93
134
  })
94
135
  })
136
+
95
137
  describe("setFlag", () => {
96
138
  it("should throw an error if a flag is not provided", async () => {
97
139
  await config.createUser()
@@ -101,8 +143,9 @@ describe("/users", () => {
101
143
  .send({ value: "test" })
102
144
  .expect(400)
103
145
  .expect("Content-Type", /json/)
104
- expect(res.body.message).toEqual("Must supply a 'flag' field in request body.")
105
-
146
+ expect(res.body.message).toEqual(
147
+ "Must supply a 'flag' field in request body."
148
+ )
106
149
  })
107
150
 
108
151
  it("should be able to set a flag on the user", async () => {
@@ -146,8 +189,9 @@ describe("/users", () => {
146
189
  .send({ value: "test" })
147
190
  .expect(400)
148
191
  .expect("Content-Type", /json/)
149
- expect(res.body.message).toEqual("Must supply a 'flag' field in request body.")
150
-
192
+ expect(res.body.message).toEqual(
193
+ "Must supply a 'flag' field in request body."
194
+ )
151
195
  })
152
196
 
153
197
  it("should be able to set a flag on the user", async () => {
@@ -161,37 +205,4 @@ describe("/users", () => {
161
205
  expect(res.body.message).toEqual("Flag set successfully")
162
206
  })
163
207
  })
164
-
165
- describe("syncUser", () => {
166
- it("should sync the user", async () => {
167
- let user = await config.createUser()
168
- await config.createApp('New App')
169
- let res = await request
170
- .post(`/api/users/metadata/sync/${user._id}`)
171
- .set(config.defaultHeaders())
172
- .expect(200)
173
- .expect("Content-Type", /json/)
174
- expect(res.body.message).toEqual('User synced.')
175
- })
176
-
177
-
178
- it("should sync the user when a previous user is specified", async () => {
179
- const app1 = await config.createApp('App 1')
180
- const app2 = await config.createApp('App 2')
181
-
182
- let user = await config.createUser({
183
- builder: false,
184
- admin: true,
185
- roles: { [app1.appId]: 'ADMIN' }
186
- })
187
- let res = await request
188
- .post(`/api/users/metadata/sync/${user._id}`)
189
- .set(config.defaultHeaders())
190
- .send({ previousUser: { ...user, roles: { ...user.roles, [app2.appId]: 'BASIC' } } })
191
- .expect(200)
192
- .expect("Content-Type", /json/)
193
-
194
- expect(res.body.message).toEqual('User synced.')
195
- })
196
- })
197
208
  })
@@ -32,11 +32,6 @@ router
32
32
  authorized(PermissionType.USER, PermissionLevel.WRITE),
33
33
  controller.destroyMetadata
34
34
  )
35
- .post(
36
- "/api/users/metadata/sync/:id",
37
- authorized(PermissionType.USER, PermissionLevel.WRITE),
38
- controller.syncUser
39
- )
40
35
  .post(
41
36
  "/api/users/flags",
42
37
  authorized(PermissionType.USER, PermissionLevel.WRITE),
package/src/app.ts CHANGED
@@ -2,21 +2,9 @@ if (process.env.DD_APM_ENABLED) {
2
2
  require("./ddApm")
3
3
  }
4
4
 
5
- if (process.env.ELASTIC_APM_ENABLED) {
6
- require("./elasticApm")
7
- }
8
-
9
5
  // need to load environment first
10
6
  import env from "./environment"
11
7
 
12
- // enable APM if configured
13
- if (process.env.ELASTIC_APM_ENABLED) {
14
- const apm = require("elastic-apm-node").start({
15
- serviceName: process.env.SERVICE,
16
- environment: process.env.BUDIBASE_ENVIRONMENT,
17
- })
18
- }
19
-
20
8
  import { ExtendableContext } from "koa"
21
9
  import * as db from "./db"
22
10
  db.init()
@@ -27,8 +15,8 @@ import * as api from "./api"
27
15
  import * as automations from "./automations"
28
16
  import { Thread } from "./threads"
29
17
  import * as redis from "./utilities/redis"
18
+ import { initialise as initialiseWebsockets } from "./websockets"
30
19
  import { events, logging, middleware, timers } from "@budibase/backend-core"
31
- import { initialise as initialiseWebsockets } from "./websocket"
32
20
  import { startup } from "./startup"
33
21
  const Sentry = require("@sentry/node")
34
22
  const destroyable = require("server-destroy")
@@ -53,7 +41,8 @@ app.use(
53
41
  })
54
42
  )
55
43
 
56
- app.use(middleware.logging)
44
+ app.use(middleware.correlation)
45
+ app.use(middleware.pino)
57
46
  app.use(userAgent)
58
47
 
59
48
  if (env.isProd()) {
@@ -72,7 +61,7 @@ if (env.isProd()) {
72
61
 
73
62
  const server = http.createServer(app.callback())
74
63
  destroyable(server)
75
- initialiseWebsockets(server)
64
+ initialiseWebsockets(app, server)
76
65
 
77
66
  let shuttingDown = false,
78
67
  errCode = 0
@@ -15,7 +15,14 @@ import * as delay from "./steps/delay"
15
15
  import * as queryRow from "./steps/queryRows"
16
16
  import * as loop from "./steps/loop"
17
17
  import env from "../environment"
18
- import { AutomationStepSchema, AutomationStepInput } from "@budibase/types"
18
+ import {
19
+ AutomationStepSchema,
20
+ AutomationStepInput,
21
+ PluginType,
22
+ AutomationStep,
23
+ } from "@budibase/types"
24
+ import sdk from "../sdk"
25
+ import { getAutomationPlugin } from "../utilities/fileSystem"
19
26
 
20
27
  const ACTION_IMPLS: Record<
21
28
  string,
@@ -38,25 +45,26 @@ const ACTION_IMPLS: Record<
38
45
  zapier: zapier.run,
39
46
  integromat: integromat.run,
40
47
  }
41
- export const ACTION_DEFINITIONS: Record<string, AutomationStepSchema> = {
42
- SEND_EMAIL_SMTP: sendSmtpEmail.definition,
43
- CREATE_ROW: createRow.definition,
44
- UPDATE_ROW: updateRow.definition,
45
- DELETE_ROW: deleteRow.definition,
46
- OUTGOING_WEBHOOK: outgoingWebhook.definition,
47
- EXECUTE_SCRIPT: executeScript.definition,
48
- EXECUTE_QUERY: executeQuery.definition,
49
- SERVER_LOG: serverLog.definition,
50
- DELAY: delay.definition,
51
- FILTER: filter.definition,
52
- QUERY_ROWS: queryRow.definition,
53
- LOOP: loop.definition,
54
- // these used to be lowercase step IDs, maintain for backwards compat
55
- discord: discord.definition,
56
- slack: slack.definition,
57
- zapier: zapier.definition,
58
- integromat: integromat.definition,
59
- }
48
+ export const BUILTIN_ACTION_DEFINITIONS: Record<string, AutomationStepSchema> =
49
+ {
50
+ SEND_EMAIL_SMTP: sendSmtpEmail.definition,
51
+ CREATE_ROW: createRow.definition,
52
+ UPDATE_ROW: updateRow.definition,
53
+ DELETE_ROW: deleteRow.definition,
54
+ OUTGOING_WEBHOOK: outgoingWebhook.definition,
55
+ EXECUTE_SCRIPT: executeScript.definition,
56
+ EXECUTE_QUERY: executeQuery.definition,
57
+ SERVER_LOG: serverLog.definition,
58
+ DELAY: delay.definition,
59
+ FILTER: filter.definition,
60
+ QUERY_ROWS: queryRow.definition,
61
+ LOOP: loop.definition,
62
+ // these used to be lowercase step IDs, maintain for backwards compat
63
+ discord: discord.definition,
64
+ slack: slack.definition,
65
+ zapier: zapier.definition,
66
+ integromat: integromat.definition,
67
+ }
60
68
 
61
69
  // don't add the bash script/definitions unless in self host
62
70
  // the fact this isn't included in any definitions means it cannot be
@@ -66,12 +74,36 @@ if (env.SELF_HOSTED) {
66
74
  // @ts-ignore
67
75
  ACTION_IMPLS["EXECUTE_BASH"] = bash.run
68
76
  // @ts-ignore
69
- ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition
77
+ BUILTIN_ACTION_DEFINITIONS["EXECUTE_BASH"] = bash.definition
78
+ }
79
+
80
+ export async function getActionDefinitions() {
81
+ const actionDefinitions = BUILTIN_ACTION_DEFINITIONS
82
+ if (env.SELF_HOSTED) {
83
+ const plugins = await sdk.plugins.fetch(PluginType.AUTOMATION)
84
+ for (let plugin of plugins) {
85
+ const schema = plugin.schema.schema as AutomationStep
86
+ actionDefinitions[schema.stepId] = {
87
+ ...schema,
88
+ custom: true,
89
+ }
90
+ }
91
+ }
92
+ return actionDefinitions
70
93
  }
71
94
 
72
95
  /* istanbul ignore next */
73
- export async function getAction(actionName: string) {
74
- if (ACTION_IMPLS[actionName] != null) {
75
- return ACTION_IMPLS[actionName]
96
+ export async function getAction(stepId: string) {
97
+ if (ACTION_IMPLS[stepId] != null) {
98
+ return ACTION_IMPLS[stepId]
99
+ }
100
+ // must be a plugin
101
+ if (env.SELF_HOSTED) {
102
+ const plugins = await sdk.plugins.fetch(PluginType.AUTOMATION)
103
+ const found = plugins.find(plugin => plugin.schema.schema.stepId === stepId)
104
+ if (!found) {
105
+ throw new Error(`Unable to find action implementation for "${stepId}"`)
106
+ }
107
+ return (await getAutomationPlugin(found)).action
76
108
  }
77
109
  }
@@ -6,7 +6,7 @@ import BullQueue from "bull"
6
6
  export { automationQueue } from "./bullboard"
7
7
  export { shutdown } from "./bullboard"
8
8
  export { TRIGGER_DEFINITIONS } from "./triggers"
9
- export { ACTION_DEFINITIONS } from "./actions"
9
+ export { BUILTIN_ACTION_DEFINITIONS, getActionDefinitions } from "./actions"
10
10
 
11
11
  /**
12
12
  * This module is built purely to kick off the worker farm and manage the inputs/outputs
@@ -4,8 +4,11 @@ import * as automationUtils from "../automationUtils"
4
4
  import environment from "../../environment"
5
5
  import {
6
6
  AutomationActionStepId,
7
- AutomationStepSchema,
7
+ AutomationCustomIOType,
8
+ AutomationIOType,
8
9
  AutomationStepInput,
10
+ AutomationStepSchema,
11
+ AutomationStepType,
9
12
  } from "@budibase/types"
10
13
 
11
14
  export const definition: AutomationStepSchema = {
@@ -13,7 +16,7 @@ export const definition: AutomationStepSchema = {
13
16
  tagline: "Execute a bash command",
14
17
  icon: "JourneyEvent",
15
18
  description: "Run a bash script",
16
- type: "ACTION",
19
+ type: AutomationStepType.ACTION,
17
20
  internal: true,
18
21
  stepId: AutomationActionStepId.EXECUTE_BASH,
19
22
  inputs: {},
@@ -21,8 +24,8 @@ export const definition: AutomationStepSchema = {
21
24
  inputs: {
22
25
  properties: {
23
26
  code: {
24
- type: "string",
25
- customType: "code",
27
+ type: AutomationIOType.STRING,
28
+ customType: AutomationCustomIOType.CODE,
26
29
  title: "Code",
27
30
  },
28
31
  },
@@ -31,16 +34,16 @@ export const definition: AutomationStepSchema = {
31
34
  outputs: {
32
35
  properties: {
33
36
  stdout: {
34
- type: "string",
37
+ type: AutomationIOType.STRING,
35
38
  description: "Standard output of your bash command or script",
36
39
  },
37
40
  success: {
38
- type: "boolean",
41
+ type: AutomationIOType.BOOLEAN,
39
42
  description: "Whether the command was successful",
40
43
  },
41
44
  },
45
+ required: ["stdout"],
42
46
  },
43
- required: ["stdout"],
44
47
  },
45
48
  }
46
49