@budibase/worker 2.3.20 → 2.3.21-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 (180) hide show
  1. package/__mocks__/node-fetch.ts +23 -0
  2. package/jest-testcontainers-config.js +8 -0
  3. package/jest.config.ts +14 -18
  4. package/package.json +12 -8
  5. package/scripts/dev/manage.js +1 -0
  6. package/scripts/test.sh +12 -0
  7. package/src/api/controllers/global/auth.ts +109 -111
  8. package/src/api/controllers/global/configs.ts +150 -142
  9. package/src/api/controllers/global/self.ts +28 -44
  10. package/src/api/controllers/global/users.ts +211 -32
  11. package/src/api/controllers/system/accounts.ts +7 -5
  12. package/src/api/controllers/system/tenants.ts +4 -8
  13. package/src/api/index.ts +4 -20
  14. package/src/api/routes/global/auth.ts +10 -7
  15. package/src/api/routes/global/configs.ts +6 -12
  16. package/src/api/routes/global/tests/auditLogs.spec.ts +111 -0
  17. package/src/api/routes/global/tests/auth.spec.ts +217 -18
  18. package/src/api/routes/global/tests/configs.spec.ts +93 -65
  19. package/src/api/routes/global/tests/realEmail.spec.ts +1 -0
  20. package/src/api/routes/global/tests/roles.spec.ts +20 -14
  21. package/src/api/routes/global/tests/self.spec.ts +3 -4
  22. package/src/api/routes/global/tests/users.spec.ts +29 -28
  23. package/src/api/routes/global/users.ts +19 -14
  24. package/src/api/routes/index.ts +3 -0
  25. package/src/api/routes/system/tenants.ts +1 -1
  26. package/src/api/routes/system/tests/accounts.spec.ts +4 -4
  27. package/src/api/routes/system/tests/migrations.spec.ts +2 -2
  28. package/src/api/routes/system/tests/restore.spec.ts +2 -2
  29. package/src/api/routes/system/tests/status.spec.ts +5 -5
  30. package/src/db/index.ts +8 -2
  31. package/src/ddApm.ts +7 -0
  32. package/src/elasticApm.ts +10 -0
  33. package/src/environment.ts +4 -0
  34. package/src/index.ts +29 -8
  35. package/src/middleware/tests/tenancy.spec.ts +4 -4
  36. package/src/migrations/functions/globalInfoSyncUsers.ts +4 -3
  37. package/src/sdk/accounts/index.ts +2 -1
  38. package/src/sdk/accounts/{accounts.ts → metadata.ts} +0 -1
  39. package/src/sdk/auth/auth.ts +86 -0
  40. package/src/sdk/auth/index.ts +1 -0
  41. package/src/sdk/tenants/index.ts +1 -0
  42. package/src/sdk/tenants/tenants.ts +76 -0
  43. package/src/sdk/users/events.ts +4 -0
  44. package/src/sdk/users/index.ts +1 -0
  45. package/src/sdk/users/tests/users.spec.ts +76 -0
  46. package/src/sdk/users/users.ts +86 -53
  47. package/src/tests/TestConfiguration.ts +41 -62
  48. package/src/tests/api/auditLogs.ts +26 -0
  49. package/src/tests/api/auth.ts +44 -14
  50. package/src/tests/api/base.ts +2 -1
  51. package/src/tests/api/configs.ts +9 -1
  52. package/src/tests/api/email.ts +1 -0
  53. package/src/tests/api/index.ts +3 -0
  54. package/src/tests/api/restore.ts +1 -0
  55. package/src/tests/api/users.ts +2 -2
  56. package/src/tests/jestEnv.ts +2 -1
  57. package/src/tests/jestSetup.ts +10 -6
  58. package/src/tests/logging.ts +34 -0
  59. package/src/tests/structures/configs.ts +20 -13
  60. package/src/tests/structures/index.ts +0 -4
  61. package/src/utilities/email.ts +22 -68
  62. package/src/utilities/redis.ts +42 -2
  63. package/src/utilities/templates.ts +4 -9
  64. package/coverage/clover.xml +0 -2199
  65. package/coverage/coverage-final.json +0 -84
  66. package/coverage/lcov-report/base.css +0 -224
  67. package/coverage/lcov-report/block-navigation.js +0 -87
  68. package/coverage/lcov-report/favicon.png +0 -0
  69. package/coverage/lcov-report/index.html +0 -431
  70. package/coverage/lcov-report/prettify.css +0 -1
  71. package/coverage/lcov-report/prettify.js +0 -2
  72. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  73. package/coverage/lcov-report/sorter.js +0 -196
  74. package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +0 -934
  75. package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +0 -1348
  76. package/coverage/lcov-report/src/api/controllers/global/email.ts.html +0 -196
  77. package/coverage/lcov-report/src/api/controllers/global/events.ts.html +0 -136
  78. package/coverage/lcov-report/src/api/controllers/global/index.html +0 -251
  79. package/coverage/lcov-report/src/api/controllers/global/license.ts.html +0 -187
  80. package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +0 -283
  81. package/coverage/lcov-report/src/api/controllers/global/self.ts.html +0 -577
  82. package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +0 -316
  83. package/coverage/lcov-report/src/api/controllers/global/users.ts.html +0 -838
  84. package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +0 -244
  85. package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +0 -148
  86. package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +0 -124
  87. package/coverage/lcov-report/src/api/controllers/system/index.html +0 -191
  88. package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +0 -124
  89. package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +0 -124
  90. package/coverage/lcov-report/src/api/controllers/system/status.ts.html +0 -133
  91. package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +0 -154
  92. package/coverage/lcov-report/src/api/index.html +0 -116
  93. package/coverage/lcov-report/src/api/index.ts.html +0 -595
  94. package/coverage/lcov-report/src/api/routes/global/auth.ts.html +0 -349
  95. package/coverage/lcov-report/src/api/routes/global/configs.ts.html +0 -457
  96. package/coverage/lcov-report/src/api/routes/global/email.ts.html +0 -193
  97. package/coverage/lcov-report/src/api/routes/global/events.ts.html +0 -109
  98. package/coverage/lcov-report/src/api/routes/global/index.html +0 -251
  99. package/coverage/lcov-report/src/api/routes/global/license.ts.html +0 -124
  100. package/coverage/lcov-report/src/api/routes/global/roles.ts.html +0 -133
  101. package/coverage/lcov-report/src/api/routes/global/self.ts.html +0 -139
  102. package/coverage/lcov-report/src/api/routes/global/templates.ts.html +0 -196
  103. package/coverage/lcov-report/src/api/routes/global/users.ts.html +0 -475
  104. package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +0 -196
  105. package/coverage/lcov-report/src/api/routes/index.html +0 -116
  106. package/coverage/lcov-report/src/api/routes/index.ts.html +0 -202
  107. package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +0 -142
  108. package/coverage/lcov-report/src/api/routes/system/environment.ts.html +0 -109
  109. package/coverage/lcov-report/src/api/routes/system/index.html +0 -191
  110. package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +0 -142
  111. package/coverage/lcov-report/src/api/routes/system/restore.ts.html +0 -109
  112. package/coverage/lcov-report/src/api/routes/system/status.ts.html +0 -109
  113. package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +0 -124
  114. package/coverage/lcov-report/src/api/routes/validation/index.html +0 -131
  115. package/coverage/lcov-report/src/api/routes/validation/index.ts.html +0 -88
  116. package/coverage/lcov-report/src/api/routes/validation/users.ts.html +0 -235
  117. package/coverage/lcov-report/src/constants/index.html +0 -116
  118. package/coverage/lcov-report/src/constants/index.ts.html +0 -637
  119. package/coverage/lcov-report/src/constants/templates/index.html +0 -116
  120. package/coverage/lcov-report/src/constants/templates/index.ts.html +0 -316
  121. package/coverage/lcov-report/src/db/index.html +0 -116
  122. package/coverage/lcov-report/src/db/index.ts.html +0 -115
  123. package/coverage/lcov-report/src/environment.ts.html +0 -388
  124. package/coverage/lcov-report/src/index.html +0 -131
  125. package/coverage/lcov-report/src/index.ts.html +0 -394
  126. package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +0 -139
  127. package/coverage/lcov-report/src/middleware/index.html +0 -116
  128. package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +0 -145
  129. package/coverage/lcov-report/src/migrations/functions/index.html +0 -116
  130. package/coverage/lcov-report/src/migrations/index.html +0 -116
  131. package/coverage/lcov-report/src/migrations/index.ts.html +0 -271
  132. package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +0 -262
  133. package/coverage/lcov-report/src/sdk/accounts/index.html +0 -131
  134. package/coverage/lcov-report/src/sdk/accounts/index.ts.html +0 -88
  135. package/coverage/lcov-report/src/sdk/index.html +0 -116
  136. package/coverage/lcov-report/src/sdk/index.ts.html +0 -106
  137. package/coverage/lcov-report/src/sdk/users/events.ts.html +0 -601
  138. package/coverage/lcov-report/src/sdk/users/index.html +0 -146
  139. package/coverage/lcov-report/src/sdk/users/index.ts.html +0 -88
  140. package/coverage/lcov-report/src/sdk/users/users.ts.html +0 -1999
  141. package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +0 -1075
  142. package/coverage/lcov-report/src/tests/api/accounts.ts.html +0 -160
  143. package/coverage/lcov-report/src/tests/api/auth.ts.html +0 -220
  144. package/coverage/lcov-report/src/tests/api/base.ts.html +0 -133
  145. package/coverage/lcov-report/src/tests/api/configs.ts.html +0 -226
  146. package/coverage/lcov-report/src/tests/api/email.ts.html +0 -148
  147. package/coverage/lcov-report/src/tests/api/environment.ts.html +0 -130
  148. package/coverage/lcov-report/src/tests/api/groups.ts.html +0 -163
  149. package/coverage/lcov-report/src/tests/api/index.html +0 -356
  150. package/coverage/lcov-report/src/tests/api/index.ts.html +0 -238
  151. package/coverage/lcov-report/src/tests/api/license.ts.html +0 -136
  152. package/coverage/lcov-report/src/tests/api/migrations.ts.html +0 -151
  153. package/coverage/lcov-report/src/tests/api/restore.ts.html +0 -127
  154. package/coverage/lcov-report/src/tests/api/roles.ts.html +0 -181
  155. package/coverage/lcov-report/src/tests/api/self.ts.html +0 -163
  156. package/coverage/lcov-report/src/tests/api/status.ts.html +0 -121
  157. package/coverage/lcov-report/src/tests/api/templates.ts.html +0 -175
  158. package/coverage/lcov-report/src/tests/api/tenants.ts.html +0 -130
  159. package/coverage/lcov-report/src/tests/api/users.ts.html +0 -514
  160. package/coverage/lcov-report/src/tests/controllers.ts.html +0 -100
  161. package/coverage/lcov-report/src/tests/index.html +0 -146
  162. package/coverage/lcov-report/src/tests/index.ts.html +0 -103
  163. package/coverage/lcov-report/src/tests/mocks/email.ts.html +0 -115
  164. package/coverage/lcov-report/src/tests/mocks/index.html +0 -131
  165. package/coverage/lcov-report/src/tests/mocks/index.ts.html +0 -106
  166. package/coverage/lcov-report/src/tests/structures/configs.ts.html +0 -313
  167. package/coverage/lcov-report/src/tests/structures/groups.ts.html +0 -118
  168. package/coverage/lcov-report/src/tests/structures/index.html +0 -161
  169. package/coverage/lcov-report/src/tests/structures/index.ts.html +0 -151
  170. package/coverage/lcov-report/src/tests/structures/users.ts.html +0 -196
  171. package/coverage/lcov-report/src/utilities/appService.ts.html +0 -208
  172. package/coverage/lcov-report/src/utilities/email.ts.html +0 -850
  173. package/coverage/lcov-report/src/utilities/fileSystem.ts.html +0 -100
  174. package/coverage/lcov-report/src/utilities/index.html +0 -206
  175. package/coverage/lcov-report/src/utilities/index.ts.html +0 -112
  176. package/coverage/lcov-report/src/utilities/redis.ts.html +0 -424
  177. package/coverage/lcov-report/src/utilities/templates.ts.html +0 -232
  178. package/coverage/lcov-report/src/utilities/users.ts.html +0 -133
  179. package/coverage/lcov.info +0 -4187
  180. package/src/tests/structures/users.ts +0 -37
@@ -1,12 +1,27 @@
1
+ import { CloudAccount, SSOUser, User } from "@budibase/types"
2
+
1
3
  jest.mock("nodemailer")
2
- import { TestConfiguration, mocks } from "../../../../tests"
4
+ import {
5
+ TestConfiguration,
6
+ mocks,
7
+ structures,
8
+ generator,
9
+ } from "../../../../tests"
3
10
  const sendMailMock = mocks.email.mock()
4
- import { events } from "@budibase/backend-core"
11
+ import { events, constants } from "@budibase/backend-core"
12
+ import { Response } from "superagent"
13
+
14
+ import * as userSdk from "../../../../sdk/users"
15
+
16
+ function getAuthCookie(response: Response) {
17
+ return response.headers["set-cookie"]
18
+ .find((s: string) => s.startsWith(`${constants.Cookie.Auth}=`))
19
+ .split("=")[1]
20
+ .split(";")[0]
21
+ }
5
22
 
6
- const expectSetAuthCookie = (res: any) => {
7
- expect(
8
- res.get("Set-Cookie").find((c: string) => c.startsWith("budibase:auth"))
9
- ).toBeDefined()
23
+ const expectSetAuthCookie = (response: Response) => {
24
+ expect(getAuthCookie(response).length > 1).toBe(true)
10
25
  }
11
26
 
12
27
  describe("/api/global/auth", () => {
@@ -24,53 +39,237 @@ describe("/api/global/auth", () => {
24
39
  jest.clearAllMocks()
25
40
  })
26
41
 
42
+ async function createSSOUser() {
43
+ return config.doInTenant(async () => {
44
+ return userSdk.save(structures.users.ssoUser(), {
45
+ requirePassword: false,
46
+ })
47
+ })
48
+ }
49
+
27
50
  describe("password", () => {
28
51
  describe("POST /api/global/auth/:tenantId/login", () => {
29
- it("should login", () => {})
52
+ it("logs in with correct credentials", async () => {
53
+ const tenantId = config.tenantId!
54
+ const email = config.user?.email!
55
+ const password = config.userPassword
56
+
57
+ const response = await config.api.auth.login(tenantId, email, password)
58
+
59
+ expectSetAuthCookie(response)
60
+ expect(events.auth.login).toBeCalledTimes(1)
61
+ })
62
+
63
+ it("should return 403 with incorrect credentials", async () => {
64
+ const tenantId = config.tenantId!
65
+ const email = config.user?.email!
66
+ const password = "incorrect"
67
+
68
+ const response = await config.api.auth.login(
69
+ tenantId,
70
+ email,
71
+ password,
72
+ { status: 403 }
73
+ )
74
+ expect(response.body).toEqual({
75
+ message: "Invalid credentials",
76
+ status: 403,
77
+ })
78
+ })
79
+
80
+ it("should return 403 when user doesn't exist", async () => {
81
+ const tenantId = config.tenantId!
82
+ const email = "invaliduser@test.com"
83
+ const password = "password"
84
+
85
+ const response = await config.api.auth.login(
86
+ tenantId,
87
+ email,
88
+ password,
89
+ { status: 403 }
90
+ )
91
+ expect(response.body).toEqual({
92
+ message: "Invalid credentials",
93
+ status: 403,
94
+ })
95
+ })
96
+
97
+ describe("sso user", () => {
98
+ let user: User
99
+
100
+ async function testSSOUser() {
101
+ const tenantId = user.tenantId!
102
+ const email = user.email
103
+ const password = "test"
104
+
105
+ const response = await config.api.auth.login(
106
+ tenantId,
107
+ email,
108
+ password,
109
+ { status: 403 }
110
+ )
111
+
112
+ expect(response.body).toEqual({
113
+ message: "Invalid credentials",
114
+ status: 403,
115
+ })
116
+ }
117
+
118
+ describe("budibase sso user", () => {
119
+ it("should prevent user from logging in", async () => {
120
+ user = await createSSOUser()
121
+ await testSSOUser()
122
+ })
123
+ })
124
+
125
+ describe("root account sso user", () => {
126
+ it("should prevent user from logging in", async () => {
127
+ user = await config.createUser()
128
+ const account = structures.accounts.ssoAccount() as CloudAccount
129
+ mocks.accounts.getAccount.mockReturnValueOnce(
130
+ Promise.resolve(account)
131
+ )
132
+
133
+ await testSSOUser()
134
+ })
135
+ })
136
+ })
30
137
  })
31
138
 
32
139
  describe("POST /api/global/auth/logout", () => {
33
140
  it("should logout", async () => {
34
- await config.api.auth.logout()
141
+ const response = await config.api.auth.logout()
35
142
  expect(events.auth.logout).toBeCalledTimes(1)
36
143
 
37
- // TODO: Verify sessions deleted
144
+ const authCookie = getAuthCookie(response)
145
+ expect(authCookie).toBe("")
38
146
  })
39
147
  })
40
148
 
41
149
  describe("POST /api/global/auth/:tenantId/reset", () => {
42
150
  it("should generate password reset email", async () => {
151
+ const user = await config.createUser()
152
+
43
153
  const { res, code } = await config.api.auth.requestPasswordReset(
44
- sendMailMock
154
+ sendMailMock,
155
+ user.email
45
156
  )
46
- const user = await config.getUser("test@test.com")
47
157
 
48
158
  expect(res.body).toEqual({
49
159
  message: "Please check your email for a reset link.",
50
160
  })
51
161
  expect(sendMailMock).toHaveBeenCalled()
52
-
53
162
  expect(code).toBeDefined()
54
163
  expect(events.user.passwordResetRequested).toBeCalledTimes(1)
55
164
  expect(events.user.passwordResetRequested).toBeCalledWith(user)
56
165
  })
166
+
167
+ describe("sso user", () => {
168
+ let user: User
169
+
170
+ async function testSSOUser() {
171
+ const { res } = await config.api.auth.requestPasswordReset(
172
+ sendMailMock,
173
+ user.email
174
+ )
175
+ expect(sendMailMock).not.toHaveBeenCalled()
176
+ }
177
+
178
+ describe("budibase sso user", () => {
179
+ it("should prevent user from generating password reset email", async () => {
180
+ user = await createSSOUser()
181
+ await testSSOUser()
182
+ })
183
+ })
184
+
185
+ describe("root account sso user", () => {
186
+ it("should prevent user from generating password reset email", async () => {
187
+ user = await config.createUser(structures.users.user())
188
+ const account = structures.accounts.ssoAccount() as CloudAccount
189
+ mocks.accounts.getAccount.mockReturnValueOnce(
190
+ Promise.resolve(account)
191
+ )
192
+
193
+ await testSSOUser()
194
+ })
195
+ })
196
+ })
57
197
  })
58
198
 
59
199
  describe("POST /api/global/auth/:tenantId/reset/update", () => {
60
200
  it("should reset password", async () => {
201
+ let user = await config.createUser()
61
202
  const { code } = await config.api.auth.requestPasswordReset(
62
- sendMailMock
203
+ sendMailMock,
204
+ user.email
63
205
  )
64
- const user = await config.getUser("test@test.com")
65
206
  delete user.password
66
207
 
67
- const res = await config.api.auth.updatePassword(code)
208
+ const newPassword = "newpassword"
209
+ const res = await config.api.auth.updatePassword(code!, newPassword)
210
+
211
+ user = await config.getUser(user.email)
212
+ delete user.password
68
213
 
69
214
  expect(res.body).toEqual({ message: "password reset successfully." })
70
215
  expect(events.user.passwordReset).toBeCalledTimes(1)
71
216
  expect(events.user.passwordReset).toBeCalledWith(user)
72
217
 
73
- // TODO: Login using new password
218
+ // login using new password
219
+ await config.api.auth.login(user.tenantId, user.email, newPassword)
220
+ })
221
+
222
+ describe("sso user", () => {
223
+ let user: User | SSOUser
224
+
225
+ async function testSSOUser(code: string) {
226
+ const res = await config.api.auth.updatePassword(
227
+ code!,
228
+ generator.string(),
229
+ { status: 400 }
230
+ )
231
+
232
+ expect(res.body).toEqual({
233
+ message: "Cannot reset password.",
234
+ status: 400,
235
+ })
236
+ }
237
+
238
+ describe("budibase sso user", () => {
239
+ it("should prevent user from generating password reset email", async () => {
240
+ user = await config.createUser()
241
+ const { code } = await config.api.auth.requestPasswordReset(
242
+ sendMailMock,
243
+ user.email
244
+ )
245
+
246
+ // convert to sso now that password reset has been requested
247
+ const ssoUser = user as SSOUser
248
+ ssoUser.providerType = structures.sso.providerType()
249
+ delete ssoUser.password
250
+ await config.doInTenant(() => userSdk.save(ssoUser))
251
+
252
+ await testSSOUser(code!)
253
+ })
254
+ })
255
+
256
+ describe("root account sso user", () => {
257
+ it("should prevent user from generating password reset email", async () => {
258
+ user = await config.createUser()
259
+ const { code } = await config.api.auth.requestPasswordReset(
260
+ sendMailMock,
261
+ user.email
262
+ )
263
+
264
+ // convert to account owner now that password has been requested
265
+ const account = structures.accounts.ssoAccount() as CloudAccount
266
+ mocks.accounts.getAccount.mockReturnValueOnce(
267
+ Promise.resolve(account)
268
+ )
269
+
270
+ await testSSOUser(code!)
271
+ })
272
+ })
74
273
  })
75
274
  })
76
275
  })
@@ -145,7 +344,7 @@ describe("/api/global/auth", () => {
145
344
  const location: string = res.get("location")
146
345
  expect(
147
346
  location.startsWith(
148
- "http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2Fdefault%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access"
347
+ `http://localhost/auth?response_type=code&client_id=clientId&redirect_uri=http%3A%2F%2Flocalhost%3A10000%2Fapi%2Fglobal%2Fauth%2F${config.tenantId}%2Foidc%2Fcallback&scope=openid%20profile%20email%20offline_access`
149
348
  )
150
349
  ).toBe(true)
151
350
  })
@@ -158,7 +357,7 @@ describe("/api/global/auth", () => {
158
357
 
159
358
  const res = await config.api.configs.OIDCCallback(configId, preAuthRes)
160
359
 
161
- expect(events.auth.login).toBeCalledWith("oidc")
360
+ expect(events.auth.login).toBeCalledWith("oidc", "oauth@example.com")
162
361
  expect(events.auth.login).toBeCalledTimes(1)
163
362
  expect(res.status).toBe(302)
164
363
  const location: string = res.get("location")
@@ -2,12 +2,13 @@
2
2
  jest.mock("nodemailer")
3
3
  import { TestConfiguration, structures, mocks } from "../../../../tests"
4
4
  mocks.email.mock()
5
- import { Config, events } from "@budibase/backend-core"
5
+ import { events } from "@budibase/backend-core"
6
+ import { GetPublicSettingsResponse, Config, ConfigType } from "@budibase/types"
6
7
 
7
8
  describe("configs", () => {
8
9
  const config = new TestConfiguration()
9
10
 
10
- beforeAll(async () => {
11
+ beforeEach(async () => {
11
12
  await config.beforeAll()
12
13
  })
13
14
 
@@ -19,22 +20,29 @@ describe("configs", () => {
19
20
  await config.afterAll()
20
21
  })
21
22
 
22
- describe("post /api/global/configs", () => {
23
- const saveConfig = async (conf: any, _id?: string, _rev?: string) => {
24
- const data = {
25
- ...conf,
26
- _id,
27
- _rev,
28
- }
29
-
30
- const res = await config.api.configs.saveConfig(data)
31
-
32
- return {
33
- ...data,
34
- ...res.body,
35
- }
23
+ const saveConfig = async (conf: Config, _id?: string, _rev?: string) => {
24
+ const data = {
25
+ ...conf,
26
+ _id,
27
+ _rev,
36
28
  }
37
-
29
+ const res = await config.api.configs.saveConfig(data)
30
+ return {
31
+ ...data,
32
+ ...res.body,
33
+ }
34
+ }
35
+
36
+ const saveSettingsConfig = async (
37
+ conf?: any,
38
+ _id?: string,
39
+ _rev?: string
40
+ ) => {
41
+ const settingsConfig = structures.configs.settings(conf)
42
+ return saveConfig(settingsConfig, _id, _rev)
43
+ }
44
+
45
+ describe("POST /api/global/configs", () => {
38
46
  describe("google", () => {
39
47
  const saveGoogleConfig = async (
40
48
  conf?: any,
@@ -49,20 +57,20 @@ describe("configs", () => {
49
57
  it("should create activated google config", async () => {
50
58
  await saveGoogleConfig()
51
59
  expect(events.auth.SSOCreated).toBeCalledTimes(1)
52
- expect(events.auth.SSOCreated).toBeCalledWith(Config.GOOGLE)
60
+ expect(events.auth.SSOCreated).toBeCalledWith(ConfigType.GOOGLE)
53
61
  expect(events.auth.SSODeactivated).not.toBeCalled()
54
62
  expect(events.auth.SSOActivated).toBeCalledTimes(1)
55
- expect(events.auth.SSOActivated).toBeCalledWith(Config.GOOGLE)
56
- await config.deleteConfig(Config.GOOGLE)
63
+ expect(events.auth.SSOActivated).toBeCalledWith(ConfigType.GOOGLE)
64
+ await config.deleteConfig(ConfigType.GOOGLE)
57
65
  })
58
66
 
59
67
  it("should create deactivated google config", async () => {
60
68
  await saveGoogleConfig({ activated: false })
61
69
  expect(events.auth.SSOCreated).toBeCalledTimes(1)
62
- expect(events.auth.SSOCreated).toBeCalledWith(Config.GOOGLE)
70
+ expect(events.auth.SSOCreated).toBeCalledWith(ConfigType.GOOGLE)
63
71
  expect(events.auth.SSOActivated).not.toBeCalled()
64
72
  expect(events.auth.SSODeactivated).not.toBeCalled()
65
- await config.deleteConfig(Config.GOOGLE)
73
+ await config.deleteConfig(ConfigType.GOOGLE)
66
74
  })
67
75
  })
68
76
 
@@ -76,11 +84,11 @@ describe("configs", () => {
76
84
  googleConf._rev
77
85
  )
78
86
  expect(events.auth.SSOUpdated).toBeCalledTimes(1)
79
- expect(events.auth.SSOUpdated).toBeCalledWith(Config.GOOGLE)
87
+ expect(events.auth.SSOUpdated).toBeCalledWith(ConfigType.GOOGLE)
80
88
  expect(events.auth.SSOActivated).not.toBeCalled()
81
89
  expect(events.auth.SSODeactivated).toBeCalledTimes(1)
82
- expect(events.auth.SSODeactivated).toBeCalledWith(Config.GOOGLE)
83
- await config.deleteConfig(Config.GOOGLE)
90
+ expect(events.auth.SSODeactivated).toBeCalledWith(ConfigType.GOOGLE)
91
+ await config.deleteConfig(ConfigType.GOOGLE)
84
92
  })
85
93
 
86
94
  it("should update google config to activated", async () => {
@@ -92,11 +100,11 @@ describe("configs", () => {
92
100
  googleConf._rev
93
101
  )
94
102
  expect(events.auth.SSOUpdated).toBeCalledTimes(1)
95
- expect(events.auth.SSOUpdated).toBeCalledWith(Config.GOOGLE)
103
+ expect(events.auth.SSOUpdated).toBeCalledWith(ConfigType.GOOGLE)
96
104
  expect(events.auth.SSODeactivated).not.toBeCalled()
97
105
  expect(events.auth.SSOActivated).toBeCalledTimes(1)
98
- expect(events.auth.SSOActivated).toBeCalledWith(Config.GOOGLE)
99
- await config.deleteConfig(Config.GOOGLE)
106
+ expect(events.auth.SSOActivated).toBeCalledWith(ConfigType.GOOGLE)
107
+ await config.deleteConfig(ConfigType.GOOGLE)
100
108
  })
101
109
  })
102
110
  })
@@ -115,20 +123,20 @@ describe("configs", () => {
115
123
  it("should create activated OIDC config", async () => {
116
124
  await saveOIDCConfig()
117
125
  expect(events.auth.SSOCreated).toBeCalledTimes(1)
118
- expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC)
126
+ expect(events.auth.SSOCreated).toBeCalledWith(ConfigType.OIDC)
119
127
  expect(events.auth.SSODeactivated).not.toBeCalled()
120
128
  expect(events.auth.SSOActivated).toBeCalledTimes(1)
121
- expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC)
122
- await config.deleteConfig(Config.OIDC)
129
+ expect(events.auth.SSOActivated).toBeCalledWith(ConfigType.OIDC)
130
+ await config.deleteConfig(ConfigType.OIDC)
123
131
  })
124
132
 
125
133
  it("should create deactivated OIDC config", async () => {
126
134
  await saveOIDCConfig({ activated: false })
127
135
  expect(events.auth.SSOCreated).toBeCalledTimes(1)
128
- expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC)
136
+ expect(events.auth.SSOCreated).toBeCalledWith(ConfigType.OIDC)
129
137
  expect(events.auth.SSOActivated).not.toBeCalled()
130
138
  expect(events.auth.SSODeactivated).not.toBeCalled()
131
- await config.deleteConfig(Config.OIDC)
139
+ await config.deleteConfig(ConfigType.OIDC)
132
140
  })
133
141
  })
134
142
 
@@ -142,11 +150,11 @@ describe("configs", () => {
142
150
  oidcConf._rev
143
151
  )
144
152
  expect(events.auth.SSOUpdated).toBeCalledTimes(1)
145
- expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC)
153
+ expect(events.auth.SSOUpdated).toBeCalledWith(ConfigType.OIDC)
146
154
  expect(events.auth.SSOActivated).not.toBeCalled()
147
155
  expect(events.auth.SSODeactivated).toBeCalledTimes(1)
148
- expect(events.auth.SSODeactivated).toBeCalledWith(Config.OIDC)
149
- await config.deleteConfig(Config.OIDC)
156
+ expect(events.auth.SSODeactivated).toBeCalledWith(ConfigType.OIDC)
157
+ await config.deleteConfig(ConfigType.OIDC)
150
158
  })
151
159
 
152
160
  it("should update OIDC config to activated", async () => {
@@ -158,11 +166,11 @@ describe("configs", () => {
158
166
  oidcConf._rev
159
167
  )
160
168
  expect(events.auth.SSOUpdated).toBeCalledTimes(1)
161
- expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC)
169
+ expect(events.auth.SSOUpdated).toBeCalledWith(ConfigType.OIDC)
162
170
  expect(events.auth.SSODeactivated).not.toBeCalled()
163
171
  expect(events.auth.SSOActivated).toBeCalledTimes(1)
164
- expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC)
165
- await config.deleteConfig(Config.OIDC)
172
+ expect(events.auth.SSOActivated).toBeCalledWith(ConfigType.OIDC)
173
+ await config.deleteConfig(ConfigType.OIDC)
166
174
  })
167
175
  })
168
176
  })
@@ -179,11 +187,11 @@ describe("configs", () => {
179
187
 
180
188
  describe("create", () => {
181
189
  it("should create SMTP config", async () => {
182
- await config.deleteConfig(Config.SMTP)
190
+ await config.deleteConfig(ConfigType.SMTP)
183
191
  await saveSMTPConfig()
184
192
  expect(events.email.SMTPUpdated).not.toBeCalled()
185
193
  expect(events.email.SMTPCreated).toBeCalledTimes(1)
186
- await config.deleteConfig(Config.SMTP)
194
+ await config.deleteConfig(ConfigType.SMTP)
187
195
  })
188
196
  })
189
197
 
@@ -194,24 +202,15 @@ describe("configs", () => {
194
202
  await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev)
195
203
  expect(events.email.SMTPCreated).not.toBeCalled()
196
204
  expect(events.email.SMTPUpdated).toBeCalledTimes(1)
197
- await config.deleteConfig(Config.SMTP)
205
+ await config.deleteConfig(ConfigType.SMTP)
198
206
  })
199
207
  })
200
208
  })
201
209
 
202
210
  describe("settings", () => {
203
- const saveSettingsConfig = async (
204
- conf?: any,
205
- _id?: string,
206
- _rev?: string
207
- ) => {
208
- const settingsConfig = structures.configs.settings(conf)
209
- return saveConfig(settingsConfig, _id, _rev)
210
- }
211
-
212
211
  describe("create", () => {
213
212
  it("should create settings config with default settings", async () => {
214
- await config.deleteConfig(Config.SETTINGS)
213
+ await config.deleteConfig(ConfigType.SETTINGS)
215
214
 
216
215
  await saveSettingsConfig()
217
216
 
@@ -221,8 +220,8 @@ describe("configs", () => {
221
220
  })
222
221
 
223
222
  it("should create settings config with non-default settings", async () => {
224
- config.modeSelf()
225
- await config.deleteConfig(Config.SETTINGS)
223
+ config.selfHosted()
224
+ await config.deleteConfig(ConfigType.SETTINGS)
226
225
  const conf = {
227
226
  company: "acme",
228
227
  logoUrl: "http://example.com",
@@ -234,14 +233,14 @@ describe("configs", () => {
234
233
  expect(events.org.nameUpdated).toBeCalledTimes(1)
235
234
  expect(events.org.logoUpdated).toBeCalledTimes(1)
236
235
  expect(events.org.platformURLUpdated).toBeCalledTimes(1)
237
- config.modeCloud()
236
+ config.cloudHosted()
238
237
  })
239
238
  })
240
239
 
241
240
  describe("update", () => {
242
241
  it("should update settings config", async () => {
243
- config.modeSelf()
244
- await config.deleteConfig(Config.SETTINGS)
242
+ config.selfHosted()
243
+ await config.deleteConfig(ConfigType.SETTINGS)
245
244
  const settingsConfig = await saveSettingsConfig()
246
245
  settingsConfig.config.company = "acme"
247
246
  settingsConfig.config.logoUrl = "http://example.com"
@@ -256,20 +255,49 @@ describe("configs", () => {
256
255
  expect(events.org.nameUpdated).toBeCalledTimes(1)
257
256
  expect(events.org.logoUpdated).toBeCalledTimes(1)
258
257
  expect(events.org.platformURLUpdated).toBeCalledTimes(1)
259
- config.modeCloud()
258
+ config.cloudHosted()
260
259
  })
261
260
  })
262
261
  })
263
262
  })
264
263
 
265
- it("should return the correct checklist status based on the state of the budibase installation", async () => {
266
- await config.saveSmtpConfig()
264
+ describe("GET /api/global/configs/checklist", () => {
265
+ it("should return the correct checklist", async () => {
266
+ await config.saveSmtpConfig()
267
+
268
+ const res = await config.api.configs.getConfigChecklist()
269
+ const checklist = res.body
267
270
 
268
- const res = await config.api.configs.getConfigChecklist()
269
- const checklist = res.body
271
+ expect(checklist.apps.checked).toBeFalsy()
272
+ expect(checklist.smtp.checked).toBeTruthy()
273
+ expect(checklist.adminUser.checked).toBeTruthy()
274
+ })
275
+ })
270
276
 
271
- expect(checklist.apps.checked).toBeFalsy()
272
- expect(checklist.smtp.checked).toBeTruthy()
273
- expect(checklist.adminUser.checked).toBeTruthy()
277
+ describe("GET /api/global/configs/public", () => {
278
+ it("should return the expected public settings", async () => {
279
+ await saveSettingsConfig()
280
+
281
+ const res = await config.api.configs.getPublicSettings()
282
+ const body = res.body as GetPublicSettingsResponse
283
+
284
+ const expected = {
285
+ _id: "config_settings",
286
+ type: "settings",
287
+ config: {
288
+ company: "Budibase",
289
+ logoUrl: "",
290
+ analyticsEnabled: false,
291
+ google: true,
292
+ googleCallbackUrl: `http://localhost:10000/api/global/auth/${config.tenantId}/google/callback`,
293
+ isSSOEnforced: false,
294
+ oidc: false,
295
+ oidcCallbackUrl: `http://localhost:10000/api/global/auth/${config.tenantId}/oidc/callback`,
296
+ platformUrl: "http://localhost:10000",
297
+ },
298
+ }
299
+ delete body._rev
300
+ expect(body).toEqual(expected)
301
+ })
274
302
  })
275
303
  })
@@ -1,3 +1,4 @@
1
+ jest.unmock("node-fetch")
1
2
  import { TestConfiguration } from "../../../../tests"
2
3
  import { EmailTemplatePurpose } from "../../../../constants"
3
4
  const nodemailer = require("nodemailer")
@@ -1,6 +1,7 @@
1
1
  import { structures, TestConfiguration } from "../../../../tests"
2
2
  import { context, db, permissions, roles } from "@budibase/backend-core"
3
3
  import { Mock } from "jest-mock"
4
+ import { Database } from "@budibase/types"
4
5
 
5
6
  jest.mock("@budibase/backend-core", () => {
6
7
  const core = jest.requireActual("@budibase/backend-core")
@@ -16,14 +17,13 @@ jest.mock("@budibase/backend-core", () => {
16
17
  }
17
18
  })
18
19
 
19
- const appDb = db.getDB("app_test")
20
- const mockAppDB = context.getAppDB as Mock
21
- mockAppDB.mockReturnValue(appDb)
20
+ let appId: string
21
+ let appDb: Database
22
22
 
23
23
  async function addAppMetadata() {
24
24
  await appDb.put({
25
25
  _id: "app_metadata",
26
- appId: "app_test",
26
+ appId: appId,
27
27
  name: "New App",
28
28
  version: "version",
29
29
  url: "url",
@@ -32,6 +32,7 @@ async function addAppMetadata() {
32
32
 
33
33
  describe("/api/global/roles", () => {
34
34
  const config = new TestConfiguration()
35
+
35
36
  const role = new roles.Role(
36
37
  db.generateRoleID("newRole"),
37
38
  roles.BUILTIN_ROLE_IDS.BASIC,
@@ -39,12 +40,19 @@ describe("/api/global/roles", () => {
39
40
  )
40
41
 
41
42
  beforeAll(async () => {
42
- console.debug(role)
43
- appDb.put(role)
44
- await addAppMetadata()
45
43
  await config.beforeAll()
46
44
  })
47
45
 
46
+ beforeEach(async () => {
47
+ appId = db.generateAppID(config.tenantId)
48
+ appDb = db.getDB(appId)
49
+ const mockAppDB = context.getAppDB as Mock
50
+ mockAppDB.mockReturnValue(appDb)
51
+
52
+ await addAppMetadata()
53
+ await appDb.put(role)
54
+ })
55
+
48
56
  afterAll(async () => {
49
57
  await config.afterAll()
50
58
  })
@@ -57,16 +65,14 @@ describe("/api/global/roles", () => {
57
65
  it("retrieves roles", async () => {
58
66
  const res = await config.api.roles.get()
59
67
  expect(res.body).toBeDefined()
60
- expect(res.body["app_test"].roles.length).toEqual(5)
61
- expect(res.body["app_test"].roles.map((r: any) => r._id)).toContain(
62
- role._id
63
- )
68
+ expect(res.body[appId].roles.length).toEqual(5)
69
+ expect(res.body[appId].roles.map((r: any) => r._id)).toContain(role._id)
64
70
  })
65
71
  })
66
72
 
67
73
  describe("GET api/global/roles/:appId", () => {
68
74
  it("finds a role by appId", async () => {
69
- const res = await config.api.roles.find("app_test")
75
+ const res = await config.api.roles.find(appId)
70
76
  expect(res.body).toBeDefined()
71
77
  expect(res.body.name).toEqual("New App")
72
78
  })
@@ -79,9 +85,9 @@ describe("/api/global/roles", () => {
79
85
  app_test: "role1",
80
86
  }
81
87
  const userResponse = await config.createUser(user)
82
- const res = await config.api.roles.remove("app_test")
88
+ const res = await config.api.roles.remove(appId)
83
89
  const updatedUser = await config.api.users.getUser(userResponse._id!)
84
- expect(updatedUser.body.roles).not.toHaveProperty("app_test")
90
+ expect(updatedUser.body.roles).not.toHaveProperty(appId)
85
91
  expect(res.body.message).toEqual("App role removed from all users")
86
92
  })
87
93
  })