@budibase/worker 1.2.57 → 1.2.58-alpha.2

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 (42) hide show
  1. package/package.json +7 -6
  2. package/scripts/jestSetup.js +6 -0
  3. package/src/api/controllers/global/auth.ts +14 -1
  4. package/src/api/controllers/global/users.ts +6 -8
  5. package/src/api/controllers/system/accounts.ts +21 -0
  6. package/src/api/{index.js → index.ts} +12 -16
  7. package/src/api/routes/global/configs.js +1 -0
  8. package/src/api/routes/{tests/auth.spec.js → global/tests/auth.spec.ts} +32 -56
  9. package/src/api/routes/{tests/configs.spec.js → global/tests/configs.spec.ts} +76 -47
  10. package/src/api/routes/{tests/email.spec.js → global/tests/email.spec.ts} +7 -15
  11. package/src/api/routes/{tests/realEmail.spec.js → global/tests/realEmail.spec.ts} +20 -21
  12. package/src/api/routes/{tests/self.spec.js → global/tests/self.spec.ts} +10 -18
  13. package/src/api/routes/global/tests/users.spec.ts +464 -0
  14. package/src/api/routes/index.js +2 -0
  15. package/src/api/routes/system/accounts.ts +19 -0
  16. package/src/api/routes/system/tests/accounts.spec.ts +57 -0
  17. package/src/{environment.js → environment.ts} +10 -9
  18. package/src/index.ts +6 -4
  19. package/src/sdk/accounts/accounts.ts +53 -0
  20. package/src/sdk/accounts/index.ts +1 -0
  21. package/src/sdk/index.ts +1 -0
  22. package/src/sdk/users/users.ts +217 -77
  23. package/src/tests/TestConfiguration.ts +273 -0
  24. package/src/tests/api/accounts.ts +28 -0
  25. package/src/tests/api/auth.ts +48 -0
  26. package/src/tests/api/configs.ts +40 -0
  27. package/src/tests/api/email.ts +24 -0
  28. package/src/tests/api/index.ts +25 -0
  29. package/src/tests/api/self.ts +21 -0
  30. package/src/tests/api/users.ts +95 -0
  31. package/src/tests/index.ts +14 -0
  32. package/src/tests/mocks/index.ts +7 -0
  33. package/src/tests/structures/accounts.ts +24 -0
  34. package/src/tests/structures/index.ts +20 -0
  35. package/src/tests/structures/users.ts +12 -4
  36. package/src/utilities/redis.js +1 -0
  37. package/scripts/load/users.js +0 -97
  38. package/src/api/routes/tests/users.spec.js +0 -390
  39. package/src/tests/TestConfiguration.js +0 -231
  40. package/src/tests/index.js +0 -12
  41. package/src/tests/mocks/index.js +0 -5
  42. package/src/tests/structures/index.js +0 -14
@@ -1,12 +1,11 @@
1
1
  jest.mock("nodemailer")
2
- const { config, mocks, structures, request } = require("../../../tests")
2
+ import { TestConfiguration, mocks, API } from "../../../../tests"
3
3
  const sendMailMock = mocks.email.mock()
4
-
5
- const { EmailTemplatePurpose } = require("../../../constants")
6
-
7
- const TENANT_ID = structures.TENANT_ID
4
+ import { EmailTemplatePurpose } from "../../../../constants"
8
5
 
9
6
  describe("/api/global/email", () => {
7
+ const config = new TestConfiguration()
8
+ const api = new API(config)
10
9
 
11
10
  beforeAll(async () => {
12
11
  await config.beforeAll()
@@ -20,16 +19,9 @@ describe("/api/global/email", () => {
20
19
  // initially configure settings
21
20
  await config.saveSmtpConfig()
22
21
  await config.saveSettingsConfig()
23
- const res = await request
24
- .post(`/api/global/email/send`)
25
- .send({
26
- email: "test@test.com",
27
- purpose: EmailTemplatePurpose.INVITATION,
28
- tenantId: TENANT_ID,
29
- })
30
- .set(config.defaultHeaders())
31
- .expect("Content-Type", /json/)
32
- .expect(200)
22
+
23
+ const res = await api.emails.sendEmail(EmailTemplatePurpose.INVITATION)
24
+
33
25
  expect(res.body.message).toBeDefined()
34
26
  expect(sendMailMock).toHaveBeenCalled()
35
27
  const emailCall = sendMailMock.mock.calls[0][0]
@@ -1,5 +1,5 @@
1
- const { config, request } = require("../../../tests")
2
- const { EmailTemplatePurpose } = require("../../../constants")
1
+ import { TestConfiguration, API } from "../../../../tests"
2
+ import { EmailTemplatePurpose } from "../../../../constants"
3
3
  const nodemailer = require("nodemailer")
4
4
  const fetch = require("node-fetch")
5
5
 
@@ -7,6 +7,8 @@ const fetch = require("node-fetch")
7
7
  jest.setTimeout(30000)
8
8
 
9
9
  describe("/api/global/email", () => {
10
+ const config = new TestConfiguration()
11
+ const api = new API(config)
10
12
 
11
13
  beforeAll(async () => {
12
14
  await config.beforeAll()
@@ -16,27 +18,24 @@ describe("/api/global/email", () => {
16
18
  await config.afterAll()
17
19
  })
18
20
 
19
- async function sendRealEmail(purpose) {
21
+ async function sendRealEmail(purpose: string) {
20
22
  let response, text
21
23
  try {
22
- const timeout = () => new Promise((resolve, reject) =>
23
- setTimeout(() => reject({
24
- status: 301,
25
- errno: "ETIME"
26
- }), 20000)
27
- )
24
+ const timeout = () =>
25
+ new Promise((resolve, reject) =>
26
+ setTimeout(
27
+ () =>
28
+ reject({
29
+ status: 301,
30
+ errno: "ETIME",
31
+ }),
32
+ 20000
33
+ )
34
+ )
28
35
  await Promise.race([config.saveEtherealSmtpConfig(), timeout()])
29
36
  await Promise.race([config.saveSettingsConfig(), timeout()])
30
- const user = await config.getUser("test@test.com")
31
- const res = await request
32
- .post(`/api/global/email/send`)
33
- .send({
34
- email: "test@test.com",
35
- purpose,
36
- userId: user._id,
37
- })
38
- .set(config.defaultHeaders())
39
- .timeout(20000)
37
+
38
+ const res = await api.emails.sendEmail(purpose).timeout(20000)
40
39
  // ethereal hiccup, can't test right now
41
40
  if (res.status >= 300) {
42
41
  return
@@ -47,7 +46,7 @@ describe("/api/global/email", () => {
47
46
  expect(testUrl).toBeDefined()
48
47
  response = await fetch(testUrl)
49
48
  text = await response.text()
50
- } catch (err) {
49
+ } catch (err: any) {
51
50
  // ethereal hiccup, can't test right now
52
51
  if (parseInt(err.status) >= 300 || (err && err.errno === "ETIME")) {
53
52
  return
@@ -81,4 +80,4 @@ describe("/api/global/email", () => {
81
80
  it("should be able to send a password recovery email", async () => {
82
81
  await sendRealEmail(EmailTemplatePurpose.PASSWORD_RECOVERY)
83
82
  })
84
- })
83
+ })
@@ -1,8 +1,10 @@
1
1
  jest.mock("nodemailer")
2
- const { config, request } = require("../../../tests")
3
- const { events } = require("@budibase/backend-core")
2
+ import { TestConfiguration, API } from "../../../../tests"
3
+ import { events } from "@budibase/backend-core"
4
4
 
5
5
  describe("/api/global/self", () => {
6
+ const config = new TestConfiguration()
7
+ const api = new API(config)
6
8
 
7
9
  beforeAll(async () => {
8
10
  await config.beforeAll()
@@ -16,23 +18,13 @@ describe("/api/global/self", () => {
16
18
  jest.clearAllMocks()
17
19
  })
18
20
 
19
- const updateSelf = async (user) => {
20
- const res = await request
21
- .post(`/api/global/self`)
22
- .send(user)
23
- .set(config.defaultHeaders())
24
- .expect("Content-Type", /json/)
25
- .expect(200)
26
- return res
27
- }
28
-
29
21
  describe("update", () => {
30
-
31
22
  it("should update self", async () => {
32
23
  const user = await config.createUser()
24
+ await config.createSession(user)
33
25
 
34
26
  delete user.password
35
- const res = await updateSelf(user)
27
+ const res = await api.self.updateSelf(user)
36
28
 
37
29
  expect(res.body._id).toBe(user._id)
38
30
  expect(events.user.updated).toBeCalledTimes(1)
@@ -42,10 +34,10 @@ describe("/api/global/self", () => {
42
34
 
43
35
  it("should update password", async () => {
44
36
  const user = await config.createUser()
45
- const password = "newPassword"
46
- user.password = password
37
+ await config.createSession(user)
47
38
 
48
- const res = await updateSelf(user)
39
+ user.password = "newPassword"
40
+ const res = await api.self.updateSelf(user)
49
41
 
50
42
  delete user.password
51
43
  expect(res.body._id).toBe(user._id)
@@ -55,4 +47,4 @@ describe("/api/global/self", () => {
55
47
  expect(events.user.passwordUpdated).toBeCalledWith(user)
56
48
  })
57
49
  })
58
- })
50
+ })
@@ -0,0 +1,464 @@
1
+ jest.mock("nodemailer")
2
+ import {
3
+ TestConfiguration,
4
+ mocks,
5
+ structures,
6
+ TENANT_1,
7
+ API,
8
+ } from "../../../../tests"
9
+ const sendMailMock = mocks.email.mock()
10
+ import { events, tenancy } from "@budibase/backend-core"
11
+
12
+ describe("/api/global/users", () => {
13
+ const config = new TestConfiguration()
14
+ const api = new API(config)
15
+
16
+ beforeAll(async () => {
17
+ await config.beforeAll()
18
+ })
19
+
20
+ afterAll(async () => {
21
+ await config.afterAll()
22
+ })
23
+
24
+ beforeEach(() => {
25
+ jest.clearAllMocks()
26
+ })
27
+
28
+ describe("invite", () => {
29
+ it("should be able to generate an invitation", async () => {
30
+ const { code, res } = await api.users.sendUserInvite(sendMailMock)
31
+
32
+ expect(res.body).toEqual({ message: "Invitation has been sent." })
33
+ expect(sendMailMock).toHaveBeenCalled()
34
+ expect(code).toBeDefined()
35
+ expect(events.user.invited).toBeCalledTimes(1)
36
+ })
37
+
38
+ it("should be able to create new user from invite", async () => {
39
+ const { code } = await api.users.sendUserInvite(sendMailMock)
40
+
41
+ const res = await api.users.acceptInvite(code)
42
+
43
+ expect(res.body._id).toBeDefined()
44
+ const user = await config.getUser("invite@test.com")
45
+ expect(user).toBeDefined()
46
+ expect(user._id).toEqual(res.body._id)
47
+ expect(events.user.inviteAccepted).toBeCalledTimes(1)
48
+ expect(events.user.inviteAccepted).toBeCalledWith(user)
49
+ })
50
+ })
51
+
52
+ describe("bulkCreate", () => {
53
+ it("should ignore users existing in the same tenant", async () => {
54
+ const user = await config.createUser()
55
+ jest.clearAllMocks()
56
+
57
+ const response = await api.users.bulkCreateUsers([user])
58
+
59
+ expect(response.successful.length).toBe(0)
60
+ expect(response.unsuccessful.length).toBe(1)
61
+ expect(response.unsuccessful[0].email).toBe(user.email)
62
+ expect(events.user.created).toBeCalledTimes(0)
63
+ })
64
+
65
+ it("should ignore users existing in other tenants", async () => {
66
+ const user = await config.createUser()
67
+ jest.resetAllMocks()
68
+
69
+ await tenancy.doInTenant(TENANT_1, async () => {
70
+ const response = await api.users.bulkCreateUsers([user])
71
+
72
+ expect(response.successful.length).toBe(0)
73
+ expect(response.unsuccessful.length).toBe(1)
74
+ expect(response.unsuccessful[0].email).toBe(user.email)
75
+ expect(events.user.created).toBeCalledTimes(0)
76
+ })
77
+ })
78
+
79
+ it("should ignore accounts using the same email", async () => {
80
+ const account = structures.accounts.account()
81
+ const resp = await api.accounts.saveMetadata(account)
82
+ const user = structures.users.user({ email: resp.email })
83
+ jest.clearAllMocks()
84
+
85
+ const response = await api.users.bulkCreateUsers([user])
86
+
87
+ expect(response.successful.length).toBe(0)
88
+ expect(response.unsuccessful.length).toBe(1)
89
+ expect(response.unsuccessful[0].email).toBe(user.email)
90
+ expect(events.user.created).toBeCalledTimes(0)
91
+ })
92
+
93
+ it("should be able to bulkCreate users", async () => {
94
+ const builder = structures.users.builderUser()
95
+ const admin = structures.users.adminUser()
96
+ const user = structures.users.user()
97
+
98
+ const response = await api.users.bulkCreateUsers([builder, admin, user])
99
+
100
+ expect(response.successful.length).toBe(3)
101
+ expect(response.successful[0].email).toBe(builder.email)
102
+ expect(response.successful[1].email).toBe(admin.email)
103
+ expect(response.successful[2].email).toBe(user.email)
104
+ expect(response.unsuccessful.length).toBe(0)
105
+ expect(events.user.created).toBeCalledTimes(3)
106
+ expect(events.user.permissionAdminAssigned).toBeCalledTimes(1)
107
+ expect(events.user.permissionBuilderAssigned).toBeCalledTimes(2)
108
+ })
109
+ })
110
+
111
+ describe("create", () => {
112
+ it("should be able to create a basic user", async () => {
113
+ const user = structures.users.user()
114
+
115
+ await api.users.saveUser(user)
116
+
117
+ expect(events.user.created).toBeCalledTimes(1)
118
+ expect(events.user.updated).not.toBeCalled()
119
+ expect(events.user.permissionBuilderAssigned).not.toBeCalled()
120
+ expect(events.user.permissionAdminAssigned).not.toBeCalled()
121
+ })
122
+
123
+ it("should be able to create an admin user", async () => {
124
+ const user = structures.users.adminUser()
125
+
126
+ await api.users.saveUser(user)
127
+
128
+ expect(events.user.created).toBeCalledTimes(1)
129
+ expect(events.user.updated).not.toBeCalled()
130
+ expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
131
+ expect(events.user.permissionAdminAssigned).toBeCalledTimes(1)
132
+ })
133
+
134
+ it("should be able to create a builder user", async () => {
135
+ const user = structures.users.builderUser()
136
+
137
+ await api.users.saveUser(user)
138
+
139
+ expect(events.user.created).toBeCalledTimes(1)
140
+ expect(events.user.updated).not.toBeCalled()
141
+ expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
142
+ expect(events.user.permissionAdminAssigned).not.toBeCalled()
143
+ })
144
+
145
+ it("should be able to assign app roles", async () => {
146
+ const user = structures.users.user()
147
+ user.roles = {
148
+ app_123: "role1",
149
+ app_456: "role2",
150
+ }
151
+
152
+ await api.users.saveUser(user)
153
+
154
+ const savedUser = await config.getUser(user.email)
155
+ expect(events.user.created).toBeCalledTimes(1)
156
+ expect(events.user.updated).not.toBeCalled()
157
+ expect(events.role.assigned).toBeCalledTimes(2)
158
+ expect(events.role.assigned).toBeCalledWith(savedUser, "role1")
159
+ expect(events.role.assigned).toBeCalledWith(savedUser, "role2")
160
+ })
161
+
162
+ it("should not be able to create user that exists in same tenant", async () => {
163
+ const user = await config.createUser()
164
+ jest.clearAllMocks()
165
+ delete user._id
166
+ delete user._rev
167
+
168
+ const response = await api.users.saveUser(user, 400)
169
+
170
+ expect(response.body.message).toBe(`Unavailable`)
171
+ expect(events.user.created).toBeCalledTimes(0)
172
+ })
173
+
174
+ it("should not be able to create user that exists in other tenant", async () => {
175
+ const user = await config.createUser()
176
+ jest.resetAllMocks()
177
+
178
+ await tenancy.doInTenant(TENANT_1, async () => {
179
+ delete user._id
180
+ const response = await api.users.saveUser(user, 400)
181
+
182
+ expect(response.body.message).toBe(`Unavailable`)
183
+ expect(events.user.created).toBeCalledTimes(0)
184
+ })
185
+ })
186
+
187
+ it("should not be able to create user with the same email as an account", async () => {
188
+ const user = structures.users.user()
189
+ const account = structures.accounts.cloudAccount()
190
+ mocks.accounts.getAccount.mockReturnValueOnce(account)
191
+
192
+ const response = await api.users.saveUser(user, 400)
193
+
194
+ expect(response.body.message).toBe(`Unavailable`)
195
+ expect(events.user.created).toBeCalledTimes(0)
196
+ })
197
+ })
198
+
199
+ describe("update", () => {
200
+ it("should be able to update a basic user", async () => {
201
+ const user = await config.createUser()
202
+ jest.clearAllMocks()
203
+
204
+ await api.users.saveUser(user)
205
+
206
+ expect(events.user.created).not.toBeCalled()
207
+ expect(events.user.updated).toBeCalledTimes(1)
208
+ expect(events.user.permissionBuilderAssigned).not.toBeCalled()
209
+ expect(events.user.permissionAdminAssigned).not.toBeCalled()
210
+ expect(events.user.passwordForceReset).not.toBeCalled()
211
+ })
212
+
213
+ it("should be able to force reset password", async () => {
214
+ const user = await config.createUser()
215
+ jest.clearAllMocks()
216
+
217
+ user.forceResetPassword = true
218
+ user.password = "tempPassword"
219
+ await api.users.saveUser(user)
220
+
221
+ expect(events.user.created).not.toBeCalled()
222
+ expect(events.user.updated).toBeCalledTimes(1)
223
+ expect(events.user.permissionBuilderAssigned).not.toBeCalled()
224
+ expect(events.user.permissionAdminAssigned).not.toBeCalled()
225
+ expect(events.user.passwordForceReset).toBeCalledTimes(1)
226
+ })
227
+
228
+ it("should be able to update a basic user to an admin user", async () => {
229
+ const user = await config.createUser()
230
+ jest.clearAllMocks()
231
+
232
+ await api.users.saveUser(structures.users.adminUser(user))
233
+
234
+ expect(events.user.created).not.toBeCalled()
235
+ expect(events.user.updated).toBeCalledTimes(1)
236
+ expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
237
+ expect(events.user.permissionAdminAssigned).toBeCalledTimes(1)
238
+ })
239
+
240
+ it("should be able to update a basic user to a builder user", async () => {
241
+ const user = await config.createUser()
242
+ jest.clearAllMocks()
243
+
244
+ await api.users.saveUser(structures.users.builderUser(user))
245
+
246
+ expect(events.user.created).not.toBeCalled()
247
+ expect(events.user.updated).toBeCalledTimes(1)
248
+ expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
249
+ expect(events.user.permissionAdminAssigned).not.toBeCalled()
250
+ })
251
+
252
+ it("should be able to update an admin user to a basic user", async () => {
253
+ const user = await config.createUser(structures.users.adminUser())
254
+ jest.clearAllMocks()
255
+ user.admin!.global = false
256
+ user.builder!.global = false
257
+
258
+ await api.users.saveUser(user)
259
+
260
+ expect(events.user.created).not.toBeCalled()
261
+ expect(events.user.updated).toBeCalledTimes(1)
262
+ expect(events.user.permissionAdminRemoved).toBeCalledTimes(1)
263
+ expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
264
+ })
265
+
266
+ it("should be able to update an builder user to a basic user", async () => {
267
+ const user = await config.createUser(structures.users.builderUser())
268
+ jest.clearAllMocks()
269
+ user.builder!.global = false
270
+
271
+ await api.users.saveUser(user)
272
+
273
+ expect(events.user.created).not.toBeCalled()
274
+ expect(events.user.updated).toBeCalledTimes(1)
275
+ expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
276
+ expect(events.user.permissionAdminRemoved).not.toBeCalled()
277
+ })
278
+
279
+ it("should be able to assign app roles", async () => {
280
+ const user = await config.createUser()
281
+ jest.clearAllMocks()
282
+ user.roles = {
283
+ app_123: "role1",
284
+ app_456: "role2",
285
+ }
286
+
287
+ await api.users.saveUser(user)
288
+
289
+ const savedUser = await config.getUser(user.email)
290
+ expect(events.user.created).not.toBeCalled()
291
+ expect(events.user.updated).toBeCalledTimes(1)
292
+ expect(events.role.assigned).toBeCalledTimes(2)
293
+ expect(events.role.assigned).toBeCalledWith(savedUser, "role1")
294
+ expect(events.role.assigned).toBeCalledWith(savedUser, "role2")
295
+ })
296
+
297
+ it("should be able to unassign app roles", async () => {
298
+ let user = structures.users.user()
299
+ user.roles = {
300
+ app_123: "role1",
301
+ app_456: "role2",
302
+ }
303
+ user = await config.createUser(user)
304
+ jest.clearAllMocks()
305
+ user.roles = {}
306
+
307
+ await api.users.saveUser(user)
308
+
309
+ const savedUser = await config.getUser(user.email)
310
+ expect(events.user.created).not.toBeCalled()
311
+ expect(events.user.updated).toBeCalledTimes(1)
312
+ expect(events.role.unassigned).toBeCalledTimes(2)
313
+ expect(events.role.unassigned).toBeCalledWith(savedUser, "role1")
314
+ expect(events.role.unassigned).toBeCalledWith(savedUser, "role2")
315
+ })
316
+
317
+ it("should be able to update existing app roles", async () => {
318
+ let user = structures.users.user()
319
+ user.roles = {
320
+ app_123: "role1",
321
+ app_456: "role2",
322
+ }
323
+ user = await config.createUser(user)
324
+ jest.clearAllMocks()
325
+ user.roles = {
326
+ app_123: "role1",
327
+ app_456: "role2-edit",
328
+ }
329
+
330
+ await api.users.saveUser(user)
331
+
332
+ const savedUser = await config.getUser(user.email)
333
+ expect(events.user.created).not.toBeCalled()
334
+ expect(events.user.updated).toBeCalledTimes(1)
335
+ expect(events.role.unassigned).toBeCalledTimes(1)
336
+ expect(events.role.unassigned).toBeCalledWith(savedUser, "role2")
337
+ expect(events.role.assigned).toBeCalledTimes(1)
338
+ expect(events.role.assigned).toBeCalledWith(savedUser, "role2-edit")
339
+ })
340
+
341
+ it("should not be able to update email address", async () => {
342
+ const email = "email@test.com"
343
+ const user = await config.createUser(structures.users.user({ email }))
344
+ user.email = "new@test.com"
345
+
346
+ const response = await api.users.saveUser(user, 400)
347
+
348
+ const dbUser = await config.getUser(email)
349
+ user.email = email
350
+ expect(user).toStrictEqual(dbUser)
351
+ expect(response.body.message).toBe("Email address cannot be changed")
352
+ })
353
+ })
354
+
355
+ describe("bulkDelete", () => {
356
+ it("should not be able to bulkDelete current user", async () => {
357
+ const user = await config.defaultUser!
358
+ const request = { userIds: [user._id!] }
359
+
360
+ const response = await api.users.bulkDeleteUsers(request, 400)
361
+
362
+ expect(response.body.message).toBe("Unable to delete self.")
363
+ expect(events.user.deleted).not.toBeCalled()
364
+ })
365
+
366
+ it("should not be able to bulkDelete account owner", async () => {
367
+ const user = await config.createUser()
368
+ const account = structures.accounts.cloudAccount()
369
+ account.budibaseUserId = user._id!
370
+ mocks.accounts.getAccountByTenantId.mockReturnValue(account)
371
+
372
+ const request = { userIds: [user._id!] }
373
+
374
+ const response = await api.users.bulkDeleteUsers(request)
375
+
376
+ expect(response.body.successful.length).toBe(0)
377
+ expect(response.body.unsuccessful.length).toBe(1)
378
+ expect(response.body.unsuccessful[0].reason).toBe(
379
+ "Account holder cannot be deleted"
380
+ )
381
+ expect(response.body.unsuccessful[0]._id).toBe(user._id)
382
+ expect(events.user.deleted).not.toBeCalled()
383
+ })
384
+
385
+ it("should be able to bulk delete users", async () => {
386
+ const account = structures.accounts.cloudAccount()
387
+ mocks.accounts.getAccountByTenantId.mockReturnValue(account)
388
+
389
+ const builder = structures.users.builderUser()
390
+ const admin = structures.users.adminUser()
391
+ const user = structures.users.user()
392
+ const createdUsers = await api.users.bulkCreateUsers([
393
+ builder,
394
+ admin,
395
+ user,
396
+ ])
397
+ const request = { userIds: createdUsers.successful.map(u => u._id!) }
398
+
399
+ const response = await api.users.bulkDeleteUsers(request)
400
+
401
+ expect(response.body.successful.length).toBe(3)
402
+ expect(response.body.unsuccessful.length).toBe(0)
403
+ expect(events.user.deleted).toBeCalledTimes(3)
404
+ expect(events.user.permissionAdminRemoved).toBeCalledTimes(1)
405
+ expect(events.user.permissionBuilderRemoved).toBeCalledTimes(2)
406
+ })
407
+ })
408
+
409
+ describe("destroy", () => {
410
+ it("should be able to destroy a basic user", async () => {
411
+ const user = await config.createUser()
412
+ jest.clearAllMocks()
413
+
414
+ await api.users.deleteUser(user._id!)
415
+
416
+ expect(events.user.deleted).toBeCalledTimes(1)
417
+ expect(events.user.permissionBuilderRemoved).not.toBeCalled()
418
+ expect(events.user.permissionAdminRemoved).not.toBeCalled()
419
+ })
420
+
421
+ it("should be able to destroy an admin user", async () => {
422
+ const user = await config.createUser(structures.users.adminUser())
423
+ jest.clearAllMocks()
424
+
425
+ await api.users.deleteUser(user._id!)
426
+
427
+ expect(events.user.deleted).toBeCalledTimes(1)
428
+ expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
429
+ expect(events.user.permissionAdminRemoved).toBeCalledTimes(1)
430
+ })
431
+
432
+ it("should be able to destroy a builder user", async () => {
433
+ const user = await config.createUser(structures.users.builderUser())
434
+ jest.clearAllMocks()
435
+
436
+ await api.users.deleteUser(user._id!)
437
+
438
+ expect(events.user.deleted).toBeCalledTimes(1)
439
+ expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
440
+ expect(events.user.permissionAdminRemoved).not.toBeCalled()
441
+ })
442
+
443
+ it("should not be able to destroy account owner", async () => {
444
+ const user = await config.createUser()
445
+ const account = structures.accounts.cloudAccount()
446
+ mocks.accounts.getAccount.mockReturnValueOnce(account)
447
+
448
+ const response = await api.users.deleteUser(user._id!, 400)
449
+
450
+ expect(response.body.message).toBe("Account holder cannot be deleted")
451
+ })
452
+
453
+ it("should not be able to destroy account owner as account owner", async () => {
454
+ const user = await config.defaultUser!
455
+ const account = structures.accounts.cloudAccount()
456
+ account.email = user.email
457
+ mocks.accounts.getAccount.mockReturnValueOnce(account)
458
+
459
+ const response = await api.users.deleteUser(user._id!, 400)
460
+
461
+ expect(response.body.message).toBe("Unable to delete self.")
462
+ })
463
+ })
464
+ })
@@ -12,6 +12,7 @@ const statusRoutes = require("./system/status")
12
12
  const selfRoutes = require("./global/self")
13
13
  const licenseRoutes = require("./global/license")
14
14
  const migrationRoutes = require("./system/migrations")
15
+ const accountRoutes = require("./system/accounts")
15
16
 
16
17
  let userGroupRoutes = api.groups
17
18
  exports.routes = [
@@ -29,4 +30,5 @@ exports.routes = [
29
30
  licenseRoutes,
30
31
  userGroupRoutes,
31
32
  migrationRoutes,
33
+ accountRoutes,
32
34
  ]
@@ -0,0 +1,19 @@
1
+ import Router from "@koa/router"
2
+ import * as controller from "../../controllers/system/accounts"
3
+ import { middleware } from "@budibase/backend-core"
4
+
5
+ const router = new Router()
6
+
7
+ router
8
+ .put(
9
+ "/api/system/accounts/:accountId/metadata",
10
+ middleware.internalApi,
11
+ controller.save
12
+ )
13
+ .delete(
14
+ "/api/system/accounts/:accountId/metadata",
15
+ middleware.internalApi,
16
+ controller.destroy
17
+ )
18
+
19
+ export = router