@budibase/worker 2.2.26 → 2.2.27

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 (166) hide show
  1. package/Dockerfile +1 -1
  2. package/coverage/clover.xml +1393 -1364
  3. package/coverage/coverage-final.json +83 -77
  4. package/coverage/lcov-report/index.html +133 -133
  5. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +52 -52
  6. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +161 -218
  7. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +4 -4
  8. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +136 -0
  9. package/coverage/lcov-report/src/api/controllers/global/index.html +85 -70
  10. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +16 -16
  11. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +77 -77
  12. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +20 -20
  13. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +54 -54
  14. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +82 -43
  15. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +9 -9
  16. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +5 -5
  17. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +4 -4
  18. package/coverage/lcov-report/src/api/controllers/system/index.html +11 -11
  19. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +5 -5
  20. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +4 -4
  21. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +5 -5
  22. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +7 -7
  23. package/coverage/lcov-report/src/api/index.html +1 -1
  24. package/coverage/lcov-report/src/api/index.ts.html +37 -25
  25. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +14 -14
  26. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +25 -25
  27. package/coverage/lcov-report/src/api/routes/global/email.ts.html +13 -13
  28. package/coverage/lcov-report/src/api/routes/global/events.ts.html +109 -0
  29. package/coverage/lcov-report/src/api/routes/global/index.html +37 -22
  30. package/coverage/lcov-report/src/api/routes/global/license.ts.html +9 -9
  31. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +10 -10
  32. package/coverage/lcov-report/src/api/routes/global/self.ts.html +11 -11
  33. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +14 -14
  34. package/coverage/lcov-report/src/api/routes/global/users.ts.html +62 -20
  35. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +12 -12
  36. package/coverage/lcov-report/src/api/routes/index.html +7 -7
  37. package/coverage/lcov-report/src/api/routes/index.ts.html +29 -23
  38. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +10 -10
  39. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +9 -9
  40. package/coverage/lcov-report/src/api/routes/system/index.html +15 -15
  41. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +10 -10
  42. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +9 -9
  43. package/coverage/lcov-report/src/api/routes/system/status.ts.html +9 -9
  44. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +10 -10
  45. package/coverage/lcov-report/src/api/routes/validation/index.html +3 -3
  46. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +2 -2
  47. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +14 -14
  48. package/coverage/lcov-report/src/constants/index.html +17 -17
  49. package/coverage/lcov-report/src/constants/index.ts.html +77 -53
  50. package/coverage/lcov-report/src/constants/templates/index.html +19 -19
  51. package/coverage/lcov-report/src/constants/templates/index.ts.html +42 -42
  52. package/coverage/lcov-report/src/db/index.html +3 -3
  53. package/coverage/lcov-report/src/db/index.ts.html +10 -10
  54. package/coverage/lcov-report/src/environment.ts.html +44 -29
  55. package/coverage/lcov-report/src/index.html +27 -27
  56. package/coverage/lcov-report/src/index.ts.html +55 -55
  57. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +5 -5
  58. package/coverage/lcov-report/src/middleware/index.html +1 -1
  59. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +9 -9
  60. package/coverage/lcov-report/src/migrations/functions/index.html +11 -11
  61. package/coverage/lcov-report/src/migrations/index.html +15 -15
  62. package/coverage/lcov-report/src/migrations/index.ts.html +27 -27
  63. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +13 -13
  64. package/coverage/lcov-report/src/sdk/accounts/index.html +13 -13
  65. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +2 -2
  66. package/coverage/lcov-report/src/sdk/index.html +5 -5
  67. package/coverage/lcov-report/src/sdk/index.ts.html +6 -6
  68. package/coverage/lcov-report/src/sdk/users/events.ts.html +82 -58
  69. package/coverage/lcov-report/src/sdk/users/index.html +29 -29
  70. package/coverage/lcov-report/src/sdk/users/index.ts.html +2 -2
  71. package/coverage/lcov-report/src/sdk/users/users.ts.html +176 -119
  72. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +119 -95
  73. package/coverage/lcov-report/src/tests/api/accounts.ts.html +7 -7
  74. package/coverage/lcov-report/src/tests/api/auth.ts.html +8 -8
  75. package/coverage/lcov-report/src/tests/api/base.ts.html +5 -5
  76. package/coverage/lcov-report/src/tests/api/configs.ts.html +9 -9
  77. package/coverage/lcov-report/src/tests/api/email.ts.html +6 -6
  78. package/coverage/lcov-report/src/tests/api/environment.ts.html +6 -6
  79. package/coverage/lcov-report/src/tests/api/groups.ts.html +163 -0
  80. package/coverage/lcov-report/src/tests/api/index.html +91 -31
  81. package/coverage/lcov-report/src/tests/api/index.ts.html +62 -29
  82. package/coverage/lcov-report/src/tests/api/license.ts.html +136 -0
  83. package/coverage/lcov-report/src/tests/api/migrations.ts.html +8 -8
  84. package/coverage/lcov-report/src/tests/api/restore.ts.html +7 -7
  85. package/coverage/lcov-report/src/tests/api/roles.ts.html +181 -0
  86. package/coverage/lcov-report/src/tests/api/self.ts.html +7 -7
  87. package/coverage/lcov-report/src/tests/api/status.ts.html +6 -6
  88. package/coverage/lcov-report/src/tests/api/templates.ts.html +175 -0
  89. package/coverage/lcov-report/src/tests/api/tenants.ts.html +10 -10
  90. package/coverage/lcov-report/src/tests/api/users.ts.html +28 -25
  91. package/coverage/lcov-report/src/tests/controllers.ts.html +14 -14
  92. package/coverage/lcov-report/src/tests/index.html +34 -34
  93. package/coverage/lcov-report/src/tests/index.ts.html +19 -55
  94. package/coverage/lcov-report/src/tests/mocks/{email.js.html → email.ts.html} +5 -5
  95. package/coverage/lcov-report/src/tests/mocks/index.html +6 -6
  96. package/coverage/lcov-report/src/tests/mocks/index.ts.html +10 -10
  97. package/coverage/lcov-report/src/tests/structures/configs.ts.html +11 -11
  98. package/coverage/lcov-report/src/tests/structures/groups.ts.html +15 -15
  99. package/coverage/lcov-report/src/tests/structures/index.html +25 -25
  100. package/coverage/lcov-report/src/tests/structures/index.ts.html +17 -17
  101. package/coverage/lcov-report/src/tests/structures/users.ts.html +16 -16
  102. package/coverage/lcov-report/src/utilities/appService.ts.html +45 -18
  103. package/coverage/lcov-report/src/utilities/email.ts.html +28 -28
  104. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +4 -4
  105. package/coverage/lcov-report/src/utilities/index.html +27 -27
  106. package/coverage/lcov-report/src/utilities/index.ts.html +2 -2
  107. package/coverage/lcov-report/src/utilities/redis.ts.html +20 -20
  108. package/coverage/lcov-report/src/utilities/templates.ts.html +6 -6
  109. package/coverage/lcov-report/src/utilities/users.ts.html +3 -3
  110. package/coverage/lcov.info +2777 -2582
  111. package/jest.config.ts +7 -2
  112. package/package.json +10 -7
  113. package/scripts/dev/manage.js +2 -2
  114. package/src/api/controllers/global/auth.ts +1 -1
  115. package/src/api/controllers/global/configs.ts +112 -131
  116. package/src/api/controllers/global/events.ts +17 -0
  117. package/src/api/controllers/global/users.ts +14 -1
  118. package/src/api/index.ts +4 -0
  119. package/src/api/routes/global/auth.ts +1 -1
  120. package/src/api/routes/global/configs.ts +7 -7
  121. package/src/api/routes/global/email.ts +1 -1
  122. package/src/api/routes/global/events.ts +8 -0
  123. package/src/api/routes/global/license.ts +1 -1
  124. package/src/api/routes/global/roles.ts +1 -1
  125. package/src/api/routes/global/self.ts +1 -1
  126. package/src/api/routes/global/templates.ts +1 -1
  127. package/src/api/routes/global/tests/groups.spec.ts +58 -0
  128. package/src/api/routes/global/tests/license.spec.ts +0 -2
  129. package/src/api/routes/global/tests/roles.spec.ts +66 -5
  130. package/src/api/routes/global/tests/templates.spec.ts +81 -9
  131. package/src/api/routes/global/tests/users.spec.ts +2 -2
  132. package/src/api/routes/global/users.ts +15 -1
  133. package/src/api/routes/global/workspaces.ts +1 -1
  134. package/src/api/routes/index.ts +2 -0
  135. package/src/api/routes/system/accounts.ts +1 -1
  136. package/src/api/routes/system/environment.ts +1 -1
  137. package/src/api/routes/system/migrations.ts +1 -1
  138. package/src/api/routes/system/restore.ts +1 -1
  139. package/src/api/routes/system/status.ts +1 -1
  140. package/src/api/routes/system/tenants.ts +1 -1
  141. package/src/api/routes/system/tests/environment.spec.ts +1 -1
  142. package/src/constants/index.ts +13 -5
  143. package/src/db/index.ts +1 -1
  144. package/src/environment.ts +6 -1
  145. package/src/index.ts +5 -5
  146. package/src/middleware/cloudRestricted.ts +1 -1
  147. package/src/sdk/users/events.ts +8 -0
  148. package/src/sdk/users/users.ts +23 -4
  149. package/src/tests/TestConfiguration.ts +11 -3
  150. package/src/tests/api/groups.ts +26 -0
  151. package/src/tests/api/index.ts +12 -1
  152. package/src/tests/api/license.ts +17 -0
  153. package/src/tests/api/roles.ts +32 -0
  154. package/src/tests/api/templates.ts +30 -0
  155. package/src/tests/api/users.ts +2 -1
  156. package/src/tests/index.ts +6 -18
  157. package/src/tests/jestEnv.ts +11 -0
  158. package/src/tests/jestSetup.ts +3 -15
  159. package/src/tests/mocks/{email.js → email.ts} +1 -1
  160. package/src/tests/mocks/index.ts +4 -4
  161. package/src/tests/structures/configs.ts +2 -2
  162. package/src/tests/structures/groups.ts +1 -1
  163. package/src/tests/structures/index.ts +4 -4
  164. package/src/tests/structures/users.ts +1 -1
  165. package/src/utilities/appService.ts +12 -3
  166. package/tsconfig.json +2 -2
package/jest.config.ts CHANGED
@@ -2,11 +2,14 @@ import { Config } from "@jest/types"
2
2
  import * as fs from "fs"
3
3
 
4
4
  const config: Config.InitialOptions = {
5
- preset: "ts-jest",
6
5
  testEnvironment: "node",
7
- setupFiles: ["./src/tests/jestSetup.ts"],
6
+ setupFiles: ["./src/tests/jestEnv.ts"],
7
+ setupFilesAfterEnv: ["./src/tests/jestSetup.ts"],
8
8
  collectCoverageFrom: ["src/**/*.{js,ts}"],
9
9
  coverageReporters: ["lcov", "json", "clover"],
10
+ transform: {
11
+ "^.+\\.ts?$": "@swc/jest",
12
+ },
10
13
  }
11
14
 
12
15
  if (!process.env.CI) {
@@ -19,6 +22,8 @@ if (!process.env.CI) {
19
22
  }
20
23
  // add pro sources if they exist
21
24
  if (fs.existsSync("../../../budibase-pro")) {
25
+ config.moduleNameMapper["@budibase/pro/(.*)"] =
26
+ "<rootDir>/../../../budibase-pro/packages/pro/$1"
22
27
  config.moduleNameMapper["@budibase/pro"] =
23
28
  "<rootDir>/../../../budibase-pro/packages/pro/src"
24
29
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/worker",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.2.26",
4
+ "version": "2.2.27",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -36,10 +36,10 @@
36
36
  "author": "Budibase",
37
37
  "license": "GPL-3.0",
38
38
  "dependencies": {
39
- "@budibase/backend-core": "^2.2.26",
40
- "@budibase/pro": "2.2.25",
41
- "@budibase/string-templates": "^2.2.26",
42
- "@budibase/types": "^2.2.26",
39
+ "@budibase/backend-core": "^2.2.27",
40
+ "@budibase/pro": "2.2.27-alpha.0",
41
+ "@budibase/string-templates": "^2.2.27",
42
+ "@budibase/types": "^2.2.27",
43
43
  "@koa/router": "8.0.8",
44
44
  "@sentry/node": "6.17.7",
45
45
  "@techpass/passport-openidconnect": "0.3.2",
@@ -70,13 +70,16 @@
70
70
  "server-destroy": "1.0.1"
71
71
  },
72
72
  "devDependencies": {
73
+ "@swc/core": "^1.3.25",
74
+ "@swc/jest": "^0.2.24",
73
75
  "@types/jest": "26.0.23",
74
76
  "@types/jsonwebtoken": "8.5.1",
75
77
  "@types/koa": "2.13.4",
76
- "@types/koa__router": "8.0.11",
78
+ "@types/koa__router": "8.0.8",
77
79
  "@types/node": "14.18.20",
78
80
  "@types/node-fetch": "2.6.1",
79
81
  "@types/pouchdb": "6.4.0",
82
+ "@types/server-destroy": "1.0.1",
80
83
  "@types/uuid": "8.3.4",
81
84
  "@typescript-eslint/parser": "5.45.0",
82
85
  "copyfiles": "2.4.1",
@@ -94,5 +97,5 @@
94
97
  "typescript": "4.7.3",
95
98
  "update-dotenv": "1.1.1"
96
99
  },
97
- "gitHead": "a60084bc0ef21373d57e3d0d75872cdc2b3af5b4"
100
+ "gitHead": "d5e24cc25f7eff877eb808046f0069359fddeb74"
98
101
  }
@@ -21,14 +21,14 @@ async function init() {
21
21
  COUCH_DB_PASSWORD: "budibase",
22
22
  // empty string is false
23
23
  MULTI_TENANCY: "",
24
- DISABLE_ACCOUNT_PORTAL: "",
24
+ DISABLE_ACCOUNT_PORTAL: 1,
25
25
  ACCOUNT_PORTAL_URL: "http://localhost:10001",
26
26
  ACCOUNT_PORTAL_API_KEY: "budibase",
27
27
  PLATFORM_URL: "http://localhost:10000",
28
28
  APPS_URL: "http://localhost:4001",
29
29
  SERVICE: "worker-service",
30
30
  DEPLOYMENT_ENVIRONMENT: "development",
31
- TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS",
31
+ TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
32
32
  }
33
33
  let envFile = ""
34
34
  Object.keys(envFileJson).forEach(key => {
@@ -13,7 +13,7 @@ import { isEmailConfigured, sendEmail } from "../../../utilities/email"
13
13
  import { checkResetPasswordCode } from "../../../utilities/redis"
14
14
  import env from "../../../environment"
15
15
  import sdk from "../../../sdk"
16
- import { Config, ConfigType, User } from "@budibase/types"
16
+ import { ConfigType, User } from "@budibase/types"
17
17
 
18
18
  const { setCookie, getCookie, clearCookie, hash, platformLogout } = utils
19
19
  const { Cookie, Header } = constants
@@ -7,6 +7,7 @@ import {
7
7
  objectStore,
8
8
  tenancy,
9
9
  db as dbCore,
10
+ env as coreEnv,
10
11
  } from "@budibase/backend-core"
11
12
  import { checkAnyUserExists } from "../../../utilities/users"
12
13
  import {
@@ -17,127 +18,106 @@ import {
17
18
  GoogleConfig,
18
19
  OIDCConfig,
19
20
  SettingsConfig,
20
- BBContext,
21
+ isGoogleConfig,
22
+ isOIDCConfig,
23
+ isSettingsConfig,
24
+ isSMTPConfig,
25
+ Ctx,
26
+ UserCtx,
21
27
  } from "@budibase/types"
22
28
 
23
29
  const getEventFns = async (db: Database, config: ConfigDoc) => {
24
30
  const fns = []
25
- const type = config.type
26
31
 
27
32
  let existing
28
33
  if (config._id) {
29
34
  existing = await db.get(config._id)
30
35
  }
31
36
 
32
- const ssoType = type as SSOType
33
37
  if (!existing) {
34
- switch (config.type) {
35
- case ConfigType.SMTP: {
36
- fns.push(events.email.SMTPCreated)
37
- break
38
+ if (isSMTPConfig(config)) {
39
+ fns.push(events.email.SMTPCreated)
40
+ } else if (isGoogleConfig(config)) {
41
+ fns.push(() => events.auth.SSOCreated(ConfigType.GOOGLE))
42
+ if (config.config.activated) {
43
+ fns.push(() => events.auth.SSOActivated(ConfigType.GOOGLE))
38
44
  }
39
- case ConfigType.GOOGLE: {
40
- const googleCfg = config as GoogleConfig
41
- fns.push(() => events.auth.SSOCreated(ssoType))
42
- if (googleCfg.config.activated) {
43
- fns.push(() => events.auth.SSOActivated(ssoType))
44
- }
45
- break
45
+ } else if (isOIDCConfig(config)) {
46
+ fns.push(() => events.auth.SSOCreated(ConfigType.OIDC))
47
+ if (config.config.configs[0].activated) {
48
+ fns.push(() => events.auth.SSOActivated(ConfigType.OIDC))
46
49
  }
47
- case ConfigType.OIDC: {
48
- const oidcCfg = config as OIDCConfig
49
- fns.push(() => events.auth.SSOCreated(ssoType))
50
- if (oidcCfg.config.configs[0].activated) {
51
- fns.push(() => events.auth.SSOActivated(ssoType))
52
- }
53
- break
50
+ } else if (isSettingsConfig(config)) {
51
+ // company
52
+ const company = config.config.company
53
+ if (company && company !== "Budibase") {
54
+ fns.push(events.org.nameUpdated)
54
55
  }
55
- case ConfigType.SETTINGS: {
56
- // company
57
- const settingsCfg = config as SettingsConfig
58
- const company = settingsCfg.config.company
59
- if (company && company !== "Budibase") {
60
- fns.push(events.org.nameUpdated)
61
- }
62
56
 
63
- // logo
64
- const logoUrl = settingsCfg.config.logoUrl
65
- if (logoUrl) {
66
- fns.push(events.org.logoUpdated)
67
- }
57
+ // logo
58
+ const logoUrl = config.config.logoUrl
59
+ if (logoUrl) {
60
+ fns.push(events.org.logoUpdated)
61
+ }
68
62
 
69
- // platform url
70
- const platformUrl = settingsCfg.config.platformUrl
71
- if (
72
- platformUrl &&
73
- platformUrl !== "http://localhost:10000" &&
74
- env.SELF_HOSTED
75
- ) {
76
- fns.push(events.org.platformURLUpdated)
77
- }
78
- break
63
+ // platform url
64
+ const platformUrl = config.config.platformUrl
65
+ if (
66
+ platformUrl &&
67
+ platformUrl !== "http://localhost:10000" &&
68
+ env.SELF_HOSTED
69
+ ) {
70
+ fns.push(events.org.platformURLUpdated)
79
71
  }
80
72
  }
81
73
  } else {
82
- switch (config.type) {
83
- case ConfigType.SMTP: {
84
- fns.push(events.email.SMTPUpdated)
85
- break
74
+ if (isSMTPConfig(config)) {
75
+ fns.push(events.email.SMTPUpdated)
76
+ } else if (isGoogleConfig(config)) {
77
+ fns.push(() => events.auth.SSOUpdated(ConfigType.GOOGLE))
78
+ if (!existing.config.activated && config.config.activated) {
79
+ fns.push(() => events.auth.SSOActivated(ConfigType.GOOGLE))
80
+ } else if (existing.config.activated && !config.config.activated) {
81
+ fns.push(() => events.auth.SSODeactivated(ConfigType.GOOGLE))
86
82
  }
87
- case ConfigType.GOOGLE: {
88
- const googleCfg = config as GoogleConfig
89
- fns.push(() => events.auth.SSOUpdated(ssoType))
90
- if (!existing.config.activated && googleCfg.config.activated) {
91
- fns.push(() => events.auth.SSOActivated(ssoType))
92
- } else if (existing.config.activated && !googleCfg.config.activated) {
93
- fns.push(() => events.auth.SSODeactivated(ssoType))
94
- }
95
- break
83
+ } else if (isOIDCConfig(config)) {
84
+ fns.push(() => events.auth.SSOUpdated(ConfigType.OIDC))
85
+ if (
86
+ !existing.config.configs[0].activated &&
87
+ config.config.configs[0].activated
88
+ ) {
89
+ fns.push(() => events.auth.SSOActivated(ConfigType.OIDC))
90
+ } else if (
91
+ existing.config.configs[0].activated &&
92
+ !config.config.configs[0].activated
93
+ ) {
94
+ fns.push(() => events.auth.SSODeactivated(ConfigType.OIDC))
96
95
  }
97
- case ConfigType.OIDC: {
98
- const oidcCfg = config as OIDCConfig
99
- fns.push(() => events.auth.SSOUpdated(ssoType))
100
- if (
101
- !existing.config.configs[0].activated &&
102
- oidcCfg.config.configs[0].activated
103
- ) {
104
- fns.push(() => events.auth.SSOActivated(ssoType))
105
- } else if (
106
- existing.config.configs[0].activated &&
107
- !oidcCfg.config.configs[0].activated
108
- ) {
109
- fns.push(() => events.auth.SSODeactivated(ssoType))
110
- }
111
- break
96
+ } else if (isSettingsConfig(config)) {
97
+ // company
98
+ const existingCompany = existing.config.company
99
+ const company = config.config.company
100
+ if (company && company !== "Budibase" && existingCompany !== company) {
101
+ fns.push(events.org.nameUpdated)
112
102
  }
113
- case ConfigType.SETTINGS: {
114
- // company
115
- const settingsCfg = config as SettingsConfig
116
- const existingCompany = existing.config.company
117
- const company = settingsCfg.config.company
118
- if (company && company !== "Budibase" && existingCompany !== company) {
119
- fns.push(events.org.nameUpdated)
120
- }
121
103
 
122
- // logo
123
- const existingLogoUrl = existing.config.logoUrl
124
- const logoUrl = settingsCfg.config.logoUrl
125
- if (logoUrl && existingLogoUrl !== logoUrl) {
126
- fns.push(events.org.logoUpdated)
127
- }
104
+ // logo
105
+ const existingLogoUrl = existing.config.logoUrl
106
+ const logoUrl = config.config.logoUrl
107
+ if (logoUrl && existingLogoUrl !== logoUrl) {
108
+ fns.push(events.org.logoUpdated)
109
+ }
128
110
 
129
- // platform url
130
- const existingPlatformUrl = existing.config.platformUrl
131
- const platformUrl = settingsCfg.config.platformUrl
132
- if (
133
- platformUrl &&
134
- platformUrl !== "http://localhost:10000" &&
135
- existingPlatformUrl !== platformUrl &&
136
- env.SELF_HOSTED
137
- ) {
138
- fns.push(events.org.platformURLUpdated)
139
- }
140
- break
111
+ // platform url
112
+ const existingPlatformUrl = existing.config.platformUrl
113
+ const platformUrl = config.config.platformUrl
114
+ if (
115
+ platformUrl &&
116
+ platformUrl !== "http://localhost:10000" &&
117
+ existingPlatformUrl !== platformUrl &&
118
+ env.SELF_HOSTED
119
+ ) {
120
+ fns.push(events.org.platformURLUpdated)
141
121
  }
142
122
  }
143
123
  }
@@ -145,7 +125,7 @@ const getEventFns = async (db: Database, config: ConfigDoc) => {
145
125
  return fns
146
126
  }
147
127
 
148
- export async function save(ctx: BBContext) {
128
+ export async function save(ctx: UserCtx) {
149
129
  const db = tenancy.getGlobalDB()
150
130
  const { type, workspace, user, config } = ctx.request.body
151
131
  let eventFns = await getEventFns(db, ctx.request.body)
@@ -187,7 +167,7 @@ export async function save(ctx: BBContext) {
187
167
  }
188
168
  }
189
169
 
190
- export async function fetch(ctx: BBContext) {
170
+ export async function fetch(ctx: UserCtx) {
191
171
  const db = tenancy.getGlobalDB()
192
172
  const response = await db.allDocs(
193
173
  dbCore.getConfigParams(
@@ -204,7 +184,7 @@ export async function fetch(ctx: BBContext) {
204
184
  * Gets the most granular config for a particular configuration type.
205
185
  * The hierarchy is type -> workspace -> user.
206
186
  */
207
- export async function find(ctx: BBContext) {
187
+ export async function find(ctx: UserCtx) {
208
188
  const db = tenancy.getGlobalDB()
209
189
 
210
190
  const { userId, workspaceId } = ctx.query
@@ -237,18 +217,18 @@ export async function find(ctx: BBContext) {
237
217
  }
238
218
  }
239
219
 
240
- export async function publicOidc(ctx: BBContext) {
220
+ export async function publicOidc(ctx: Ctx) {
241
221
  const db = tenancy.getGlobalDB()
242
222
  try {
243
223
  // Find the config with the most granular scope based on context
244
- const oidcConfig = await dbCore.getScopedFullConfig(db, {
224
+ const oidcConfig: OIDCConfig = await dbCore.getScopedFullConfig(db, {
245
225
  type: ConfigType.OIDC,
246
226
  })
247
227
 
248
228
  if (!oidcConfig) {
249
229
  ctx.body = {}
250
230
  } else {
251
- ctx.body = oidcConfig.config.configs.map((config: any) => ({
231
+ ctx.body = oidcConfig.config.configs.map(config => ({
252
232
  logo: config.logo,
253
233
  name: config.name,
254
234
  uuid: config.uuid,
@@ -259,7 +239,7 @@ export async function publicOidc(ctx: BBContext) {
259
239
  }
260
240
  }
261
241
 
262
- export async function publicSettings(ctx: BBContext) {
242
+ export async function publicSettings(ctx: Ctx) {
263
243
  const db = tenancy.getGlobalDB()
264
244
 
265
245
  try {
@@ -285,6 +265,16 @@ export async function publicSettings(ctx: BBContext) {
285
265
  config = publicConfig
286
266
  }
287
267
 
268
+ // enrich the logo url
269
+ // empty url means deleted
270
+ if (config.config.logoUrl && config.config.logoUrl !== "") {
271
+ config.config.logoUrl = objectStore.getGlobalFileUrl(
272
+ "settings",
273
+ "logoUrl",
274
+ config.config.logoUrlEtag
275
+ )
276
+ }
277
+
288
278
  // google button flag
289
279
  if (googleConfig && googleConfig.config) {
290
280
  // activated by default for configs pre-activated flag
@@ -311,28 +301,17 @@ export async function publicSettings(ctx: BBContext) {
311
301
  }
312
302
  }
313
303
 
314
- export async function upload(ctx: BBContext) {
315
- if (ctx.request.files == null || ctx.request.files.file.length > 1) {
304
+ export async function upload(ctx: UserCtx) {
305
+ if (ctx.request.files == null || Array.isArray(ctx.request.files.file)) {
316
306
  ctx.throw(400, "One file must be uploaded.")
317
307
  }
318
- const file = ctx.request.files.file
308
+ const file = ctx.request.files.file as any
319
309
  const { type, name } = ctx.params
320
310
 
321
- let bucket
322
- if (env.SELF_HOSTED) {
323
- bucket = objectStore.ObjectStoreBuckets.GLOBAL
324
- } else {
325
- bucket = objectStore.ObjectStoreBuckets.GLOBAL_CLOUD
326
- }
327
-
328
- let key
329
- if (env.MULTI_TENANCY) {
330
- key = `${tenancy.getTenantId()}/${type}/${name}`
331
- } else {
332
- key = `${type}/${name}`
333
- }
311
+ let bucket = coreEnv.GLOBAL_BUCKET_NAME
312
+ const key = objectStore.getGlobalFileS3Key(type, name)
334
313
 
335
- await objectStore.upload({
314
+ const result = await objectStore.upload({
336
315
  bucket,
337
316
  filename: key,
338
317
  path: file.path,
@@ -349,24 +328,26 @@ export async function upload(ctx: BBContext) {
349
328
  config: {},
350
329
  }
351
330
  }
352
- let url
353
- if (env.SELF_HOSTED) {
354
- url = `/${bucket}/${key}`
355
- } else {
356
- url = `${env.CDN_URL}/${key}`
331
+
332
+ // save the Etag for cache bursting
333
+ const etag = result.ETag
334
+ if (etag) {
335
+ cfgStructure.config[`${name}Etag`] = etag.replace(/"/g, "")
357
336
  }
358
337
 
359
- cfgStructure.config[`${name}`] = url
360
- // write back to db with url updated
338
+ // save the file key
339
+ cfgStructure.config[`${name}`] = key
340
+
341
+ // write back to db
361
342
  await db.put(cfgStructure)
362
343
 
363
344
  ctx.body = {
364
345
  message: "File has been uploaded and url stored to config.",
365
- url,
346
+ url: objectStore.getGlobalFileUrl(type, name, etag),
366
347
  }
367
348
  }
368
349
 
369
- export async function destroy(ctx: BBContext) {
350
+ export async function destroy(ctx: UserCtx) {
370
351
  const db = tenancy.getGlobalDB()
371
352
  const { id, rev } = ctx.params
372
353
  try {
@@ -378,7 +359,7 @@ export async function destroy(ctx: BBContext) {
378
359
  }
379
360
  }
380
361
 
381
- export async function configChecklist(ctx: BBContext) {
362
+ export async function configChecklist(ctx: Ctx) {
382
363
  const db = tenancy.getGlobalDB()
383
364
  const tenantId = tenancy.getTenantId()
384
365
 
@@ -0,0 +1,17 @@
1
+ import {
2
+ UserCtx,
3
+ PostEventPublishRequest,
4
+ EventPublishType,
5
+ } from "@budibase/types"
6
+ import { events } from "@budibase/backend-core"
7
+
8
+ export async function publish(ctx: UserCtx<PostEventPublishRequest, void>) {
9
+ switch (ctx.request.body.type) {
10
+ case EventPublishType.ENVIRONMENT_VARIABLE_UPGRADE_PANEL_OPENED:
11
+ await events.environmentVariable.upgradePanelOpened(ctx.user._id!)
12
+ break
13
+ default:
14
+ ctx.throw(400, "Invalid publish event type.")
15
+ }
16
+ ctx.status = 200
17
+ }
@@ -178,7 +178,7 @@ export const find = async (ctx: any) => {
178
178
 
179
179
  export const tenantUserLookup = async (ctx: any) => {
180
180
  const id = ctx.params.id
181
- const user = await tenancy.getTenantUser(id)
181
+ const user = await sdk.users.getPlatformUser(id)
182
182
  if (user) {
183
183
  ctx.body = user
184
184
  } else {
@@ -210,6 +210,19 @@ export const inviteMultiple = async (ctx: any) => {
210
210
  ctx.body = await sdk.users.invite(request)
211
211
  }
212
212
 
213
+ export const checkInvite = async (ctx: any) => {
214
+ const { code } = ctx.params
215
+ let invite
216
+ try {
217
+ invite = await checkInviteCode(code, false)
218
+ } catch (e) {
219
+ ctx.throw(400, "There was a problem with the invite")
220
+ }
221
+ ctx.body = {
222
+ email: invite.email,
223
+ }
224
+ }
225
+
213
226
  export const inviteAccept = async (ctx: any) => {
214
227
  const { inviteCode, password, firstName, lastName } = ctx.request.body
215
228
  try {
package/src/api/index.ts CHANGED
@@ -62,6 +62,10 @@ const PUBLIC_ENDPOINTS = [
62
62
  route: "/api/system/restored",
63
63
  method: "POST",
64
64
  },
65
+ {
66
+ route: "/api/global/users/invite",
67
+ method: "GET",
68
+ },
65
69
  ]
66
70
 
67
71
  const NO_TENANCY_ENDPOINTS = [
@@ -85,4 +85,4 @@ router
85
85
  .get("/api/global/auth/oidc/callback", authController.oidcAuth)
86
86
  .get("/api/admin/auth/oidc/callback", authController.oidcAuth)
87
87
 
88
- export = router
88
+ export default router
@@ -34,8 +34,8 @@ function settingValidation() {
34
34
  function googleValidation() {
35
35
  // prettier-ignore
36
36
  return Joi.object({
37
- clientID: Joi.string().required(),
38
- clientSecret: Joi.string().required(),
37
+ clientID: Joi.when('activated', { is: true, then: Joi.string().required() }),
38
+ clientSecret: Joi.when('activated', { is: true, then: Joi.string().required() }),
39
39
  activated: Joi.boolean().required(),
40
40
  }).unknown(true)
41
41
  }
@@ -45,12 +45,12 @@ function oidcValidation() {
45
45
  return Joi.object({
46
46
  configs: Joi.array().items(
47
47
  Joi.object({
48
- clientID: Joi.string().required(),
49
- clientSecret: Joi.string().required(),
50
- configUrl: Joi.string().required(),
48
+ clientID: Joi.when('activated', { is: true, then: Joi.string().required() }),
49
+ clientSecret: Joi.when('activated', { is: true, then: Joi.string().required() }),
50
+ configUrl: Joi.when('activated', { is: true, then: Joi.string().required() }),
51
51
  logo: Joi.string().allow("", null),
52
52
  name: Joi.string().allow("", null),
53
- uuid: Joi.string().required(),
53
+ uuid: Joi.when('activated', { is: true, then: Joi.string().required() }),
54
54
  activated: Joi.boolean().required(),
55
55
  scopes: Joi.array().optional()
56
56
  })
@@ -121,4 +121,4 @@ router
121
121
  controller.upload
122
122
  )
123
123
 
124
- export = router
124
+ export default router
@@ -33,4 +33,4 @@ router.post(
33
33
  controller.sendEmail
34
34
  )
35
35
 
36
- export = router
36
+ export default router
@@ -0,0 +1,8 @@
1
+ import Router from "@koa/router"
2
+ import * as controller from "../../controllers/global/events"
3
+
4
+ const router: Router = new Router()
5
+
6
+ router.post("/api/global/event/publish", controller.publish)
7
+
8
+ export default router
@@ -10,4 +10,4 @@ router
10
10
  .delete("/api/global/license/info", controller.deleteInfo)
11
11
  .get("/api/global/license/usage", controller.getQuotaUsage)
12
12
 
13
- export = router
13
+ export default router
@@ -13,4 +13,4 @@ router
13
13
  controller.removeAppRole
14
14
  )
15
15
 
16
- export = router
16
+ export default router
@@ -15,4 +15,4 @@ router
15
15
  controller.updateSelf
16
16
  )
17
17
 
18
- export = router
18
+ export default router
@@ -34,4 +34,4 @@ router
34
34
  .get("/api/global/template/:id", controller.find)
35
35
  .delete("/api/global/template/:id/:rev", adminOnly, controller.destroy)
36
36
 
37
- export = router
37
+ export default router
@@ -0,0 +1,58 @@
1
+ import { events } from "@budibase/backend-core"
2
+ import { structures, TestConfiguration, mocks } from "../../../../tests"
3
+
4
+ describe("/api/global/groups", () => {
5
+ const config = new TestConfiguration()
6
+
7
+ beforeAll(async () => {
8
+ await config.beforeAll()
9
+ })
10
+
11
+ afterAll(async () => {
12
+ await config.afterAll()
13
+ })
14
+
15
+ beforeEach(async () => {
16
+ mocks.licenses.useGroups()
17
+ })
18
+
19
+ describe("create", () => {
20
+ it("should be able to create a new group", async () => {
21
+ const group = structures.groups.UserGroup()
22
+ await config.api.groups.saveGroup(group)
23
+ expect(events.group.created).toBeCalledTimes(1)
24
+ expect(events.group.updated).not.toBeCalled()
25
+ expect(events.group.permissionsEdited).not.toBeCalled()
26
+ })
27
+ })
28
+
29
+ describe("update", () => {
30
+ it("should be able to update a basic group", async () => {
31
+ const group = structures.groups.UserGroup()
32
+ let oldGroup = await config.api.groups.saveGroup(group)
33
+
34
+ let updatedGroup = {
35
+ ...oldGroup.body,
36
+ ...group,
37
+ name: "New Name",
38
+ }
39
+ await config.api.groups.saveGroup(updatedGroup)
40
+
41
+ expect(events.group.updated).toBeCalledTimes(1)
42
+ expect(events.group.permissionsEdited).not.toBeCalled()
43
+ })
44
+
45
+ describe("destroy", () => {
46
+ it("should be able to delete a basic group", async () => {
47
+ const group = structures.groups.UserGroup()
48
+ let oldGroup = await config.api.groups.saveGroup(group)
49
+ await config.api.groups.deleteGroup(
50
+ oldGroup.body._id,
51
+ oldGroup.body._rev
52
+ )
53
+
54
+ expect(events.group.deleted).toBeCalledTimes(1)
55
+ })
56
+ })
57
+ })
58
+ })