@budibase/worker 1.0.200-alpha.3 → 1.0.200
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 +0 -3
- package/nodemon.json +1 -1
- package/package.json +46 -56
- package/scripts/dev/manage.js +0 -2
- package/scripts/jestSetup.js +0 -9
- package/scripts/load/users.js +4 -4
- package/src/api/controllers/global/auth.ts +14 -21
- package/src/api/controllers/global/configs.js +2 -126
- package/src/api/controllers/global/roles.js +3 -3
- package/src/api/controllers/global/self.js +3 -12
- package/src/api/controllers/global/users.ts +88 -48
- 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 +16 -38
- package/src/api/routes/tests/configs.spec.js +7 -223
- package/src/api/routes/tests/email.spec.js +7 -8
- package/src/api/routes/tests/realEmail.spec.js +5 -5
- package/src/api/routes/tests/users.spec.js +13 -299
- package/src/{tests → api/routes/tests/utilities}/TestConfiguration.js +111 -68
- package/src/api/routes/tests/utilities/controllers.js +7 -0
- package/src/api/routes/tests/utilities/index.js +41 -0
- package/src/api/routes/tests/utilities/structures.js +2 -0
- package/src/api/utilities/index.js +33 -0
- package/src/api/{routes/validation/users.ts → utilities/validation.js} +4 -4
- package/src/index.ts +0 -2
- package/tsconfig.json +15 -21
- package/src/api/routes/tests/self.spec.js +0 -58
- package/src/api/routes/validation/index.ts +0 -1
- package/src/sdk/index.ts +0 -1
- package/src/sdk/users/events.ts +0 -161
- package/src/sdk/users/index.ts +0 -1
- package/src/sdk/users/users.ts +0 -201
- package/src/tests/controllers.js +0 -7
- package/src/tests/index.js +0 -12
- package/src/tests/mocks/email.js +0 -10
- package/src/tests/mocks/index.js +0 -5
- package/src/tests/structures/configs.js +0 -76
- package/src/tests/structures/index.js +0 -12
- package/src/tests/structures/users.ts +0 -28
- package/tsconfig.build.json +0 -25
|
@@ -1,22 +1,35 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getGlobalUserParams,
|
|
3
|
+
StaticDatabases,
|
|
4
|
+
} = require("@budibase/backend-core/db")
|
|
5
|
+
const { getGlobalUserByEmail } = require("@budibase/backend-core/utils")
|
|
6
|
+
const { user: userCache } = require("@budibase/backend-core/cache")
|
|
7
|
+
const { invalidateSessions } = require("@budibase/backend-core/sessions")
|
|
8
|
+
const accounts = require("@budibase/backend-core/accounts")
|
|
9
|
+
const {
|
|
10
|
+
getGlobalDB,
|
|
11
|
+
doWithGlobalDB,
|
|
12
|
+
getTenantId,
|
|
13
|
+
getTenantUser,
|
|
14
|
+
doesTenantExist,
|
|
15
|
+
doInTenant,
|
|
16
|
+
} = require("@budibase/backend-core/tenancy")
|
|
17
|
+
const { removeUserFromInfoDB } = require("@budibase/backend-core/deprovision")
|
|
18
|
+
const { errors } = require("@budibase/backend-core")
|
|
19
|
+
const { CacheKeys, bustCache } = require("@budibase/backend-core/cache")
|
|
20
|
+
import env from "../../../environment"
|
|
21
|
+
import { syncUserInApps } from "../../../utilities/appService"
|
|
22
|
+
import { quotas, users } from "@budibase/pro"
|
|
23
|
+
import { allUsers, getUser } from "../../utilities"
|
|
1
24
|
import { EmailTemplatePurpose } from "../../../constants"
|
|
2
25
|
import { checkInviteCode } from "../../../utilities/redis"
|
|
3
26
|
import { sendEmail } from "../../../utilities/email"
|
|
4
|
-
import { users } from "../../../sdk"
|
|
5
|
-
import env from "../../../environment"
|
|
6
|
-
import { User, CloudAccount } from "@budibase/types"
|
|
7
|
-
import {
|
|
8
|
-
events,
|
|
9
|
-
errors,
|
|
10
|
-
accounts,
|
|
11
|
-
db as dbUtils,
|
|
12
|
-
users as usersCore,
|
|
13
|
-
tenancy,
|
|
14
|
-
cache,
|
|
15
|
-
} from "@budibase/backend-core"
|
|
16
27
|
|
|
17
28
|
export const save = async (ctx: any) => {
|
|
18
29
|
try {
|
|
19
|
-
const user = await users.save(ctx.request.body)
|
|
30
|
+
const user: any = await users.save(ctx.request.body, getTenantId())
|
|
31
|
+
// let server know to sync user
|
|
32
|
+
await syncUserInApps(user._id)
|
|
20
33
|
ctx.body = user
|
|
21
34
|
} catch (err: any) {
|
|
22
35
|
ctx.throw(err.status || 400, err)
|
|
@@ -29,22 +42,38 @@ const parseBooleanParam = (param: any) => {
|
|
|
29
42
|
|
|
30
43
|
export const adminUser = async (ctx: any) => {
|
|
31
44
|
const { email, password, tenantId } = ctx.request.body
|
|
32
|
-
await
|
|
45
|
+
await doInTenant(tenantId, async () => {
|
|
33
46
|
// account portal sends a pre-hashed password - honour param to prevent double hashing
|
|
34
47
|
const hashPassword = parseBooleanParam(ctx.request.query.hashPassword)
|
|
35
48
|
// account portal sends no password for SSO users
|
|
36
49
|
const requirePassword = parseBooleanParam(ctx.request.query.requirePassword)
|
|
37
50
|
|
|
38
|
-
if (await
|
|
51
|
+
if (await doesTenantExist(tenantId)) {
|
|
39
52
|
ctx.throw(403, "Organisation already exists.")
|
|
40
53
|
}
|
|
41
54
|
|
|
42
|
-
const response = await
|
|
43
|
-
|
|
44
|
-
|
|
55
|
+
const response = await doWithGlobalDB(tenantId, async (db: any) => {
|
|
56
|
+
const response = await db.allDocs(
|
|
57
|
+
getGlobalUserParams(null, {
|
|
45
58
|
include_docs: true,
|
|
46
59
|
})
|
|
47
60
|
)
|
|
61
|
+
// write usage quotas for cloud
|
|
62
|
+
if (!env.SELF_HOSTED) {
|
|
63
|
+
// could be a scenario where it exists, make sure its clean
|
|
64
|
+
try {
|
|
65
|
+
const usageQuota = await db.get(
|
|
66
|
+
StaticDatabases.GLOBAL.docs.usageQuota
|
|
67
|
+
)
|
|
68
|
+
if (usageQuota) {
|
|
69
|
+
await db.remove(usageQuota._id, usageQuota._rev)
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
// don't worry about errors
|
|
73
|
+
}
|
|
74
|
+
await db.put(quotas.generateNewQuotaUsage())
|
|
75
|
+
}
|
|
76
|
+
return response
|
|
48
77
|
})
|
|
49
78
|
|
|
50
79
|
if (response.rows.some((row: any) => row.doc.admin)) {
|
|
@@ -54,7 +83,7 @@ export const adminUser = async (ctx: any) => {
|
|
|
54
83
|
)
|
|
55
84
|
}
|
|
56
85
|
|
|
57
|
-
const user
|
|
86
|
+
const user = {
|
|
58
87
|
email: email,
|
|
59
88
|
password: password,
|
|
60
89
|
createdAt: Date.now(),
|
|
@@ -68,19 +97,13 @@ export const adminUser = async (ctx: any) => {
|
|
|
68
97
|
tenantId,
|
|
69
98
|
}
|
|
70
99
|
try {
|
|
71
|
-
const finalUser = await users.save(
|
|
100
|
+
const finalUser = await users.save(
|
|
101
|
+
user,
|
|
102
|
+
tenantId,
|
|
72
103
|
hashPassword,
|
|
73
|
-
requirePassword
|
|
74
|
-
|
|
75
|
-
await
|
|
76
|
-
|
|
77
|
-
// events
|
|
78
|
-
let account: CloudAccount | undefined
|
|
79
|
-
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
80
|
-
account = await accounts.getAccountByTenantId(tenantId)
|
|
81
|
-
}
|
|
82
|
-
await events.identification.identifyTenantGroup(tenantId, account)
|
|
83
|
-
|
|
104
|
+
requirePassword
|
|
105
|
+
)
|
|
106
|
+
await bustCache(CacheKeys.CHECKLIST)
|
|
84
107
|
ctx.body = finalUser
|
|
85
108
|
} catch (err: any) {
|
|
86
109
|
ctx.throw(err.status || 400, err)
|
|
@@ -89,16 +112,37 @@ export const adminUser = async (ctx: any) => {
|
|
|
89
112
|
}
|
|
90
113
|
|
|
91
114
|
export const destroy = async (ctx: any) => {
|
|
92
|
-
const
|
|
93
|
-
await
|
|
115
|
+
const db = getGlobalDB()
|
|
116
|
+
const dbUser = await db.get(ctx.params.id)
|
|
117
|
+
|
|
118
|
+
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
119
|
+
// root account holder can't be deleted from inside budibase
|
|
120
|
+
const email = dbUser.email
|
|
121
|
+
const account = await accounts.getAccount(email)
|
|
122
|
+
if (account) {
|
|
123
|
+
if (email === ctx.user.email) {
|
|
124
|
+
ctx.throw(400, 'Please visit "Account" to delete this user')
|
|
125
|
+
} else {
|
|
126
|
+
ctx.throw(400, "Account holder cannot be deleted")
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
await removeUserFromInfoDB(dbUser)
|
|
132
|
+
await db.remove(dbUser._id, dbUser._rev)
|
|
133
|
+
await quotas.removeUser(dbUser)
|
|
134
|
+
await userCache.invalidateUser(dbUser._id)
|
|
135
|
+
await invalidateSessions(dbUser._id)
|
|
136
|
+
// let server know to sync user
|
|
137
|
+
await syncUserInApps(dbUser._id)
|
|
94
138
|
ctx.body = {
|
|
95
|
-
message: `User ${id} deleted.`,
|
|
139
|
+
message: `User ${ctx.params.id} deleted.`,
|
|
96
140
|
}
|
|
97
141
|
}
|
|
98
142
|
|
|
99
143
|
// called internally by app server user fetch
|
|
100
144
|
export const fetch = async (ctx: any) => {
|
|
101
|
-
const all = await
|
|
145
|
+
const all = await allUsers()
|
|
102
146
|
// user hashed password shouldn't ever be returned
|
|
103
147
|
for (let user of all) {
|
|
104
148
|
if (user) {
|
|
@@ -110,12 +154,12 @@ export const fetch = async (ctx: any) => {
|
|
|
110
154
|
|
|
111
155
|
// called internally by app server user find
|
|
112
156
|
export const find = async (ctx: any) => {
|
|
113
|
-
ctx.body = await
|
|
157
|
+
ctx.body = await getUser(ctx.params.id)
|
|
114
158
|
}
|
|
115
159
|
|
|
116
160
|
export const tenantUserLookup = async (ctx: any) => {
|
|
117
161
|
const id = ctx.params.id
|
|
118
|
-
const user = await
|
|
162
|
+
const user = await getTenantUser(id)
|
|
119
163
|
if (user) {
|
|
120
164
|
ctx.body = user
|
|
121
165
|
} else {
|
|
@@ -125,14 +169,14 @@ export const tenantUserLookup = async (ctx: any) => {
|
|
|
125
169
|
|
|
126
170
|
export const invite = async (ctx: any) => {
|
|
127
171
|
let { email, userInfo } = ctx.request.body
|
|
128
|
-
const existing = await
|
|
172
|
+
const existing = await getGlobalUserByEmail(email)
|
|
129
173
|
if (existing) {
|
|
130
174
|
ctx.throw(400, "Email address already in use.")
|
|
131
175
|
}
|
|
132
176
|
if (!userInfo) {
|
|
133
177
|
userInfo = {}
|
|
134
178
|
}
|
|
135
|
-
userInfo.tenantId =
|
|
179
|
+
userInfo.tenantId = getTenantId()
|
|
136
180
|
const opts: any = {
|
|
137
181
|
subject: "{{ company }} platform invitation",
|
|
138
182
|
info: userInfo,
|
|
@@ -141,7 +185,6 @@ export const invite = async (ctx: any) => {
|
|
|
141
185
|
ctx.body = {
|
|
142
186
|
message: "Invitation has been sent.",
|
|
143
187
|
}
|
|
144
|
-
await events.user.invited()
|
|
145
188
|
}
|
|
146
189
|
|
|
147
190
|
export const inviteAccept = async (ctx: any) => {
|
|
@@ -149,19 +192,16 @@ export const inviteAccept = async (ctx: any) => {
|
|
|
149
192
|
try {
|
|
150
193
|
// info is an extension of the user object that was stored by global
|
|
151
194
|
const { email, info }: any = await checkInviteCode(inviteCode)
|
|
152
|
-
ctx.body = await
|
|
153
|
-
|
|
195
|
+
ctx.body = await users.save(
|
|
196
|
+
{
|
|
154
197
|
firstName,
|
|
155
198
|
lastName,
|
|
156
199
|
password,
|
|
157
200
|
email,
|
|
158
201
|
...info,
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await events.user.inviteAccepted(user)
|
|
163
|
-
return saved
|
|
164
|
-
})
|
|
202
|
+
},
|
|
203
|
+
info.tenantId
|
|
204
|
+
)
|
|
165
205
|
} catch (err: any) {
|
|
166
206
|
if (err.code === errors.codes.USAGE_LIMIT_EXCEEDED) {
|
|
167
207
|
// explicitly re-throw limit exceeded errors
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const Router = require("@koa/router")
|
|
2
2
|
const controller = require("../../controllers/global/self")
|
|
3
3
|
const builderOnly = require("../../../middleware/builderOnly")
|
|
4
|
-
const {
|
|
4
|
+
const { buildUserSaveValidation } = require("../../utilities/validation")
|
|
5
5
|
|
|
6
6
|
const router = Router()
|
|
7
7
|
|
|
@@ -11,7 +11,7 @@ router
|
|
|
11
11
|
.get("/api/global/self", controller.getSelf)
|
|
12
12
|
.post(
|
|
13
13
|
"/api/global/self",
|
|
14
|
-
|
|
14
|
+
buildUserSaveValidation(true),
|
|
15
15
|
controller.updateSelf
|
|
16
16
|
)
|
|
17
17
|
|
|
@@ -4,7 +4,7 @@ const joiValidator = require("../../../middleware/joi-validator")
|
|
|
4
4
|
const adminOnly = require("../../../middleware/adminOnly")
|
|
5
5
|
const Joi = require("joi")
|
|
6
6
|
const cloudRestricted = require("../../../middleware/cloudRestricted")
|
|
7
|
-
const {
|
|
7
|
+
const { buildUserSaveValidation } = require("../../utilities/validation")
|
|
8
8
|
const selfController = require("../../controllers/global/self")
|
|
9
9
|
const builderOrAdmin = require("../../../middleware/builderOrAdmin")
|
|
10
10
|
|
|
@@ -42,7 +42,7 @@ router
|
|
|
42
42
|
.post(
|
|
43
43
|
"/api/global/users",
|
|
44
44
|
adminOnly,
|
|
45
|
-
|
|
45
|
+
buildUserSaveValidation(),
|
|
46
46
|
controller.save
|
|
47
47
|
)
|
|
48
48
|
.get("/api/global/users", builderOrAdmin, controller.fetch)
|
|
@@ -73,7 +73,7 @@ router
|
|
|
73
73
|
.get("/api/global/users/self", selfController.getSelf)
|
|
74
74
|
.post(
|
|
75
75
|
"/api/global/users/self",
|
|
76
|
-
|
|
76
|
+
buildUserSaveValidation(true),
|
|
77
77
|
selfController.updateSelf
|
|
78
78
|
)
|
|
79
79
|
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
jest.mock("nodemailer")
|
|
2
|
-
const
|
|
3
|
-
const sendMailMock =
|
|
4
|
-
const { events } = require("@budibase/backend-core")
|
|
2
|
+
const setup = require("./utilities")
|
|
3
|
+
const sendMailMock = setup.emailMock()
|
|
5
4
|
|
|
6
|
-
const TENANT_ID =
|
|
5
|
+
const TENANT_ID = "default"
|
|
7
6
|
|
|
8
7
|
describe("/api/global/auth", () => {
|
|
8
|
+
let request = setup.getRequest()
|
|
9
|
+
let config = setup.getConfig()
|
|
10
|
+
let code
|
|
9
11
|
|
|
10
12
|
beforeAll(async () => {
|
|
11
|
-
await config.
|
|
13
|
+
await config.init()
|
|
12
14
|
})
|
|
13
15
|
|
|
14
|
-
afterAll(
|
|
15
|
-
await config.afterAll()
|
|
16
|
-
})
|
|
16
|
+
afterAll(setup.afterAll)
|
|
17
17
|
|
|
18
18
|
afterEach(() => {
|
|
19
19
|
jest.clearAllMocks()
|
|
20
20
|
})
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
it("should be able to generate password reset email", async () => {
|
|
23
|
+
// initially configure settings
|
|
23
24
|
await config.saveSmtpConfig()
|
|
24
25
|
await config.saveSettingsConfig()
|
|
25
26
|
await config.createUser()
|
|
@@ -30,37 +31,16 @@ describe("/api/global/auth", () => {
|
|
|
30
31
|
})
|
|
31
32
|
.expect("Content-Type", /json/)
|
|
32
33
|
.expect(200)
|
|
33
|
-
const emailCall = sendMailMock.mock.calls[0][0]
|
|
34
|
-
const parts = emailCall.html.split(`http://localhost:10000/builder/auth/reset?code=`)
|
|
35
|
-
const code = parts[1].split("\"")[0].split("&")[0]
|
|
36
|
-
return { code, res }
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
it("should logout", async () => {
|
|
40
|
-
await request
|
|
41
|
-
.post("/api/global/auth/logout")
|
|
42
|
-
.set(config.defaultHeaders())
|
|
43
|
-
.expect(200)
|
|
44
|
-
expect(events.auth.logout).toBeCalledTimes(1)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it("should be able to generate password reset email", async () => {
|
|
48
|
-
const { res, code } = await requestPasswordReset()
|
|
49
|
-
const user = await config.getUser("test@test.com")
|
|
50
|
-
|
|
51
34
|
expect(res.body).toEqual({ message: "Please check your email for a reset link." })
|
|
52
35
|
expect(sendMailMock).toHaveBeenCalled()
|
|
53
|
-
|
|
36
|
+
const emailCall = sendMailMock.mock.calls[0][0]
|
|
37
|
+
// after this URL there should be a code
|
|
38
|
+
const parts = emailCall.html.split(`http://localhost:10000/builder/auth/reset?code=`)
|
|
39
|
+
code = parts[1].split("\"")[0].split("&")[0]
|
|
54
40
|
expect(code).toBeDefined()
|
|
55
|
-
expect(events.user.passwordResetRequested).toBeCalledTimes(1)
|
|
56
|
-
expect(events.user.passwordResetRequested).toBeCalledWith(user)
|
|
57
41
|
})
|
|
58
42
|
|
|
59
43
|
it("should allow resetting user password with code", async () => {
|
|
60
|
-
const { code } = await requestPasswordReset()
|
|
61
|
-
const user = await config.getUser("test@test.com")
|
|
62
|
-
delete user.password
|
|
63
|
-
|
|
64
44
|
const res = await request
|
|
65
45
|
.post(`/api/global/auth/${TENANT_ID}/reset/update`)
|
|
66
46
|
.send({
|
|
@@ -70,16 +50,14 @@ describe("/api/global/auth", () => {
|
|
|
70
50
|
.expect("Content-Type", /json/)
|
|
71
51
|
.expect(200)
|
|
72
52
|
expect(res.body).toEqual({ message: "password reset successfully." })
|
|
73
|
-
expect(events.user.passwordReset).toBeCalledTimes(1)
|
|
74
|
-
expect(events.user.passwordReset).toBeCalledWith(user)
|
|
75
53
|
})
|
|
76
54
|
|
|
77
55
|
describe("oidc", () => {
|
|
78
56
|
const auth = require("@budibase/backend-core/auth")
|
|
79
57
|
|
|
80
58
|
// mock the oidc strategy implementation and return value
|
|
81
|
-
|
|
82
|
-
|
|
59
|
+
strategyFactory = jest.fn()
|
|
60
|
+
mockStrategyReturn = jest.fn()
|
|
83
61
|
strategyFactory.mockReturnValue(mockStrategyReturn)
|
|
84
62
|
auth.oidc.strategyFactory = strategyFactory
|
|
85
63
|
|
|
@@ -1,233 +1,17 @@
|
|
|
1
1
|
// mock the email system
|
|
2
2
|
jest.mock("nodemailer")
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const { Configs } = require("@budibase/backend-core/constants")
|
|
6
|
-
const { events } = require("@budibase/backend-core")
|
|
3
|
+
const setup = require("./utilities")
|
|
4
|
+
setup.emailMock()
|
|
7
5
|
|
|
8
|
-
describe("configs", () => {
|
|
6
|
+
describe("/api/global/configs/checklist", () => {
|
|
7
|
+
let request = setup.getRequest()
|
|
8
|
+
let config = setup.getConfig()
|
|
9
9
|
|
|
10
10
|
beforeAll(async () => {
|
|
11
|
-
await config.
|
|
11
|
+
await config.init()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
jest.clearAllMocks()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
afterAll(async () => {
|
|
19
|
-
await config.afterAll()
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
describe("post /api/global/configs", () => {
|
|
23
|
-
|
|
24
|
-
const saveConfig = async (conf, _id, _rev) => {
|
|
25
|
-
const data = {
|
|
26
|
-
...conf,
|
|
27
|
-
_id,
|
|
28
|
-
_rev
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const res = await request
|
|
32
|
-
.post(`/api/global/configs`)
|
|
33
|
-
.send(data)
|
|
34
|
-
.set(config.defaultHeaders())
|
|
35
|
-
.expect("Content-Type", /json/)
|
|
36
|
-
.expect(200)
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
...data,
|
|
40
|
-
...res.body
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
describe("google", () => {
|
|
45
|
-
const saveGoogleConfig = async (conf, _id, _rev) => {
|
|
46
|
-
const googleConfig = structures.configs.google(conf)
|
|
47
|
-
return saveConfig(googleConfig, _id, _rev)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
describe("create", () => {
|
|
51
|
-
it ("should create activated google config", async () => {
|
|
52
|
-
await saveGoogleConfig()
|
|
53
|
-
expect(events.auth.SSOCreated).toBeCalledTimes(1)
|
|
54
|
-
expect(events.auth.SSOCreated).toBeCalledWith(Configs.GOOGLE)
|
|
55
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
56
|
-
expect(events.auth.SSOActivated).toBeCalledTimes(1)
|
|
57
|
-
expect(events.auth.SSOActivated).toBeCalledWith(Configs.GOOGLE)
|
|
58
|
-
await config.deleteConfig(Configs.GOOGLE)
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it ("should create deactivated google config", async () => {
|
|
62
|
-
await saveGoogleConfig({ activated: false })
|
|
63
|
-
expect(events.auth.SSOCreated).toBeCalledTimes(1)
|
|
64
|
-
expect(events.auth.SSOCreated).toBeCalledWith(Configs.GOOGLE)
|
|
65
|
-
expect(events.auth.SSOActivated).not.toBeCalled()
|
|
66
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
67
|
-
await config.deleteConfig(Configs.GOOGLE)
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
describe("update", () => {
|
|
72
|
-
it ("should update google config to deactivated", async () => {
|
|
73
|
-
const googleConf = await saveGoogleConfig()
|
|
74
|
-
jest.clearAllMocks()
|
|
75
|
-
await saveGoogleConfig({ ...googleConf.config, activated: false }, googleConf._id, googleConf._rev)
|
|
76
|
-
expect(events.auth.SSOUpdated).toBeCalledTimes(1)
|
|
77
|
-
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.GOOGLE)
|
|
78
|
-
expect(events.auth.SSOActivated).not.toBeCalled()
|
|
79
|
-
expect(events.auth.SSODeactivated).toBeCalledTimes(1)
|
|
80
|
-
expect(events.auth.SSODeactivated).toBeCalledWith(Configs.GOOGLE)
|
|
81
|
-
await config.deleteConfig(Configs.GOOGLE)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it ("should update google config to activated", async () => {
|
|
85
|
-
const googleConf = await saveGoogleConfig({ activated: false })
|
|
86
|
-
jest.clearAllMocks()
|
|
87
|
-
await saveGoogleConfig({ ...googleConf.config, activated: true}, googleConf._id, googleConf._rev)
|
|
88
|
-
expect(events.auth.SSOUpdated).toBeCalledTimes(1)
|
|
89
|
-
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.GOOGLE)
|
|
90
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
91
|
-
expect(events.auth.SSOActivated).toBeCalledTimes(1)
|
|
92
|
-
expect(events.auth.SSOActivated).toBeCalledWith(Configs.GOOGLE)
|
|
93
|
-
await config.deleteConfig(Configs.GOOGLE)
|
|
94
|
-
})
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
describe("oidc", () => {
|
|
99
|
-
const saveOIDCConfig = async (conf, _id, _rev) => {
|
|
100
|
-
const oidcConfig = structures.configs.oidc(conf)
|
|
101
|
-
return saveConfig(oidcConfig, _id, _rev)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
describe("create", () => {
|
|
105
|
-
it ("should create activated OIDC config", async () => {
|
|
106
|
-
await saveOIDCConfig()
|
|
107
|
-
expect(events.auth.SSOCreated).toBeCalledTimes(1)
|
|
108
|
-
expect(events.auth.SSOCreated).toBeCalledWith(Configs.OIDC)
|
|
109
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
110
|
-
expect(events.auth.SSOActivated).toBeCalledTimes(1)
|
|
111
|
-
expect(events.auth.SSOActivated).toBeCalledWith(Configs.OIDC)
|
|
112
|
-
await config.deleteConfig(Configs.OIDC)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it ("should create deactivated OIDC config", async () => {
|
|
116
|
-
await saveOIDCConfig({ activated: false })
|
|
117
|
-
expect(events.auth.SSOCreated).toBeCalledTimes(1)
|
|
118
|
-
expect(events.auth.SSOCreated).toBeCalledWith(Configs.OIDC)
|
|
119
|
-
expect(events.auth.SSOActivated).not.toBeCalled()
|
|
120
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
121
|
-
await config.deleteConfig(Configs.OIDC)
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
describe("update", () => {
|
|
126
|
-
it ("should update OIDC config to deactivated", async () => {
|
|
127
|
-
const oidcConf = await saveOIDCConfig()
|
|
128
|
-
jest.clearAllMocks()
|
|
129
|
-
await saveOIDCConfig({ ...oidcConf.config.configs[0], activated: false }, oidcConf._id, oidcConf._rev)
|
|
130
|
-
expect(events.auth.SSOUpdated).toBeCalledTimes(1)
|
|
131
|
-
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.OIDC)
|
|
132
|
-
expect(events.auth.SSOActivated).not.toBeCalled()
|
|
133
|
-
expect(events.auth.SSODeactivated).toBeCalledTimes(1)
|
|
134
|
-
expect(events.auth.SSODeactivated).toBeCalledWith(Configs.OIDC)
|
|
135
|
-
await config.deleteConfig(Configs.OIDC)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it ("should update OIDC config to activated", async () => {
|
|
139
|
-
const oidcConf = await saveOIDCConfig({ activated: false })
|
|
140
|
-
jest.clearAllMocks()
|
|
141
|
-
await saveOIDCConfig({ ...oidcConf.config.configs[0], activated: true}, oidcConf._id, oidcConf._rev)
|
|
142
|
-
expect(events.auth.SSOUpdated).toBeCalledTimes(1)
|
|
143
|
-
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.OIDC)
|
|
144
|
-
expect(events.auth.SSODeactivated).not.toBeCalled()
|
|
145
|
-
expect(events.auth.SSOActivated).toBeCalledTimes(1)
|
|
146
|
-
expect(events.auth.SSOActivated).toBeCalledWith(Configs.OIDC)
|
|
147
|
-
await config.deleteConfig(Configs.OIDC)
|
|
148
|
-
})
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
describe("smtp", () => {
|
|
154
|
-
const saveSMTPConfig = async (conf, _id, _rev) => {
|
|
155
|
-
const smtpConfig = structures.configs.smtp(conf)
|
|
156
|
-
return saveConfig(smtpConfig, _id, _rev)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
describe("create", () => {
|
|
160
|
-
it ("should create SMTP config", async () => {
|
|
161
|
-
await config.deleteConfig(Configs.SMTP)
|
|
162
|
-
await saveSMTPConfig()
|
|
163
|
-
expect(events.email.SMTPUpdated).not.toBeCalled()
|
|
164
|
-
expect(events.email.SMTPCreated).toBeCalledTimes(1)
|
|
165
|
-
await config.deleteConfig(Configs.SMTP)
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
describe("update", () => {
|
|
170
|
-
it ("should update SMTP config", async () => {
|
|
171
|
-
const smtpConf = await saveSMTPConfig()
|
|
172
|
-
jest.clearAllMocks()
|
|
173
|
-
await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev)
|
|
174
|
-
expect(events.email.SMTPCreated).not.toBeCalled()
|
|
175
|
-
expect(events.email.SMTPUpdated).toBeCalledTimes(1)
|
|
176
|
-
await config.deleteConfig(Configs.SMTP)
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
describe("settings", () => {
|
|
182
|
-
const saveSettingsConfig = async (conf, _id, _rev) => {
|
|
183
|
-
const settingsConfig = structures.configs.settings(conf)
|
|
184
|
-
return saveConfig(settingsConfig, _id, _rev)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
describe("create", () => {
|
|
188
|
-
it ("should create settings config with default settings", async () => {
|
|
189
|
-
await config.deleteConfig(Configs.SETTINGS)
|
|
190
|
-
|
|
191
|
-
await saveSettingsConfig()
|
|
192
|
-
|
|
193
|
-
expect(events.org.nameUpdated).not.toBeCalled()
|
|
194
|
-
expect(events.org.logoUpdated).not.toBeCalled()
|
|
195
|
-
expect(events.org.platformURLUpdated).not.toBeCalled()
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
it ("should create settings config with non-default settings", async () => {
|
|
199
|
-
await config.deleteConfig(Configs.SETTINGS)
|
|
200
|
-
const conf = {
|
|
201
|
-
company: "acme",
|
|
202
|
-
logoUrl: "http://example.com",
|
|
203
|
-
platformUrl: "http://example.com"
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
await saveSettingsConfig(conf)
|
|
207
|
-
|
|
208
|
-
expect(events.org.nameUpdated).toBeCalledTimes(1)
|
|
209
|
-
expect(events.org.logoUpdated).toBeCalledTimes(1)
|
|
210
|
-
expect(events.org.platformURLUpdated).toBeCalledTimes(1)
|
|
211
|
-
})
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
describe("update", () => {
|
|
215
|
-
it ("should update settings config", async () => {
|
|
216
|
-
await config.deleteConfig(Configs.SETTINGS)
|
|
217
|
-
const settingsConfig = await saveSettingsConfig()
|
|
218
|
-
settingsConfig.config.company = "acme"
|
|
219
|
-
settingsConfig.config.logoUrl = "http://example.com"
|
|
220
|
-
settingsConfig.config.platformUrl = "http://example.com"
|
|
221
|
-
|
|
222
|
-
await saveSettingsConfig(settingsConfig.config, settingsConfig._id, settingsConfig._rev)
|
|
223
|
-
|
|
224
|
-
expect(events.org.nameUpdated).toBeCalledTimes(1)
|
|
225
|
-
expect(events.org.logoUpdated).toBeCalledTimes(1)
|
|
226
|
-
expect(events.org.platformURLUpdated).toBeCalledTimes(1)
|
|
227
|
-
})
|
|
228
|
-
})
|
|
229
|
-
})
|
|
230
|
-
})
|
|
14
|
+
afterAll(setup.afterAll)
|
|
231
15
|
|
|
232
16
|
it("should return the correct checklist status based on the state of the budibase installation", async () => {
|
|
233
17
|
await config.saveSmtpConfig()
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
jest.mock("nodemailer")
|
|
2
|
-
const
|
|
3
|
-
const sendMailMock =
|
|
2
|
+
const setup = require("./utilities")
|
|
3
|
+
const sendMailMock = setup.emailMock()
|
|
4
4
|
|
|
5
5
|
const { EmailTemplatePurpose } = require("../../../constants")
|
|
6
|
-
|
|
7
|
-
const TENANT_ID = structures.TENANT_ID
|
|
6
|
+
const { TENANT_ID } = require("./utilities/structures")
|
|
8
7
|
|
|
9
8
|
describe("/api/global/email", () => {
|
|
9
|
+
let request = setup.getRequest()
|
|
10
|
+
let config = setup.getConfig()
|
|
10
11
|
|
|
11
12
|
beforeAll(async () => {
|
|
12
|
-
await config.
|
|
13
|
+
await config.init()
|
|
13
14
|
})
|
|
14
15
|
|
|
15
|
-
afterAll(
|
|
16
|
-
await config.afterAll()
|
|
17
|
-
})
|
|
16
|
+
afterAll(setup.afterAll)
|
|
18
17
|
|
|
19
18
|
it("should be able to send an email (with mocking)", async () => {
|
|
20
19
|
// initially configure settings
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const setup = require("./utilities")
|
|
2
2
|
const { EmailTemplatePurpose } = require("../../../constants")
|
|
3
3
|
const nodemailer = require("nodemailer")
|
|
4
4
|
const fetch = require("node-fetch")
|
|
@@ -7,14 +7,14 @@ const fetch = require("node-fetch")
|
|
|
7
7
|
jest.setTimeout(30000)
|
|
8
8
|
|
|
9
9
|
describe("/api/global/email", () => {
|
|
10
|
+
let request = setup.getRequest()
|
|
11
|
+
let config = setup.getConfig()
|
|
10
12
|
|
|
11
13
|
beforeAll(async () => {
|
|
12
|
-
await config.
|
|
14
|
+
await config.init()
|
|
13
15
|
})
|
|
14
16
|
|
|
15
|
-
afterAll(
|
|
16
|
-
await config.afterAll()
|
|
17
|
-
})
|
|
17
|
+
afterAll(setup.afterAll)
|
|
18
18
|
|
|
19
19
|
async function sendRealEmail(purpose) {
|
|
20
20
|
let response, text
|