@budibase/worker 1.0.199 → 1.0.200-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.
- package/Dockerfile +3 -0
- package/nodemon.json +1 -1
- package/package.json +56 -46
- package/scripts/dev/manage.js +2 -0
- package/scripts/jestSetup.js +9 -0
- package/scripts/load/users.js +4 -4
- package/src/api/controllers/global/auth.ts +21 -14
- package/src/api/controllers/global/configs.js +126 -2
- package/src/api/controllers/global/roles.js +3 -3
- package/src/api/controllers/global/self.js +12 -3
- package/src/api/controllers/global/users.ts +48 -88
- package/src/api/routes/global/self.js +2 -2
- package/src/api/routes/global/users.js +3 -3
- package/src/api/routes/tests/auth.spec.js +38 -16
- package/src/api/routes/tests/configs.spec.js +223 -7
- package/src/api/routes/tests/email.spec.js +8 -7
- package/src/api/routes/tests/realEmail.spec.js +5 -5
- package/src/api/routes/tests/self.spec.js +58 -0
- package/src/api/routes/tests/users.spec.js +299 -13
- package/src/api/routes/validation/index.ts +1 -0
- package/src/api/{utilities/validation.js → routes/validation/users.ts} +4 -4
- package/src/index.ts +2 -0
- package/src/sdk/index.ts +1 -0
- package/src/sdk/users/events.ts +161 -0
- package/src/sdk/users/index.ts +1 -0
- package/src/sdk/users/users.ts +201 -0
- package/src/{api/routes/tests/utilities → tests}/TestConfiguration.js +68 -111
- package/src/tests/controllers.js +7 -0
- package/src/tests/index.js +12 -0
- package/src/tests/mocks/email.js +10 -0
- package/src/tests/mocks/index.js +5 -0
- package/src/tests/structures/configs.js +76 -0
- package/src/tests/structures/index.js +12 -0
- package/src/tests/structures/users.ts +28 -0
- package/tsconfig.build.json +25 -0
- package/tsconfig.json +21 -15
- package/src/api/routes/tests/utilities/controllers.js +0 -7
- package/src/api/routes/tests/utilities/index.js +0 -41
- package/src/api/routes/tests/utilities/structures.js +0 -2
- package/src/api/utilities/index.js +0 -33
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
jest.mock("nodemailer")
|
|
2
|
+
const { config, request } = require("../../../tests")
|
|
3
|
+
const { events } = require("@budibase/backend-core")
|
|
4
|
+
|
|
5
|
+
describe("/api/global/self", () => {
|
|
6
|
+
|
|
7
|
+
beforeAll(async () => {
|
|
8
|
+
await config.beforeAll()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
afterAll(async () => {
|
|
12
|
+
await config.afterAll()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.clearAllMocks()
|
|
17
|
+
})
|
|
18
|
+
|
|
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
|
+
describe("update", () => {
|
|
30
|
+
|
|
31
|
+
it("should update self", async () => {
|
|
32
|
+
const user = await config.createUser()
|
|
33
|
+
|
|
34
|
+
delete user.password
|
|
35
|
+
const res = await updateSelf(user)
|
|
36
|
+
|
|
37
|
+
expect(res.body._id).toBe(user._id)
|
|
38
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
39
|
+
expect(events.user.updated).toBeCalledWith(user)
|
|
40
|
+
expect(events.user.passwordUpdated).not.toBeCalled()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it("should update password", async () => {
|
|
44
|
+
const user = await config.createUser()
|
|
45
|
+
const password = "newPassword"
|
|
46
|
+
user.password = password
|
|
47
|
+
|
|
48
|
+
const res = await updateSelf(user)
|
|
49
|
+
|
|
50
|
+
delete user.password
|
|
51
|
+
expect(res.body._id).toBe(user._id)
|
|
52
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
53
|
+
expect(events.user.updated).toBeCalledWith(user)
|
|
54
|
+
expect(events.user.passwordUpdated).toBeCalledTimes(1)
|
|
55
|
+
expect(events.user.passwordUpdated).toBeCalledWith(user)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
jest.mock("nodemailer")
|
|
2
|
-
const
|
|
3
|
-
const sendMailMock =
|
|
2
|
+
const { config, request, mocks, structures } = require("../../../tests")
|
|
3
|
+
const sendMailMock = mocks.email.mock()
|
|
4
|
+
const { events } = require("@budibase/backend-core")
|
|
4
5
|
|
|
5
6
|
describe("/api/global/users", () => {
|
|
6
|
-
let request = setup.getRequest()
|
|
7
|
-
let config = setup.getConfig()
|
|
8
|
-
let code
|
|
9
7
|
|
|
10
8
|
beforeAll(async () => {
|
|
11
|
-
await config.
|
|
9
|
+
await config.beforeAll()
|
|
12
10
|
})
|
|
13
11
|
|
|
14
|
-
afterAll(
|
|
12
|
+
afterAll(async () => {
|
|
13
|
+
await config.afterAll()
|
|
14
|
+
})
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
// initially configure settings
|
|
16
|
+
const sendUserInvite = async () => {
|
|
18
17
|
await config.saveSmtpConfig()
|
|
19
18
|
await config.saveSettingsConfig()
|
|
20
19
|
const res = await request
|
|
@@ -25,16 +24,26 @@ describe("/api/global/users", () => {
|
|
|
25
24
|
.set(config.defaultHeaders())
|
|
26
25
|
.expect("Content-Type", /json/)
|
|
27
26
|
.expect(200)
|
|
27
|
+
|
|
28
|
+
const emailCall = sendMailMock.mock.calls[0][0]
|
|
29
|
+
// after this URL there should be a code
|
|
30
|
+
const parts = emailCall.html.split("http://localhost:10000/builder/invite?code=")
|
|
31
|
+
const code = parts[1].split("\"")[0].split("&")[0]
|
|
32
|
+
return { code, res }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
it("should be able to generate an invitation", async () => {
|
|
36
|
+
const { code, res } = await sendUserInvite()
|
|
37
|
+
|
|
28
38
|
expect(res.body).toEqual({ message: "Invitation has been sent." })
|
|
29
39
|
expect(sendMailMock).toHaveBeenCalled()
|
|
30
|
-
const emailCall = sendMailMock.mock.calls[0][0]
|
|
31
|
-
// after this URL there should be a code
|
|
32
|
-
const parts = emailCall.html.split("http://localhost:10000/builder/invite?code=")
|
|
33
|
-
code = parts[1].split("\"")[0].split("&")[0]
|
|
34
40
|
expect(code).toBeDefined()
|
|
41
|
+
expect(events.user.invited).toBeCalledTimes(1)
|
|
35
42
|
})
|
|
36
43
|
|
|
37
44
|
it("should be able to create new user from invite", async () => {
|
|
45
|
+
const { code } = await sendUserInvite()
|
|
46
|
+
|
|
38
47
|
const res = await request
|
|
39
48
|
.post(`/api/global/users/invite/accept`)
|
|
40
49
|
.send({
|
|
@@ -47,5 +56,282 @@ describe("/api/global/users", () => {
|
|
|
47
56
|
const user = await config.getUser("invite@test.com")
|
|
48
57
|
expect(user).toBeDefined()
|
|
49
58
|
expect(user._id).toEqual(res.body._id)
|
|
59
|
+
expect(events.user.inviteAccepted).toBeCalledTimes(1)
|
|
60
|
+
expect(events.user.inviteAccepted).toBeCalledWith(user)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const createUser = async (user) => {
|
|
64
|
+
const existing = await config.getUser(user.email)
|
|
65
|
+
if (existing) {
|
|
66
|
+
await deleteUser(existing._id)
|
|
67
|
+
}
|
|
68
|
+
return saveUser(user)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const updateUser = async (user) => {
|
|
72
|
+
const existing = await config.getUser(user.email)
|
|
73
|
+
user._id = existing._id
|
|
74
|
+
return saveUser(user)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const saveUser = async (user) => {
|
|
78
|
+
const res = await request
|
|
79
|
+
.post(`/api/global/users`)
|
|
80
|
+
.send(user)
|
|
81
|
+
.set(config.defaultHeaders())
|
|
82
|
+
.expect("Content-Type", /json/)
|
|
83
|
+
.expect(200)
|
|
84
|
+
return res.body
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const deleteUser = async (email) => {
|
|
88
|
+
const user = await config.getUser(email)
|
|
89
|
+
if (user) {
|
|
90
|
+
await request
|
|
91
|
+
.delete(`/api/global/users/${user._id}`)
|
|
92
|
+
.set(config.defaultHeaders())
|
|
93
|
+
.expect("Content-Type", /json/)
|
|
94
|
+
.expect(200)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
describe("create", () => {
|
|
99
|
+
it("should be able to create a basic user", async () => {
|
|
100
|
+
jest.clearAllMocks()
|
|
101
|
+
const user = structures.users.user({ email: "basic@test.com" })
|
|
102
|
+
await createUser(user)
|
|
103
|
+
|
|
104
|
+
expect(events.user.created).toBeCalledTimes(1)
|
|
105
|
+
expect(events.user.updated).not.toBeCalled()
|
|
106
|
+
expect(events.user.permissionBuilderAssigned).not.toBeCalled()
|
|
107
|
+
expect(events.user.permissionAdminAssigned).not.toBeCalled()
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it("should be able to create an admin user", async () => {
|
|
111
|
+
jest.clearAllMocks()
|
|
112
|
+
const user = structures.users.adminUser({ email: "admin@test.com" })
|
|
113
|
+
await createUser(user)
|
|
114
|
+
|
|
115
|
+
expect(events.user.created).toBeCalledTimes(1)
|
|
116
|
+
expect(events.user.updated).not.toBeCalled()
|
|
117
|
+
expect(events.user.permissionBuilderAssigned).not.toBeCalled()
|
|
118
|
+
expect(events.user.permissionAdminAssigned).toBeCalledTimes(1)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("should be able to create a builder user", async () => {
|
|
122
|
+
jest.clearAllMocks()
|
|
123
|
+
const user = structures.users.builderUser({ email: "builder@test.com" })
|
|
124
|
+
await createUser(user)
|
|
125
|
+
|
|
126
|
+
expect(events.user.created).toBeCalledTimes(1)
|
|
127
|
+
expect(events.user.updated).not.toBeCalled()
|
|
128
|
+
expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
|
|
129
|
+
expect(events.user.permissionAdminAssigned).not.toBeCalled()
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it("should be able to assign app roles", async () => {
|
|
133
|
+
jest.clearAllMocks()
|
|
134
|
+
const user = structures.users.user({ email: "assign-roles@test.com" })
|
|
135
|
+
user.roles = {
|
|
136
|
+
"app_123": "role1",
|
|
137
|
+
"app_456": "role2",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
await createUser(user)
|
|
141
|
+
const savedUser = await config.getUser(user.email)
|
|
142
|
+
|
|
143
|
+
expect(events.user.created).toBeCalledTimes(1)
|
|
144
|
+
expect(events.user.updated).not.toBeCalled()
|
|
145
|
+
expect(events.role.assigned).toBeCalledTimes(2)
|
|
146
|
+
expect(events.role.assigned).toBeCalledWith(savedUser, "role1")
|
|
147
|
+
expect(events.role.assigned).toBeCalledWith(savedUser, "role2")
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
describe("update", () => {
|
|
152
|
+
it("should be able to update a basic user", async () => {
|
|
153
|
+
let user = structures.users.user({ email: "basic-update@test.com" })
|
|
154
|
+
await createUser(user)
|
|
155
|
+
jest.clearAllMocks()
|
|
156
|
+
|
|
157
|
+
await updateUser(user)
|
|
158
|
+
|
|
159
|
+
expect(events.user.created).not.toBeCalled()
|
|
160
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
161
|
+
expect(events.user.permissionBuilderAssigned).not.toBeCalled()
|
|
162
|
+
expect(events.user.permissionAdminAssigned).not.toBeCalled()
|
|
163
|
+
expect(events.user.passwordForceReset).not.toBeCalled()
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it("should be able to force reset password", async () => {
|
|
167
|
+
let user = structures.users.user({ email: "basic-password-update@test.com" })
|
|
168
|
+
await createUser(user)
|
|
169
|
+
jest.clearAllMocks()
|
|
170
|
+
|
|
171
|
+
user.forceResetPassword = true
|
|
172
|
+
user.password = "tempPassword"
|
|
173
|
+
await updateUser(user)
|
|
174
|
+
|
|
175
|
+
expect(events.user.created).not.toBeCalled()
|
|
176
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
177
|
+
expect(events.user.permissionBuilderAssigned).not.toBeCalled()
|
|
178
|
+
expect(events.user.permissionAdminAssigned).not.toBeCalled()
|
|
179
|
+
expect(events.user.passwordForceReset).toBeCalledTimes(1)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it("should be able to update a basic user to an admin user", async () => {
|
|
183
|
+
let user = structures.users.user({ email: "basic-update-admin@test.com" })
|
|
184
|
+
await createUser(user)
|
|
185
|
+
jest.clearAllMocks()
|
|
186
|
+
|
|
187
|
+
await updateUser(structures.users.adminUser(user))
|
|
188
|
+
|
|
189
|
+
expect(events.user.created).not.toBeCalled()
|
|
190
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
191
|
+
expect(events.user.permissionBuilderAssigned).not.toBeCalled()
|
|
192
|
+
expect(events.user.permissionAdminAssigned).toBeCalledTimes(1)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it("should be able to update a basic user to a builder user", async () => {
|
|
196
|
+
let user = structures.users.user({ email: "basic-update-builder@test.com" })
|
|
197
|
+
await createUser(user)
|
|
198
|
+
jest.clearAllMocks()
|
|
199
|
+
|
|
200
|
+
await updateUser(structures.users.builderUser(user))
|
|
201
|
+
|
|
202
|
+
expect(events.user.created).not.toBeCalled()
|
|
203
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
204
|
+
expect(events.user.permissionBuilderAssigned).toBeCalledTimes(1)
|
|
205
|
+
expect(events.user.permissionAdminAssigned).not.toBeCalled()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it("should be able to update an admin user to a basic user", async () => {
|
|
209
|
+
let user = structures.users.adminUser({ email: "admin-update-basic@test.com" })
|
|
210
|
+
await createUser(user)
|
|
211
|
+
jest.clearAllMocks()
|
|
212
|
+
|
|
213
|
+
user.admin.global = false
|
|
214
|
+
await updateUser(user)
|
|
215
|
+
|
|
216
|
+
expect(events.user.created).not.toBeCalled()
|
|
217
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
218
|
+
expect(events.user.permissionAdminRemoved).toBeCalledTimes(1)
|
|
219
|
+
expect(events.user.permissionBuilderRemoved).not.toBeCalled()
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it("should be able to update an builder user to a basic user", async () => {
|
|
223
|
+
let user = structures.users.builderUser({ email: "builder-update-basic@test.com" })
|
|
224
|
+
await createUser(user)
|
|
225
|
+
jest.clearAllMocks()
|
|
226
|
+
|
|
227
|
+
user.builder.global = false
|
|
228
|
+
await updateUser(user)
|
|
229
|
+
|
|
230
|
+
expect(events.user.created).not.toBeCalled()
|
|
231
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
232
|
+
expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
|
|
233
|
+
expect(events.user.permissionAdminRemoved).not.toBeCalled()
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it("should be able to assign app roles", async () => {
|
|
237
|
+
const user = structures.users.user({ email: "assign-roles-update@test.com" })
|
|
238
|
+
await createUser(user)
|
|
239
|
+
jest.clearAllMocks()
|
|
240
|
+
|
|
241
|
+
user.roles = {
|
|
242
|
+
"app_123": "role1",
|
|
243
|
+
"app_456": "role2",
|
|
244
|
+
}
|
|
245
|
+
await updateUser(user)
|
|
246
|
+
const savedUser = await config.getUser(user.email)
|
|
247
|
+
|
|
248
|
+
expect(events.user.created).not.toBeCalled()
|
|
249
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
250
|
+
expect(events.role.assigned).toBeCalledTimes(2)
|
|
251
|
+
expect(events.role.assigned).toBeCalledWith(savedUser, "role1")
|
|
252
|
+
expect(events.role.assigned).toBeCalledWith(savedUser, "role2")
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it("should be able to unassign app roles", async () => {
|
|
256
|
+
const user = structures.users.user({ email: "unassign-roles@test.com" })
|
|
257
|
+
user.roles = {
|
|
258
|
+
"app_123": "role1",
|
|
259
|
+
"app_456": "role2",
|
|
260
|
+
}
|
|
261
|
+
await createUser(user)
|
|
262
|
+
jest.clearAllMocks()
|
|
263
|
+
|
|
264
|
+
user.roles = {}
|
|
265
|
+
await updateUser(user)
|
|
266
|
+
const savedUser = await config.getUser(user.email)
|
|
267
|
+
|
|
268
|
+
expect(events.user.created).not.toBeCalled()
|
|
269
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
270
|
+
expect(events.role.unassigned).toBeCalledTimes(2)
|
|
271
|
+
expect(events.role.unassigned).toBeCalledWith(savedUser, "role1")
|
|
272
|
+
expect(events.role.unassigned).toBeCalledWith(savedUser, "role2")
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it("should be able to update existing app roles", async () => {
|
|
276
|
+
const user = structures.users.user({ email: "update-roles@test.com" })
|
|
277
|
+
user.roles = {
|
|
278
|
+
"app_123": "role1",
|
|
279
|
+
"app_456": "role2",
|
|
280
|
+
}
|
|
281
|
+
await createUser(user)
|
|
282
|
+
jest.clearAllMocks()
|
|
283
|
+
|
|
284
|
+
user.roles = {
|
|
285
|
+
"app_123": "role1",
|
|
286
|
+
"app_456": "role2-edit",
|
|
287
|
+
}
|
|
288
|
+
await updateUser(user)
|
|
289
|
+
const savedUser = await config.getUser(user.email)
|
|
290
|
+
|
|
291
|
+
expect(events.user.created).not.toBeCalled()
|
|
292
|
+
expect(events.user.updated).toBeCalledTimes(1)
|
|
293
|
+
expect(events.role.unassigned).toBeCalledTimes(1)
|
|
294
|
+
expect(events.role.unassigned).toBeCalledWith(savedUser, "role2")
|
|
295
|
+
expect(events.role.assigned).toBeCalledTimes(1)
|
|
296
|
+
expect(events.role.assigned).toBeCalledWith(savedUser, "role2-edit")
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
describe("destroy", () => {
|
|
301
|
+
it("should be able to destroy a basic user", async () => {
|
|
302
|
+
let user = structures.users.user({ email: "destroy@test.com" })
|
|
303
|
+
await createUser(user)
|
|
304
|
+
jest.clearAllMocks()
|
|
305
|
+
|
|
306
|
+
await deleteUser(user.email)
|
|
307
|
+
|
|
308
|
+
expect(events.user.deleted).toBeCalledTimes(1)
|
|
309
|
+
expect(events.user.permissionBuilderRemoved).not.toBeCalled()
|
|
310
|
+
expect(events.user.permissionAdminRemoved).not.toBeCalled()
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
it("should be able to destroy an admin user", async () => {
|
|
314
|
+
let user = structures.users.adminUser({ email: "destroy-admin@test.com" })
|
|
315
|
+
await createUser(user)
|
|
316
|
+
jest.clearAllMocks()
|
|
317
|
+
|
|
318
|
+
await deleteUser(user.email)
|
|
319
|
+
|
|
320
|
+
expect(events.user.deleted).toBeCalledTimes(1)
|
|
321
|
+
expect(events.user.permissionBuilderRemoved).not.toBeCalled()
|
|
322
|
+
expect(events.user.permissionAdminRemoved).toBeCalledTimes(1)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it("should be able to destroy a builder user", async () => {
|
|
326
|
+
let user = structures.users.builderUser({ email: "destroy-admin@test.com" })
|
|
327
|
+
await createUser(user)
|
|
328
|
+
jest.clearAllMocks()
|
|
329
|
+
|
|
330
|
+
await deleteUser(user.email)
|
|
331
|
+
|
|
332
|
+
expect(events.user.deleted).toBeCalledTimes(1)
|
|
333
|
+
expect(events.user.permissionBuilderRemoved).toBeCalledTimes(1)
|
|
334
|
+
expect(events.user.permissionAdminRemoved).not.toBeCalled()
|
|
335
|
+
})
|
|
50
336
|
})
|
|
51
337
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as users from "./users"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import joiValidator from "../../../middleware/joi-validator"
|
|
2
|
+
import Joi from "joi"
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
let schema = {
|
|
4
|
+
export const buildUserSaveValidation = (isSelf = false) => {
|
|
5
|
+
let schema: any = {
|
|
6
6
|
email: Joi.string().allow(null, ""),
|
|
7
7
|
password: Joi.string().allow(null, ""),
|
|
8
8
|
forceResetPassword: Joi.boolean().optional(),
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ const http = require("http")
|
|
|
18
18
|
const api = require("./api")
|
|
19
19
|
const redis = require("./utilities/redis")
|
|
20
20
|
const Sentry = require("@sentry/node")
|
|
21
|
+
import { events } from "@budibase/backend-core"
|
|
21
22
|
|
|
22
23
|
// this will setup http and https proxies form env variables
|
|
23
24
|
bootstrap()
|
|
@@ -73,6 +74,7 @@ server.on("close", async () => {
|
|
|
73
74
|
console.log("Server Closed")
|
|
74
75
|
}
|
|
75
76
|
await redis.shutdown()
|
|
77
|
+
await events.shutdown()
|
|
76
78
|
if (!env.isTest()) {
|
|
77
79
|
process.exit(errCode)
|
|
78
80
|
}
|
package/src/sdk/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * as users from "./users"
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import env from "../../environment"
|
|
2
|
+
import { events, accounts, tenancy } from "@budibase/backend-core"
|
|
3
|
+
import { User, UserRoles, CloudAccount } from "@budibase/types"
|
|
4
|
+
|
|
5
|
+
export const handleDeleteEvents = async (user: any) => {
|
|
6
|
+
await events.user.deleted(user)
|
|
7
|
+
|
|
8
|
+
if (isBuilder(user)) {
|
|
9
|
+
await events.user.permissionBuilderRemoved(user)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (isAdmin(user)) {
|
|
13
|
+
await events.user.permissionAdminRemoved(user)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const assignAppRoleEvents = async (
|
|
18
|
+
user: User,
|
|
19
|
+
roles: UserRoles,
|
|
20
|
+
existingRoles: UserRoles
|
|
21
|
+
) => {
|
|
22
|
+
for (const [appId, role] of Object.entries(roles)) {
|
|
23
|
+
// app role in existing is not same as new
|
|
24
|
+
if (!existingRoles || existingRoles[appId] !== role) {
|
|
25
|
+
await events.role.assigned(user, role)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const unassignAppRoleEvents = async (
|
|
31
|
+
user: User,
|
|
32
|
+
roles: UserRoles,
|
|
33
|
+
existingRoles: UserRoles
|
|
34
|
+
) => {
|
|
35
|
+
if (!existingRoles) {
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
for (const [appId, role] of Object.entries(existingRoles)) {
|
|
39
|
+
// app role in new is not same as existing
|
|
40
|
+
if (!roles || roles[appId] !== role) {
|
|
41
|
+
await events.role.unassigned(user, role)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleAppRoleEvents = async (user: any, existingUser: any) => {
|
|
47
|
+
const roles = user.roles
|
|
48
|
+
const existingRoles = existingUser?.roles
|
|
49
|
+
|
|
50
|
+
await assignAppRoleEvents(user, roles, existingRoles)
|
|
51
|
+
await unassignAppRoleEvents(user, roles, existingRoles)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const handleSaveEvents = async (user: any, existingUser: any) => {
|
|
55
|
+
const tenantId = tenancy.getTenantId()
|
|
56
|
+
let tenantAccount: CloudAccount | undefined
|
|
57
|
+
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
58
|
+
tenantAccount = await accounts.getAccountByTenantId(tenantId)
|
|
59
|
+
}
|
|
60
|
+
await events.identification.identifyUser(user, tenantAccount)
|
|
61
|
+
|
|
62
|
+
if (existingUser) {
|
|
63
|
+
await events.user.updated(user)
|
|
64
|
+
|
|
65
|
+
if (isRemovingBuilder(user, existingUser)) {
|
|
66
|
+
await events.user.permissionBuilderRemoved(user)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isRemovingAdmin(user, existingUser)) {
|
|
70
|
+
await events.user.permissionAdminRemoved(user)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
!existingUser.forceResetPassword &&
|
|
75
|
+
user.forceResetPassword &&
|
|
76
|
+
user.password
|
|
77
|
+
) {
|
|
78
|
+
await events.user.passwordForceReset(user)
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
await events.user.created(user)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isAddingBuilder(user, existingUser)) {
|
|
85
|
+
await events.user.permissionBuilderAssigned(user)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (isAddingAdmin(user, existingUser)) {
|
|
89
|
+
await events.user.permissionAdminAssigned(user)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await handleAppRoleEvents(user, existingUser)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const isBuilder = (user: any) => user.builder && user.builder.global
|
|
96
|
+
const isAdmin = (user: any) => user.admin && user.admin.global
|
|
97
|
+
|
|
98
|
+
export const isAddingBuilder = (user: any, existingUser: any) => {
|
|
99
|
+
return isAddingPermission(user, existingUser, isBuilder)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const isRemovingBuilder = (user: any, existingUser: any) => {
|
|
103
|
+
return isRemovingPermission(user, existingUser, isBuilder)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const isAddingAdmin = (user: any, existingUser: any) => {
|
|
107
|
+
return isAddingPermission(user, existingUser, isAdmin)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const isRemovingAdmin = (user: any, existingUser: any) => {
|
|
111
|
+
return isRemovingPermission(user, existingUser, isAdmin)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check if a permission is being added to a new or existing user.
|
|
116
|
+
*/
|
|
117
|
+
const isAddingPermission = (
|
|
118
|
+
user: any,
|
|
119
|
+
existingUser: any,
|
|
120
|
+
hasPermission: any
|
|
121
|
+
) => {
|
|
122
|
+
// new user doesn't have the permission
|
|
123
|
+
if (!hasPermission(user)) {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// existing user has the permission
|
|
128
|
+
if (existingUser && hasPermission(existingUser)) {
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// permission is being added
|
|
133
|
+
return true
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Check if a permission is being removed from an existing user.
|
|
138
|
+
*/
|
|
139
|
+
const isRemovingPermission = (
|
|
140
|
+
user: any,
|
|
141
|
+
existingUser: any,
|
|
142
|
+
hasPermission: any
|
|
143
|
+
) => {
|
|
144
|
+
// new user has the permission
|
|
145
|
+
if (hasPermission(user)) {
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// no existing user or existing user doesn't have the permission
|
|
150
|
+
if (!existingUser) {
|
|
151
|
+
return false
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// existing user doesn't have the permission
|
|
155
|
+
if (!hasPermission(existingUser)) {
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// permission is being removed
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./users"
|