@budibase/server 2.5.6-alpha.1 → 2.5.6-alpha.10

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 (121) hide show
  1. package/builder/assets/{index.1fe52b59.js → index.5c1a6913.js} +361 -361
  2. package/builder/assets/index.c0265b74.css +6 -0
  3. package/builder/index.html +2 -2
  4. package/dist/api/controllers/automation.js +13 -7
  5. package/dist/api/controllers/plugin/index.js +6 -37
  6. package/dist/api/controllers/table/utils.js +2 -1
  7. package/dist/api/controllers/user.js +1 -83
  8. package/dist/api/routes/user.js +0 -1
  9. package/dist/app.js +2 -2
  10. package/dist/automations/actions.js +32 -6
  11. package/dist/automations/index.js +3 -2
  12. package/dist/automations/steps/bash.js +6 -6
  13. package/dist/automations/steps/createRow.js +11 -11
  14. package/dist/automations/steps/delay.js +3 -3
  15. package/dist/automations/steps/deleteRow.js +8 -8
  16. package/dist/automations/steps/discord.js +8 -8
  17. package/dist/automations/steps/executeQuery.js +9 -9
  18. package/dist/automations/steps/executeScript.js +6 -6
  19. package/dist/automations/steps/filter.js +6 -6
  20. package/dist/automations/steps/integromat.js +10 -10
  21. package/dist/automations/steps/loop.js +9 -9
  22. package/dist/automations/steps/outgoingWebhook.js +10 -10
  23. package/dist/automations/steps/queryRows.js +14 -14
  24. package/dist/automations/steps/sendSmtpEmail.js +9 -9
  25. package/dist/automations/steps/serverLog.js +4 -4
  26. package/dist/automations/steps/slack.js +6 -6
  27. package/dist/automations/steps/updateRow.js +11 -11
  28. package/dist/automations/steps/zapier.js +9 -9
  29. package/dist/automations/triggerInfo/app.js +5 -5
  30. package/dist/automations/triggerInfo/cron.js +4 -4
  31. package/dist/automations/triggerInfo/rowDeleted.js +5 -5
  32. package/dist/automations/triggerInfo/rowSaved.js +7 -7
  33. package/dist/automations/triggerInfo/rowUpdated.js +7 -7
  34. package/dist/automations/triggerInfo/webhook.js +6 -6
  35. package/dist/events/docUpdates/index.js +17 -0
  36. package/dist/events/docUpdates/processors.js +18 -0
  37. package/dist/events/docUpdates/syncUsers.js +49 -0
  38. package/dist/events/index.js +3 -0
  39. package/dist/integrations/index.js +3 -3
  40. package/dist/package.json +9 -8
  41. package/dist/sdk/app/applications/sync.js +117 -23
  42. package/dist/sdk/index.js +2 -0
  43. package/dist/sdk/plugins/index.js +27 -0
  44. package/dist/sdk/plugins/plugins.js +53 -0
  45. package/dist/sdk/users/utils.js +21 -4
  46. package/dist/startup.js +2 -1
  47. package/dist/threads/automation.js +2 -2
  48. package/dist/tsconfig.build.tsbuildinfo +1 -1
  49. package/dist/utilities/fileSystem/plugin.js +33 -23
  50. package/dist/utilities/global.js +17 -12
  51. package/dist/watch.js +2 -2
  52. package/dist/websockets/client.js +14 -0
  53. package/dist/websockets/grid.js +60 -0
  54. package/dist/websockets/index.js +17 -0
  55. package/dist/websockets/websocket.js +78 -0
  56. package/jest.config.ts +3 -3
  57. package/nodemon.json +7 -3
  58. package/package.json +10 -9
  59. package/src/api/controllers/automation.ts +12 -6
  60. package/src/api/controllers/plugin/index.ts +8 -45
  61. package/src/api/controllers/row/internal.ts +9 -10
  62. package/src/api/controllers/row/utils.ts +2 -2
  63. package/src/api/controllers/table/utils.ts +2 -1
  64. package/src/api/controllers/user.ts +10 -96
  65. package/src/api/routes/tests/automation.spec.js +2 -2
  66. package/src/api/routes/tests/user.spec.js +0 -37
  67. package/src/api/routes/user.ts +0 -5
  68. package/src/app.ts +2 -2
  69. package/src/automations/actions.ts +56 -24
  70. package/src/automations/index.ts +1 -1
  71. package/src/automations/steps/bash.ts +10 -7
  72. package/src/automations/steps/createRow.ts +15 -12
  73. package/src/automations/steps/delay.ts +6 -4
  74. package/src/automations/steps/deleteRow.ts +12 -9
  75. package/src/automations/steps/discord.ts +10 -8
  76. package/src/automations/steps/executeQuery.ts +13 -10
  77. package/src/automations/steps/executeScript.ts +10 -7
  78. package/src/automations/steps/filter.ts +8 -6
  79. package/src/automations/steps/integromat.ts +12 -10
  80. package/src/automations/steps/loop.ts +16 -10
  81. package/src/automations/steps/outgoingWebhook.ts +14 -11
  82. package/src/automations/steps/queryRows.ts +18 -15
  83. package/src/automations/steps/sendSmtpEmail.ts +11 -9
  84. package/src/automations/steps/serverLog.ts +6 -4
  85. package/src/automations/steps/slack.ts +8 -6
  86. package/src/automations/steps/updateRow.ts +15 -12
  87. package/src/automations/steps/zapier.ts +11 -9
  88. package/src/automations/tests/utilities/index.ts +2 -2
  89. package/src/automations/triggerInfo/app.ts +8 -5
  90. package/src/automations/triggerInfo/cron.ts +7 -4
  91. package/src/automations/triggerInfo/rowDeleted.ts +8 -5
  92. package/src/automations/triggerInfo/rowSaved.ts +10 -7
  93. package/src/automations/triggerInfo/rowUpdated.ts +10 -7
  94. package/src/automations/triggerInfo/webhook.ts +9 -6
  95. package/src/events/docUpdates/index.ts +1 -0
  96. package/src/events/docUpdates/processors.ts +14 -0
  97. package/src/events/docUpdates/syncUsers.ts +35 -0
  98. package/src/events/index.ts +1 -0
  99. package/src/integrations/index.ts +3 -3
  100. package/src/sdk/app/applications/sync.ts +129 -22
  101. package/src/sdk/app/applications/tests/sync.spec.ts +137 -0
  102. package/src/sdk/index.ts +2 -0
  103. package/src/sdk/plugins/index.ts +5 -0
  104. package/src/sdk/plugins/plugins.ts +41 -0
  105. package/src/sdk/users/tests/utils.spec.ts +1 -32
  106. package/src/sdk/users/utils.ts +23 -5
  107. package/src/startup.ts +2 -1
  108. package/src/tests/utilities/TestConfiguration.ts +28 -0
  109. package/src/tests/utilities/structures.ts +25 -17
  110. package/src/threads/automation.ts +2 -2
  111. package/src/utilities/fileSystem/plugin.ts +13 -4
  112. package/src/utilities/global.ts +21 -16
  113. package/src/watch.ts +2 -2
  114. package/src/websockets/client.ts +11 -0
  115. package/src/websockets/grid.ts +55 -0
  116. package/src/websockets/index.ts +14 -0
  117. package/src/websockets/websocket.ts +83 -0
  118. package/tsconfig.json +1 -7
  119. package/builder/assets/index.841e62d8.css +0 -6
  120. package/dist/websocket.js +0 -22
  121. package/src/websocket.ts +0 -26
@@ -4,12 +4,14 @@ import {
4
4
  AutomationActionStepId,
5
5
  AutomationStepSchema,
6
6
  AutomationStepInput,
7
+ AutomationStepType,
8
+ AutomationIOType,
7
9
  } from "@budibase/types"
8
10
 
9
11
  export const definition: AutomationStepSchema = {
10
12
  name: "Zapier Webhook",
11
13
  stepId: AutomationActionStepId.zapier,
12
- type: "ACTION",
14
+ type: AutomationStepType.ACTION,
13
15
  internal: false,
14
16
  description: "Trigger a Zapier Zap via webhooks",
15
17
  tagline: "Trigger a Zapier Zap",
@@ -19,27 +21,27 @@ export const definition: AutomationStepSchema = {
19
21
  inputs: {
20
22
  properties: {
21
23
  url: {
22
- type: "string",
24
+ type: AutomationIOType.STRING,
23
25
  title: "Webhook URL",
24
26
  },
25
27
  value1: {
26
- type: "string",
28
+ type: AutomationIOType.STRING,
27
29
  title: "Payload Value 1",
28
30
  },
29
31
  value2: {
30
- type: "string",
32
+ type: AutomationIOType.STRING,
31
33
  title: "Payload Value 2",
32
34
  },
33
35
  value3: {
34
- type: "string",
36
+ type: AutomationIOType.STRING,
35
37
  title: "Payload Value 3",
36
38
  },
37
39
  value4: {
38
- type: "string",
40
+ type: AutomationIOType.STRING,
39
41
  title: "Payload Value 4",
40
42
  },
41
43
  value5: {
42
- type: "string",
44
+ type: AutomationIOType.STRING,
43
45
  title: "Payload Value 5",
44
46
  },
45
47
  },
@@ -48,11 +50,11 @@ export const definition: AutomationStepSchema = {
48
50
  outputs: {
49
51
  properties: {
50
52
  httpStatus: {
51
- type: "number",
53
+ type: AutomationIOType.NUMBER,
52
54
  description: "The HTTP status code of the request",
53
55
  },
54
56
  response: {
55
- type: "string",
57
+ type: AutomationIOType.STRING,
56
58
  description: "The response from Zapier",
57
59
  },
58
60
  },
@@ -1,6 +1,6 @@
1
1
  import TestConfig from "../../../tests/utilities/TestConfiguration"
2
2
  import { context } from "@budibase/backend-core"
3
- import { ACTION_DEFINITIONS, getAction } from "../../actions"
3
+ import { BUILTIN_ACTION_DEFINITIONS, getAction } from "../../actions"
4
4
  import emitter from "../../../events/index"
5
5
  import env from "../../../environment"
6
6
 
@@ -57,4 +57,4 @@ export async function runStep(stepId: string, inputs: any, stepContext?: any) {
57
57
  }
58
58
 
59
59
  export const apiKey = "test"
60
- export const actions = ACTION_DEFINITIONS
60
+ export const actions = BUILTIN_ACTION_DEFINITIONS
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,8 +18,8 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  fields: {
18
- type: "object",
19
- customType: "triggerSchema",
21
+ type: AutomationIOType.OBJECT,
22
+ customType: AutomationCustomIOType.TRIGGER_SCHEMA,
20
23
  title: "Fields",
21
24
  },
22
25
  },
@@ -25,13 +28,13 @@ export const definition: AutomationTriggerSchema = {
25
28
  outputs: {
26
29
  properties: {
27
30
  fields: {
28
- type: "object",
31
+ type: AutomationIOType.OBJECT,
29
32
  description: "Fields submitted from the app frontend",
30
- customType: "triggerSchema",
33
+ customType: AutomationCustomIOType.TRIGGER_SCHEMA,
31
34
  },
32
35
  },
33
36
  required: ["fields"],
34
37
  },
35
38
  },
36
- type: "TRIGGER",
39
+ type: AutomationStepType.TRIGGER,
37
40
  }
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,8 +18,8 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  cron: {
18
- type: "string",
19
- customType: "cron",
21
+ type: AutomationIOType.STRING,
22
+ customType: AutomationCustomIOType.CRON,
20
23
  title: "Expression",
21
24
  },
22
25
  },
@@ -25,12 +28,12 @@ export const definition: AutomationTriggerSchema = {
25
28
  outputs: {
26
29
  properties: {
27
30
  timestamp: {
28
- type: "number",
31
+ type: AutomationIOType.NUMBER,
29
32
  description: "Timestamp the cron was executed",
30
33
  },
31
34
  },
32
35
  required: ["timestamp"],
33
36
  },
34
37
  },
35
- type: "TRIGGER",
38
+ type: AutomationStepType.TRIGGER,
36
39
  }
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,8 +18,8 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  tableId: {
18
- type: "string",
19
- customType: "table",
21
+ type: AutomationIOType.STRING,
22
+ customType: AutomationCustomIOType.TABLE,
20
23
  title: "Table",
21
24
  },
22
25
  },
@@ -25,13 +28,13 @@ export const definition: AutomationTriggerSchema = {
25
28
  outputs: {
26
29
  properties: {
27
30
  row: {
28
- type: "object",
29
- customType: "row",
31
+ type: AutomationIOType.OBJECT,
32
+ customType: AutomationCustomIOType.ROW,
30
33
  description: "The row that was deleted",
31
34
  },
32
35
  },
33
36
  required: ["row"],
34
37
  },
35
38
  },
36
- type: "TRIGGER",
39
+ type: AutomationStepType.TRIGGER,
37
40
  }
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,8 +18,8 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  tableId: {
18
- type: "string",
19
- customType: "table",
21
+ type: AutomationIOType.STRING,
22
+ customType: AutomationCustomIOType.TABLE,
20
23
  title: "Table",
21
24
  },
22
25
  },
@@ -25,21 +28,21 @@ export const definition: AutomationTriggerSchema = {
25
28
  outputs: {
26
29
  properties: {
27
30
  row: {
28
- type: "object",
29
- customType: "row",
31
+ type: AutomationIOType.OBJECT,
32
+ customType: AutomationCustomIOType.ROW,
30
33
  description: "The new row that was created",
31
34
  },
32
35
  id: {
33
- type: "string",
36
+ type: AutomationIOType.STRING,
34
37
  description: "Row ID - can be used for updating",
35
38
  },
36
39
  revision: {
37
- type: "string",
40
+ type: AutomationIOType.STRING,
38
41
  description: "Revision of row",
39
42
  },
40
43
  },
41
44
  required: ["row", "id"],
42
45
  },
43
46
  },
44
- type: "TRIGGER",
47
+ type: AutomationStepType.TRIGGER,
45
48
  }
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,8 +18,8 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  tableId: {
18
- type: "string",
19
- customType: "table",
21
+ type: AutomationIOType.STRING,
22
+ customType: AutomationCustomIOType.TABLE,
20
23
  title: "Table",
21
24
  },
22
25
  },
@@ -25,21 +28,21 @@ export const definition: AutomationTriggerSchema = {
25
28
  outputs: {
26
29
  properties: {
27
30
  row: {
28
- type: "object",
29
- customType: "row",
31
+ type: AutomationIOType.OBJECT,
32
+ customType: AutomationCustomIOType.ROW,
30
33
  description: "The row that was updated",
31
34
  },
32
35
  id: {
33
- type: "string",
36
+ type: AutomationIOType.STRING,
34
37
  description: "Row ID - can be used for updating",
35
38
  },
36
39
  revision: {
37
- type: "string",
40
+ type: AutomationIOType.STRING,
38
41
  description: "Revision of row",
39
42
  },
40
43
  },
41
44
  required: ["row", "id"],
42
45
  },
43
46
  },
44
- type: "TRIGGER",
47
+ type: AutomationStepType.TRIGGER,
45
48
  }
@@ -1,4 +1,7 @@
1
1
  import {
2
+ AutomationCustomIOType,
3
+ AutomationIOType,
4
+ AutomationStepType,
2
5
  AutomationTriggerSchema,
3
6
  AutomationTriggerStepId,
4
7
  } from "@budibase/types"
@@ -15,13 +18,13 @@ export const definition: AutomationTriggerSchema = {
15
18
  inputs: {
16
19
  properties: {
17
20
  schemaUrl: {
18
- type: "string",
19
- customType: "webhookUrl",
21
+ type: AutomationIOType.STRING,
22
+ customType: AutomationCustomIOType.WEBHOOK_URL,
20
23
  title: "Schema URL",
21
24
  },
22
25
  triggerUrl: {
23
- type: "string",
24
- customType: "webhookUrl",
26
+ type: AutomationIOType.STRING,
27
+ customType: AutomationCustomIOType.WEBHOOK_URL,
25
28
  title: "Trigger URL",
26
29
  },
27
30
  },
@@ -30,12 +33,12 @@ export const definition: AutomationTriggerSchema = {
30
33
  outputs: {
31
34
  properties: {
32
35
  body: {
33
- type: "object",
36
+ type: AutomationIOType.OBJECT,
34
37
  description: "Body of the request which hit the webhook",
35
38
  },
36
39
  },
37
40
  required: ["body"],
38
41
  },
39
42
  },
40
- type: "TRIGGER",
43
+ type: AutomationStepType.TRIGGER,
41
44
  }
@@ -0,0 +1 @@
1
+ export * from "./processors"
@@ -0,0 +1,14 @@
1
+ import userGroupProcessor from "./syncUsers"
2
+ import { docUpdates } from "@budibase/backend-core"
3
+
4
+ export type UpdateCallback = (docId: string) => void
5
+ let started = false
6
+
7
+ export function init(updateCb?: UpdateCallback) {
8
+ if (started) {
9
+ return
10
+ }
11
+ const processors = [userGroupProcessor(updateCb)]
12
+ docUpdates.init(processors)
13
+ started = true
14
+ }
@@ -0,0 +1,35 @@
1
+ import { constants, logging } from "@budibase/backend-core"
2
+ import { sdk as proSdk } from "@budibase/pro"
3
+ import { DocUpdateEvent, UserGroupSyncEvents } from "@budibase/types"
4
+ import { syncUsersToAllApps } from "../../sdk/app/applications/sync"
5
+ import { UpdateCallback } from "./processors"
6
+
7
+ export default function process(updateCb?: UpdateCallback) {
8
+ const processor = async (update: DocUpdateEvent) => {
9
+ try {
10
+ const docId = update.id
11
+ const isGroup = docId.startsWith(constants.DocumentType.GROUP)
12
+ let userIds: string[]
13
+ if (isGroup) {
14
+ const group = await proSdk.groups.get(docId)
15
+ userIds = group.users?.map(user => user._id) || []
16
+ } else {
17
+ userIds = [docId]
18
+ }
19
+ if (userIds.length > 0) {
20
+ await syncUsersToAllApps(userIds)
21
+ }
22
+ if (updateCb) {
23
+ updateCb(docId)
24
+ }
25
+ } catch (err: any) {
26
+ // if something not found - no changes to perform
27
+ if (err?.status === 404) {
28
+ return
29
+ } else {
30
+ logging.logAlert("Failed to perform user/group app sync", err)
31
+ }
32
+ }
33
+ }
34
+ return { events: UserGroupSyncEvents, processor }
35
+ }
@@ -2,4 +2,5 @@ import BudibaseEmitter from "./BudibaseEmitter"
2
2
 
3
3
  const emitter = new BudibaseEmitter()
4
4
 
5
+ export { init } from "./docUpdates"
5
6
  export default emitter
@@ -14,11 +14,11 @@ import firebase from "./firebase"
14
14
  import redis from "./redis"
15
15
  import snowflake from "./snowflake"
16
16
  import oracle from "./oracle"
17
- import { getPlugins } from "../api/controllers/plugin"
18
17
  import { SourceName, Integration, PluginType } from "@budibase/types"
19
18
  import { getDatasourcePlugin } from "../utilities/fileSystem"
20
19
  import env from "../environment"
21
20
  import { cloneDeep } from "lodash"
21
+ import sdk from "../sdk"
22
22
 
23
23
  const DEFINITIONS: { [key: string]: Integration } = {
24
24
  [SourceName.POSTGRES]: postgres.schema,
@@ -79,7 +79,7 @@ export async function getDefinition(source: SourceName): Promise<Integration> {
79
79
  export async function getDefinitions() {
80
80
  const pluginSchemas: { [key: string]: Integration } = {}
81
81
  if (env.SELF_HOSTED) {
82
- const plugins = await getPlugins(PluginType.DATASOURCE)
82
+ const plugins = await sdk.plugins.fetch(PluginType.DATASOURCE)
83
83
  // extract the actual schema from each custom
84
84
  for (let plugin of plugins) {
85
85
  const sourceId = plugin.name
@@ -103,7 +103,7 @@ export async function getIntegration(integration: string) {
103
103
  return INTEGRATIONS[integration]
104
104
  }
105
105
  if (env.SELF_HOSTED) {
106
- const plugins = await getPlugins(PluginType.DATASOURCE)
106
+ const plugins = await sdk.plugins.fetch(PluginType.DATASOURCE)
107
107
  for (let plugin of plugins) {
108
108
  if (plugin.name === integration) {
109
109
  // need to use commonJS require due to its dynamic runtime nature
@@ -1,6 +1,117 @@
1
1
  import env from "../../../environment"
2
- import { db as dbCore, context } from "@budibase/backend-core"
2
+ import {
3
+ db as dbCore,
4
+ context,
5
+ docUpdates,
6
+ constants,
7
+ logging,
8
+ roles,
9
+ } from "@budibase/backend-core"
10
+ import { User, ContextUser, UserGroup } from "@budibase/types"
11
+ import { sdk as proSdk } from "@budibase/pro"
3
12
  import sdk from "../../"
13
+ import { getGlobalUsers, processUser } from "../../../utilities/global"
14
+ import { generateUserMetadataID, InternalTables } from "../../../db/utils"
15
+
16
+ type DeletedUser = { _id: string; deleted: boolean }
17
+
18
+ async function syncUsersToApp(
19
+ appId: string,
20
+ users: (User | DeletedUser)[],
21
+ groups: UserGroup[]
22
+ ) {
23
+ if (!(await dbCore.dbExists(appId))) {
24
+ return
25
+ }
26
+ await context.doInAppContext(appId, async () => {
27
+ const db = context.getAppDB()
28
+ for (let user of users) {
29
+ let ctxUser = user as ContextUser
30
+ let deletedUser = false
31
+ const metadataId = generateUserMetadataID(user._id!)
32
+ if ((user as DeletedUser).deleted) {
33
+ deletedUser = true
34
+ }
35
+
36
+ // make sure role is correct
37
+ if (!deletedUser) {
38
+ ctxUser = await processUser(ctxUser, { appId, groups })
39
+ }
40
+ let roleId = ctxUser.roleId
41
+ if (roleId === roles.BUILTIN_ROLE_IDS.PUBLIC) {
42
+ roleId = undefined
43
+ }
44
+
45
+ let metadata
46
+ try {
47
+ metadata = await db.get(metadataId)
48
+ } catch (err: any) {
49
+ if (err.status !== 404) {
50
+ throw err
51
+ }
52
+ // no metadata and user is to be deleted, can skip
53
+ // no role - user isn't in app anyway
54
+ if (!roleId) {
55
+ continue
56
+ } else if (!deletedUser) {
57
+ // doesn't exist yet, creating it
58
+ metadata = {
59
+ tableId: InternalTables.USER_METADATA,
60
+ }
61
+ }
62
+ }
63
+
64
+ // the user doesn't exist, or doesn't have a role anymore
65
+ // get rid of their metadata
66
+ if (deletedUser || !roleId) {
67
+ await db.remove(metadata)
68
+ continue
69
+ }
70
+
71
+ // assign the roleId for the metadata doc
72
+ if (roleId) {
73
+ metadata.roleId = roleId
74
+ }
75
+
76
+ let combined = sdk.users.combineMetadataAndUser(ctxUser, metadata)
77
+ // if no combined returned, there are no updates to make
78
+ if (combined) {
79
+ await db.put(combined)
80
+ }
81
+ }
82
+ })
83
+ }
84
+
85
+ export async function syncUsersToAllApps(userIds: string[]) {
86
+ // list of users, if one has been deleted it will be undefined in array
87
+ const users = (await getGlobalUsers(userIds, {
88
+ noProcessing: true,
89
+ })) as User[]
90
+ const groups = await proSdk.groups.fetch()
91
+ const finalUsers: (User | DeletedUser)[] = []
92
+ for (let userId of userIds) {
93
+ const user = users.find(user => user._id === userId)
94
+ if (!user) {
95
+ finalUsers.push({ _id: userId, deleted: true })
96
+ } else {
97
+ finalUsers.push(user)
98
+ }
99
+ }
100
+ const devAppIds = await dbCore.getDevAppIDs()
101
+ let promises = []
102
+ for (let devAppId of devAppIds) {
103
+ const prodAppId = dbCore.getProdAppID(devAppId)
104
+ for (let appId of [prodAppId, devAppId]) {
105
+ promises.push(syncUsersToApp(appId, finalUsers, groups))
106
+ }
107
+ }
108
+ const resp = await Promise.allSettled(promises)
109
+ const failed = resp.filter(promise => promise.status === "rejected")
110
+ if (failed.length > 0) {
111
+ const reasons = failed.map(fail => (fail as PromiseRejectedResult).reason)
112
+ logging.logAlert("Failed to sync users to apps", reasons)
113
+ }
114
+ }
4
115
 
5
116
  export async function syncApp(
6
117
  appId: string,
@@ -23,32 +134,28 @@ export async function syncApp(
23
134
  // specific case, want to make sure setup is skipped
24
135
  const prodDb = context.getProdAppDB({ skip_setup: true })
25
136
  const exists = await prodDb.exists()
26
- if (!exists) {
27
- // the database doesn't exist. Don't replicate
28
- return {
29
- message: "App sync not required, app not deployed.",
30
- }
31
- }
32
137
 
33
- const replication = new dbCore.Replication({
34
- source: prodAppId,
35
- target: appId,
36
- })
37
138
  let error
38
- try {
39
- const replOpts = replication.appReplicateOpts()
40
- if (opts?.automationOnly) {
41
- replOpts.filter = (doc: any) =>
42
- doc._id.startsWith(dbCore.DocumentType.AUTOMATION)
139
+ if (exists) {
140
+ const replication = new dbCore.Replication({
141
+ source: prodAppId,
142
+ target: appId,
143
+ })
144
+ try {
145
+ const replOpts = replication.appReplicateOpts()
146
+ if (opts?.automationOnly) {
147
+ replOpts.filter = (doc: any) =>
148
+ doc._id.startsWith(dbCore.DocumentType.AUTOMATION)
149
+ }
150
+ await replication.replicate(replOpts)
151
+ } catch (err) {
152
+ error = err
153
+ } finally {
154
+ await replication.close()
43
155
  }
44
- await replication.replicate(replOpts)
45
- } catch (err) {
46
- error = err
47
- } finally {
48
- await replication.close()
49
156
  }
50
157
 
51
- // sync the users
158
+ // sync the users - kept for safe keeping
52
159
  await sdk.users.syncGlobalUsers()
53
160
 
54
161
  if (error) {