@budibase/worker 2.3.20 → 2.3.21-alpha.0

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
@@ -30,7 +30,7 @@ describe("/api/global/self", () => {
30
30
  user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
31
31
  expect(res.body._id).toBe(user._id)
32
32
  expect(events.user.updated).toBeCalledTimes(1)
33
- expect(events.user.updated).toBeCalledWith(user)
33
+ expect(events.user.updated).toBeCalledWith(dbUser)
34
34
  expect(events.user.passwordUpdated).not.toBeCalled()
35
35
  })
36
36
 
@@ -44,12 +44,11 @@ describe("/api/global/self", () => {
44
44
  const dbUser = await config.getUser(user.email)
45
45
  user._rev = dbUser._rev
46
46
  user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
47
- delete user.password
48
47
  expect(res.body._id).toBe(user._id)
49
48
  expect(events.user.updated).toBeCalledTimes(1)
50
- expect(events.user.updated).toBeCalledWith(user)
49
+ expect(events.user.updated).toBeCalledWith(dbUser)
51
50
  expect(events.user.passwordUpdated).toBeCalledTimes(1)
52
- expect(events.user.passwordUpdated).toBeCalledWith(user)
51
+ expect(events.user.passwordUpdated).toBeCalledWith(dbUser)
53
52
  })
54
53
  })
55
54
  })
@@ -1,14 +1,11 @@
1
1
  import { InviteUsersResponse, User } from "@budibase/types"
2
2
 
3
3
  jest.mock("nodemailer")
4
- import {
5
- TestConfiguration,
6
- mocks,
7
- structures,
8
- TENANT_1,
9
- } from "../../../../tests"
4
+ import { TestConfiguration, mocks, structures } from "../../../../tests"
10
5
  const sendMailMock = mocks.email.mock()
11
- import { events, tenancy } from "@budibase/backend-core"
6
+ import { events, tenancy, accounts as _accounts } from "@budibase/backend-core"
7
+
8
+ const accounts = jest.mocked(_accounts)
12
9
 
13
10
  describe("/api/global/users", () => {
14
11
  const config = new TestConfiguration()
@@ -25,7 +22,7 @@ describe("/api/global/users", () => {
25
22
  jest.clearAllMocks()
26
23
  })
27
24
 
28
- describe("invite", () => {
25
+ describe("POST /api/global/users/invite", () => {
29
26
  it("should be able to generate an invitation", async () => {
30
27
  const email = structures.users.newEmail()
31
28
  const { code, res } = await config.api.users.sendUserInvite(
@@ -33,7 +30,11 @@ describe("/api/global/users", () => {
33
30
  email
34
31
  )
35
32
 
36
- expect(res.body).toEqual({ message: "Invitation has been sent." })
33
+ expect(res.body?.message).toBe("Invitation has been sent.")
34
+ expect(res.body?.unsuccessful.length).toBe(0)
35
+ expect(res.body?.successful.length).toBe(1)
36
+ expect(res.body?.successful[0].email).toBe(email)
37
+
37
38
  expect(sendMailMock).toHaveBeenCalled()
38
39
  expect(code).toBeDefined()
39
40
  expect(events.user.invited).toBeCalledTimes(1)
@@ -42,7 +43,7 @@ describe("/api/global/users", () => {
42
43
  it("should not be able to generate an invitation for existing user", async () => {
43
44
  const { code, res } = await config.api.users.sendUserInvite(
44
45
  sendMailMock,
45
- config.defaultUser!.email,
46
+ config.user!.email,
46
47
  400
47
48
  )
48
49
 
@@ -70,7 +71,7 @@ describe("/api/global/users", () => {
70
71
  })
71
72
  })
72
73
 
73
- describe("inviteMultiple", () => {
74
+ describe("POST /api/global/users/multi/invite", () => {
74
75
  it("should be able to generate an invitation", async () => {
75
76
  const newUserInvite = () => ({
76
77
  email: structures.users.newEmail(),
@@ -88,7 +89,7 @@ describe("/api/global/users", () => {
88
89
  })
89
90
 
90
91
  it("should not be able to generate an invitation for existing user", async () => {
91
- const request = [{ email: config.defaultUser!.email, userInfo: {} }]
92
+ const request = [{ email: config.user!.email, userInfo: {} }]
92
93
 
93
94
  const res = await config.api.users.sendMultiUserInvite(request)
94
95
 
@@ -101,7 +102,7 @@ describe("/api/global/users", () => {
101
102
  })
102
103
  })
103
104
 
104
- describe("bulk (create)", () => {
105
+ describe("POST /api/global/users/bulk", () => {
105
106
  it("should ignore users existing in the same tenant", async () => {
106
107
  const user = await config.createUser()
107
108
  jest.clearAllMocks()
@@ -118,7 +119,7 @@ describe("/api/global/users", () => {
118
119
  const user = await config.createUser()
119
120
  jest.clearAllMocks()
120
121
 
121
- await tenancy.doInTenant(TENANT_1, async () => {
122
+ await tenancy.doInTenant(config.getTenantId(), async () => {
122
123
  const response = await config.api.users.bulkCreateUsers([user])
123
124
 
124
125
  expect(response.created?.successful.length).toBe(0)
@@ -164,7 +165,7 @@ describe("/api/global/users", () => {
164
165
  })
165
166
  })
166
167
 
167
- describe("create", () => {
168
+ describe("POST /api/global/users", () => {
168
169
  it("should be able to create a basic user", async () => {
169
170
  const user = structures.users.user()
170
171
 
@@ -231,7 +232,7 @@ describe("/api/global/users", () => {
231
232
  const user = await config.createUser()
232
233
  jest.clearAllMocks()
233
234
 
234
- await tenancy.doInTenant(TENANT_1, async () => {
235
+ await tenancy.doInTenant(config.getTenantId(), async () => {
235
236
  delete user._id
236
237
  const response = await config.api.users.saveUser(user, 400)
237
238
 
@@ -243,7 +244,7 @@ describe("/api/global/users", () => {
243
244
  it("should not be able to create user with the same email as an account", async () => {
244
245
  const user = structures.users.user()
245
246
  const account = structures.accounts.cloudAccount()
246
- mocks.accounts.getAccount.mockReturnValueOnce(account)
247
+ accounts.getAccount.mockReturnValueOnce(Promise.resolve(account))
247
248
 
248
249
  const response = await config.api.users.saveUser(user, 400)
249
250
 
@@ -284,7 +285,7 @@ describe("/api/global/users", () => {
284
285
  })
285
286
  })
286
287
 
287
- describe("update", () => {
288
+ describe("POST /api/global/users (update)", () => {
288
289
  it("should be able to update a basic user", async () => {
289
290
  const user = await config.createUser()
290
291
  jest.clearAllMocks()
@@ -299,7 +300,7 @@ describe("/api/global/users", () => {
299
300
  })
300
301
 
301
302
  it("should not allow a user to update their own admin/builder status", async () => {
302
- const user = (await config.api.users.getUser(config.defaultUser?._id!))
303
+ const user = (await config.api.users.getUser(config.user?._id!))
303
304
  .body as User
304
305
  await config.api.users.saveUser({
305
306
  ...user,
@@ -444,7 +445,7 @@ describe("/api/global/users", () => {
444
445
  })
445
446
 
446
447
  it("should not be able to update email address", async () => {
447
- const email = "email@test.com"
448
+ const email = structures.email()
448
449
  const user = await config.createUser(structures.users.user({ email }))
449
450
  user.email = "new@test.com"
450
451
 
@@ -469,9 +470,9 @@ describe("/api/global/users", () => {
469
470
  })
470
471
  })
471
472
 
472
- describe("bulk (delete)", () => {
473
+ describe("POST /api/global/users/bulk (delete)", () => {
473
474
  it("should not be able to bulk delete current user", async () => {
474
- const user = await config.defaultUser!
475
+ const user = await config.user!
475
476
 
476
477
  const response = await config.api.users.bulkDeleteUsers([user._id!], 400)
477
478
 
@@ -483,7 +484,7 @@ describe("/api/global/users", () => {
483
484
  const user = await config.createUser()
484
485
  const account = structures.accounts.cloudAccount()
485
486
  account.budibaseUserId = user._id!
486
- mocks.accounts.getAccountByTenantId.mockReturnValue(account)
487
+ accounts.getAccountByTenantId.mockReturnValue(Promise.resolve(account))
487
488
 
488
489
  const response = await config.api.users.bulkDeleteUsers([user._id!])
489
490
 
@@ -498,7 +499,7 @@ describe("/api/global/users", () => {
498
499
 
499
500
  it("should be able to bulk delete users", async () => {
500
501
  const account = structures.accounts.cloudAccount()
501
- mocks.accounts.getAccountByTenantId.mockReturnValue(account)
502
+ accounts.getAccountByTenantId.mockReturnValue(Promise.resolve(account))
502
503
 
503
504
  const builder = structures.users.builderUser()
504
505
  const admin = structures.users.adminUser()
@@ -522,7 +523,7 @@ describe("/api/global/users", () => {
522
523
  })
523
524
  })
524
525
 
525
- describe("destroy", () => {
526
+ describe("DELETE /api/global/users/:userId", () => {
526
527
  it("should be able to destroy a basic user", async () => {
527
528
  const user = await config.createUser()
528
529
  jest.clearAllMocks()
@@ -559,7 +560,7 @@ describe("/api/global/users", () => {
559
560
  it("should not be able to destroy account owner", async () => {
560
561
  const user = await config.createUser()
561
562
  const account = structures.accounts.cloudAccount()
562
- mocks.accounts.getAccount.mockReturnValueOnce(account)
563
+ accounts.getAccount.mockReturnValueOnce(Promise.resolve(account))
563
564
 
564
565
  const response = await config.api.users.deleteUser(user._id!, 400)
565
566
 
@@ -567,10 +568,10 @@ describe("/api/global/users", () => {
567
568
  })
568
569
 
569
570
  it("should not be able to destroy account owner as account owner", async () => {
570
- const user = await config.defaultUser!
571
+ const user = await config.user!
571
572
  const account = structures.accounts.cloudAccount()
572
573
  account.email = user.email
573
- mocks.accounts.getAccount.mockReturnValueOnce(account)
574
+ accounts.getAccount.mockReturnValueOnce(Promise.resolve(account))
574
575
 
575
576
  const response = await config.api.users.deleteUser(user._id!, 400)
576
577
 
@@ -38,13 +38,6 @@ function buildInviteMultipleValidation() {
38
38
  ))
39
39
  }
40
40
 
41
- function buildInviteLookupValidation() {
42
- // prettier-ignore
43
- return auth.joiValidator.params(Joi.object({
44
- code: Joi.string().required()
45
- }).unknown(true))
46
- }
47
-
48
41
  const createUserAdminOnly = (ctx: any, next: any) => {
49
42
  if (!ctx.request.body._id) {
50
43
  return auth.adminOnly(ctx, next)
@@ -57,8 +50,8 @@ function buildInviteAcceptValidation() {
57
50
  // prettier-ignore
58
51
  return auth.joiValidator.body(Joi.object({
59
52
  inviteCode: Joi.string().required(),
60
- password: Joi.string().required(),
61
- firstName: Joi.string().required(),
53
+ password: Joi.string().optional(),
54
+ firstName: Joi.string().optional(),
62
55
  lastName: Joi.string().optional(),
63
56
  }).required().unknown(true))
64
57
  }
@@ -88,22 +81,34 @@ router
88
81
  .get("/api/global/roles/:appId")
89
82
  .post(
90
83
  "/api/global/users/invite",
91
- auth.adminOnly,
84
+ auth.builderOrAdmin,
92
85
  buildInviteValidation(),
93
86
  controller.invite
94
87
  )
88
+ .post(
89
+ "/api/global/users/onboard",
90
+ auth.builderOrAdmin,
91
+ buildInviteMultipleValidation(),
92
+ controller.onboardUsers
93
+ )
95
94
  .post(
96
95
  "/api/global/users/multi/invite",
97
- auth.adminOnly,
96
+ auth.builderOrAdmin,
98
97
  buildInviteMultipleValidation(),
99
98
  controller.inviteMultiple
100
99
  )
101
100
 
102
101
  // non-global endpoints
102
+ .get("/api/global/users/invite/:code", controller.checkInvite)
103
+ .post(
104
+ "/api/global/users/invite/update/:code",
105
+ auth.builderOrAdmin,
106
+ controller.updateInvite
107
+ )
103
108
  .get(
104
- "/api/global/users/invite/:code",
105
- buildInviteLookupValidation(),
106
- controller.checkInvite
109
+ "/api/global/users/invites",
110
+ auth.builderOrAdmin,
111
+ controller.getUserInvites
107
112
  )
108
113
  .post(
109
114
  "/api/global/users/invite/accept",
@@ -18,6 +18,8 @@ import accountRoutes from "./system/accounts"
18
18
  import restoreRoutes from "./system/restore"
19
19
 
20
20
  let userGroupRoutes = api.groups
21
+ let auditLogRoutes = api.auditLogs
22
+
21
23
  export const routes: Router[] = [
22
24
  configRoutes,
23
25
  userRoutes,
@@ -32,6 +34,7 @@ export const routes: Router[] = [
32
34
  selfRoutes,
33
35
  licenseRoutes,
34
36
  userGroupRoutes,
37
+ auditLogRoutes,
35
38
  migrationRoutes,
36
39
  accountRoutes,
37
40
  restoreRoutes,
@@ -7,7 +7,7 @@ const router: Router = new Router()
7
7
  router.delete(
8
8
  "/api/system/tenants/:tenantId",
9
9
  middleware.adminOnly,
10
- controller.delete
10
+ controller.destroy
11
11
  )
12
12
 
13
13
  export default router
@@ -1,4 +1,4 @@
1
- import sdk from "../../../../sdk"
1
+ import * as accounts from "../../../../sdk/accounts"
2
2
  import { TestConfiguration, structures } from "../../../../tests"
3
3
  import { v4 as uuid } from "uuid"
4
4
 
@@ -24,8 +24,8 @@ describe("accounts", () => {
24
24
 
25
25
  const response = await config.api.accounts.saveMetadata(account)
26
26
 
27
- const id = sdk.accounts.formatAccountMetadataId(account.accountId)
28
- const metadata = await sdk.accounts.getMetadata(id)
27
+ const id = accounts.metadata.formatAccountMetadataId(account.accountId)
28
+ const metadata = await accounts.metadata.getMetadata(id)
29
29
  expect(response).toStrictEqual(metadata)
30
30
  })
31
31
  })
@@ -37,7 +37,7 @@ describe("accounts", () => {
37
37
 
38
38
  await config.api.accounts.destroyMetadata(account.accountId)
39
39
 
40
- const deleted = await sdk.accounts.getMetadata(account.accountId)
40
+ const deleted = await accounts.metadata.getMetadata(account.accountId)
41
41
  expect(deleted).toBe(undefined)
42
42
  })
43
43
 
@@ -30,7 +30,7 @@ describe("/api/system/migrations", () => {
30
30
  headers: {},
31
31
  status: 403,
32
32
  })
33
- expect(res.text).toBe("Unauthorized - no public worker access")
33
+ expect(res.body).toEqual({ message: "Unauthorized", status: 403 })
34
34
  expect(migrateFn).toBeCalledTimes(0)
35
35
  })
36
36
 
@@ -47,7 +47,7 @@ describe("/api/system/migrations", () => {
47
47
  headers: {},
48
48
  status: 403,
49
49
  })
50
- expect(res.text).toBe("Unauthorized - no public worker access")
50
+ expect(res.body).toEqual({ message: "Unauthorized", status: 403 })
51
51
  })
52
52
 
53
53
  it("returns definitions", async () => {
@@ -25,12 +25,12 @@ describe("/api/system/restore", () => {
25
25
  })
26
26
 
27
27
  it("restores in self host", async () => {
28
- config.modeSelf()
28
+ config.selfHosted()
29
29
  const res = await config.api.restore.restored()
30
30
  expect(res.body).toEqual({
31
31
  message: "System prepared after restore.",
32
32
  })
33
- config.modeCloud()
33
+ config.cloudHosted()
34
34
  })
35
35
  })
36
36
  })
@@ -1,6 +1,6 @@
1
1
  import { TestConfiguration } from "../../../../tests"
2
- import { accounts } from "@budibase/backend-core"
3
- import { mocks } from "@budibase/backend-core/tests"
2
+ import { accounts as _accounts } from "@budibase/backend-core"
3
+ const accounts = jest.mocked(_accounts)
4
4
 
5
5
  describe("/api/system/status", () => {
6
6
  const config = new TestConfiguration()
@@ -19,7 +19,7 @@ describe("/api/system/status", () => {
19
19
 
20
20
  describe("GET /api/system/status", () => {
21
21
  it("returns status in self host", async () => {
22
- config.modeSelf()
22
+ config.selfHosted()
23
23
  const res = await config.api.status.getStatus()
24
24
  expect(res.body).toEqual({
25
25
  health: {
@@ -27,7 +27,7 @@ describe("/api/system/status", () => {
27
27
  },
28
28
  })
29
29
  expect(accounts.getStatus).toBeCalledTimes(0)
30
- config.modeCloud()
30
+ config.cloudHosted()
31
31
  })
32
32
 
33
33
  it("returns status in cloud", async () => {
@@ -37,7 +37,7 @@ describe("/api/system/status", () => {
37
37
  },
38
38
  }
39
39
 
40
- mocks.accounts.getStatus.mockReturnValueOnce(value)
40
+ accounts.getStatus.mockReturnValueOnce(Promise.resolve(value))
41
41
 
42
42
  const res = await config.api.status.getStatus()
43
43
 
package/src/db/index.ts CHANGED
@@ -1,10 +1,16 @@
1
1
  import * as core from "@budibase/backend-core"
2
2
  import env from "../environment"
3
3
 
4
- export const init = () => {
5
- const dbConfig: any = {}
4
+ export function init() {
5
+ const dbConfig: any = {
6
+ replication: true,
7
+ find: true,
8
+ }
9
+
6
10
  if (env.isTest() && !env.COUCH_DB_URL) {
7
11
  dbConfig.inMemory = true
12
+ dbConfig.allDbs = true
8
13
  }
14
+
9
15
  core.init({ db: dbConfig })
10
16
  }
package/src/ddApm.ts ADDED
@@ -0,0 +1,7 @@
1
+ import apm from "dd-trace"
2
+
3
+ // enable APM if configured
4
+ if (process.env.DD_APM_ENABLED) {
5
+ console.log("Starting dd-trace")
6
+ apm.init()
7
+ }
@@ -0,0 +1,10 @@
1
+ import apm from "elastic-apm-node"
2
+
3
+ // enable APM if configured
4
+ if (process.env.ELASTIC_APM_ENABLED) {
5
+ console.log("Starting elastic-apm-node")
6
+ apm.start({
7
+ serviceName: process.env.SERVICE,
8
+ environment: process.env.BUDIBASE_ENVIRONMENT,
9
+ })
10
+ }
@@ -65,6 +65,10 @@ const environment = {
65
65
  CHECKLIST_CACHE_TTL: parseIntSafe(process.env.CHECKLIST_CACHE_TTL) || 3600,
66
66
  SESSION_UPDATE_PERIOD: process.env.SESSION_UPDATE_PERIOD,
67
67
  ENCRYPTED_TEST_PUBLIC_API_KEY: process.env.ENCRYPTED_TEST_PUBLIC_API_KEY,
68
+ /**
69
+ * Mock the email service in use - links to ethereal hosted emails are logged instead.
70
+ */
71
+ ENABLE_EMAIL_TEST_MODE: process.env.ENABLE_EMAIL_TEST_MODE,
68
72
  _set(key: any, value: any) {
69
73
  process.env[key] = value
70
74
  // @ts-ignore
package/src/index.ts CHANGED
@@ -1,20 +1,27 @@
1
- // need to load environment first
2
- import env from "./environment"
1
+ if (process.env.DD_APM_ENABLED) {
2
+ require("./ddApm")
3
+ }
3
4
 
4
- // enable APM if configured
5
5
  if (process.env.ELASTIC_APM_ENABLED) {
6
- const apm = require("elastic-apm-node").start({
7
- serviceName: process.env.SERVICE,
8
- environment: process.env.BUDIBASE_ENVIRONMENT,
9
- })
6
+ require("./elasticApm")
10
7
  }
11
8
 
9
+ // need to load environment first
10
+ import env from "./environment"
12
11
  import { Scope } from "@sentry/node"
13
12
  import { Event } from "@sentry/types/dist/event"
14
13
  import Application from "koa"
15
14
  import { bootstrap } from "global-agent"
16
15
  import * as db from "./db"
17
- import { auth, logging, events, middleware } from "@budibase/backend-core"
16
+ import { sdk as proSdk } from "@budibase/pro"
17
+ import {
18
+ auth,
19
+ logging,
20
+ events,
21
+ middleware,
22
+ queue,
23
+ env as coreEnv,
24
+ } from "@budibase/backend-core"
18
25
  db.init()
19
26
  import Koa from "koa"
20
27
  import koaBody from "koa-body"
@@ -24,8 +31,20 @@ import * as redis from "./utilities/redis"
24
31
  const Sentry = require("@sentry/node")
25
32
  const koaSession = require("koa-session")
26
33
  const logger = require("koa-pino-logger")
34
+ const { userAgent } = require("koa-useragent")
35
+
27
36
  import destroyable from "server-destroy"
28
37
 
38
+ // configure events to use the pro audit log write
39
+ // can't integrate directly into backend-core due to cyclic issues
40
+ events.processors.init(proSdk.auditLogs.write)
41
+
42
+ if (coreEnv.ENABLE_SSO_MAINTENANCE_MODE) {
43
+ console.warn(
44
+ "Warning: ENABLE_SSO_MAINTENANCE_MODE is set. It is recommended this flag is disabled if maintenance is not in progress"
45
+ )
46
+ }
47
+
29
48
  // this will setup http and https proxies form env variables
30
49
  bootstrap()
31
50
 
@@ -38,6 +57,7 @@ app.use(koaBody({ multipart: true }))
38
57
  app.use(koaSession(app))
39
58
  app.use(middleware.logging)
40
59
  app.use(logger(logging.pinoSettings()))
60
+ app.use(userAgent)
41
61
 
42
62
  // authentication
43
63
  app.use(auth.passport.initialize())
@@ -73,6 +93,7 @@ server.on("close", async () => {
73
93
  console.log("Server Closed")
74
94
  await redis.shutdown()
75
95
  await events.shutdown()
96
+ await queue.shutdown()
76
97
  if (!env.isTest()) {
77
98
  process.exit(errCode)
78
99
  }
@@ -24,7 +24,7 @@ describe("tenancy middleware", () => {
24
24
  })
25
25
 
26
26
  it("should get tenant id from header", async () => {
27
- const tenantId = structures.uuid()
27
+ const tenantId = structures.tenant.id()
28
28
  const headers = {
29
29
  [constants.Header.TENANT_ID]: tenantId,
30
30
  }
@@ -35,7 +35,7 @@ describe("tenancy middleware", () => {
35
35
  })
36
36
 
37
37
  it("should get tenant id from query param", async () => {
38
- const tenantId = structures.uuid()
38
+ const tenantId = structures.tenant.id()
39
39
  const res = await config.request.get(
40
40
  `/api/global/configs/checklist?tenantId=${tenantId}`
41
41
  )
@@ -43,7 +43,7 @@ describe("tenancy middleware", () => {
43
43
  })
44
44
 
45
45
  it("should get tenant id from subdomain", async () => {
46
- const tenantId = structures.uuid()
46
+ const tenantId = structures.tenant.id()
47
47
  const headers = {
48
48
  host: `${tenantId}.localhost:10000`,
49
49
  }
@@ -67,7 +67,7 @@ describe("tenancy middleware", () => {
67
67
  it("should throw when no tenant id is found", async () => {
68
68
  const res = await config.request.get(`/api/global/configs/checklist`)
69
69
  expect(res.status).toBe(403)
70
- expect(res.text).toBe("Tenant id not set")
70
+ expect(res.body).toEqual({ message: "Tenant id not set", status: 403 })
71
71
  expect(res.headers[constants.Header.TENANT_ID]).toBe(undefined)
72
72
  })
73
73
  })
@@ -1,5 +1,6 @@
1
1
  import { User } from "@budibase/types"
2
- import sdk from "../../sdk"
2
+ import * as usersSdk from "../../sdk/users"
3
+ import { platform } from "@budibase/backend-core"
3
4
 
4
5
  /**
5
6
  * Date:
@@ -9,11 +10,11 @@ import sdk from "../../sdk"
9
10
  * Re-sync the global-db users to the global-info db users
10
11
  */
11
12
  export const run = async (globalDb: any) => {
12
- const users = (await sdk.users.allUsers()) as User[]
13
+ const users = (await usersSdk.allUsers()) as User[]
13
14
  const promises = []
14
15
  for (let user of users) {
15
16
  promises.push(
16
- sdk.users.addTenant(user.tenantId, user._id as string, user.email)
17
+ platform.users.addUser(user.tenantId, user._id as string, user.email)
17
18
  )
18
19
  }
19
20
  await Promise.all(promises)
@@ -1 +1,2 @@
1
- export * from "./accounts"
1
+ export * as metadata from "./metadata"
2
+ export { accounts as api } from "@budibase/backend-core"
@@ -2,7 +2,6 @@ import { AccountMetadata } from "@budibase/types"
2
2
  import {
3
3
  db,
4
4
  StaticDatabases,
5
- HTTPError,
6
5
  DocumentType,
7
6
  SEPARATOR,
8
7
  } from "@budibase/backend-core"