@budibase/worker 2.1.22-alpha.6 → 2.1.22-alpha.7
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/coverage/clover.xml +326 -305
- package/coverage/coverage-final.json +13 -13
- package/coverage/lcov-report/index.html +34 -34
- package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +50 -38
- package/coverage/lcov-report/src/api/controllers/global/configs.js.html +18 -18
- package/coverage/lcov-report/src/api/controllers/global/email.js.html +1 -1
- package/coverage/lcov-report/src/api/controllers/global/index.html +10 -10
- package/coverage/lcov-report/src/api/controllers/global/license.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/global/roles.js.html +1 -1
- package/coverage/lcov-report/src/api/controllers/global/self.ts.html +3 -3
- package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/global/users.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/global/workspaces.js.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/index.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/status.ts.html +1 -1
- package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +1 -1
- package/coverage/lcov-report/src/api/index.html +1 -1
- package/coverage/lcov-report/src/api/index.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/auth.js.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/configs.js.html +10 -10
- package/coverage/lcov-report/src/api/routes/global/email.js.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/index.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/license.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/roles.js.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/self.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/templates.ts.html +3 -3
- package/coverage/lcov-report/src/api/routes/global/users.js.html +1 -1
- package/coverage/lcov-report/src/api/routes/global/workspaces.js.html +1 -1
- package/coverage/lcov-report/src/api/routes/index.html +1 -1
- package/coverage/lcov-report/src/api/routes/index.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/environment.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/index.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/restore.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/status.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/validation/index.html +1 -1
- package/coverage/lcov-report/src/api/routes/validation/index.ts.html +1 -1
- package/coverage/lcov-report/src/api/routes/validation/users.ts.html +1 -1
- package/coverage/lcov-report/src/constants/index.html +10 -10
- package/coverage/lcov-report/src/constants/{index.js.html → index.ts.html} +92 -113
- package/coverage/lcov-report/src/constants/templates/index.html +1 -1
- package/coverage/lcov-report/src/constants/templates/index.js.html +3 -3
- package/coverage/lcov-report/src/db/index.html +1 -1
- package/coverage/lcov-report/src/db/index.ts.html +1 -1
- package/coverage/lcov-report/src/environment.ts.html +1 -1
- package/coverage/lcov-report/src/index.html +1 -1
- package/coverage/lcov-report/src/index.ts.html +1 -1
- package/coverage/lcov-report/src/middleware/cloudRestricted.js.html +3 -3
- package/coverage/lcov-report/src/middleware/index.html +1 -1
- package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +1 -1
- package/coverage/lcov-report/src/migrations/functions/index.html +1 -1
- package/coverage/lcov-report/src/migrations/index.html +1 -1
- package/coverage/lcov-report/src/migrations/index.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/accounts/index.html +1 -1
- package/coverage/lcov-report/src/sdk/accounts/index.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/index.html +1 -1
- package/coverage/lcov-report/src/sdk/index.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/users/events.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/users/index.html +1 -1
- package/coverage/lcov-report/src/sdk/users/index.ts.html +1 -1
- package/coverage/lcov-report/src/sdk/users/users.ts.html +1 -1
- package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +31 -22
- package/coverage/lcov-report/src/tests/api/accounts.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/auth.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/base.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/configs.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/email.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/environment.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/index.html +1 -1
- package/coverage/lcov-report/src/tests/api/index.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/migrations.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/restore.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/self.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/status.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/tenants.ts.html +1 -1
- package/coverage/lcov-report/src/tests/api/users.ts.html +1 -1
- package/coverage/lcov-report/src/tests/controllers.js.html +1 -1
- package/coverage/lcov-report/src/tests/index.html +15 -15
- package/coverage/lcov-report/src/tests/index.ts.html +1 -1
- package/coverage/lcov-report/src/tests/mocks/email.js.html +1 -1
- package/coverage/lcov-report/src/tests/mocks/index.html +1 -1
- package/coverage/lcov-report/src/tests/mocks/index.ts.html +1 -1
- package/coverage/lcov-report/src/tests/structures/configs.js.html +7 -7
- package/coverage/lcov-report/src/tests/structures/groups.ts.html +1 -1
- package/coverage/lcov-report/src/tests/structures/index.html +1 -1
- package/coverage/lcov-report/src/tests/structures/index.ts.html +1 -1
- package/coverage/lcov-report/src/tests/structures/users.ts.html +1 -1
- package/coverage/lcov-report/src/utilities/appService.js.html +4 -4
- package/coverage/lcov-report/src/utilities/{email.js.html → email.ts.html} +160 -61
- package/coverage/lcov-report/src/utilities/fileSystem.js.html +1 -1
- package/coverage/lcov-report/src/utilities/index.html +23 -23
- package/coverage/lcov-report/src/utilities/index.js.html +1 -1
- package/coverage/lcov-report/src/utilities/{redis.js.html → redis.ts.html} +53 -38
- package/coverage/lcov-report/src/utilities/{templates.js.html → templates.ts.html} +38 -38
- package/coverage/lcov-report/src/utilities/users.js.html +1 -1
- package/coverage/lcov.info +593 -529
- package/jest.config.ts +1 -0
- package/package.json +6 -6
- package/src/api/controllers/global/auth.ts +34 -30
- package/src/api/controllers/global/configs.js +17 -17
- package/src/api/controllers/global/self.ts +2 -2
- package/src/api/routes/global/configs.js +9 -9
- package/src/api/routes/global/templates.ts +2 -2
- package/src/api/routes/global/tests/configs.spec.ts +29 -29
- package/src/constants/{index.js → index.ts} +57 -64
- package/src/constants/templates/index.js +2 -2
- package/src/middleware/cloudRestricted.js +2 -2
- package/src/middleware/tests/tenancy.spec.ts +7 -7
- package/src/tests/TestConfiguration.ts +15 -12
- package/src/tests/structures/configs.js +6 -6
- package/src/utilities/appService.js +3 -3
- package/src/utilities/{email.js → email.ts} +78 -45
- package/src/utilities/{redis.js → redis.ts} +29 -24
- package/src/utilities/templates.ts +49 -0
- package/tsconfig.build.json +3 -3
- package/src/utilities/templates.js +0 -49
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
import { constants } from "@budibase/backend-core"
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export const LOGO_URL =
|
|
4
4
|
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
ACTIVE
|
|
8
|
-
INACTIVE
|
|
6
|
+
export enum UserStatus {
|
|
7
|
+
ACTIVE = "active",
|
|
8
|
+
INACTIVE = "inactive",
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
export const Config = constants.Config
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
LOGO
|
|
15
|
-
OIDC_LOGO
|
|
13
|
+
export enum ConfigUpload {
|
|
14
|
+
LOGO = "logo",
|
|
15
|
+
OIDC_LOGO = "oidc_logo",
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
EMAIL
|
|
18
|
+
export enum TemplateType {
|
|
19
|
+
EMAIL = "email",
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
BASE
|
|
24
|
-
PASSWORD_RECOVERY
|
|
25
|
-
INVITATION
|
|
26
|
-
WELCOME
|
|
27
|
-
CUSTOM
|
|
22
|
+
export enum EmailTemplatePurpose {
|
|
23
|
+
BASE = "base",
|
|
24
|
+
PASSWORD_RECOVERY = "password_recovery",
|
|
25
|
+
INVITATION = "invitation",
|
|
26
|
+
WELCOME = "welcome",
|
|
27
|
+
CUSTOM = "custom",
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
PLATFORM_URL
|
|
32
|
-
COMPANY
|
|
33
|
-
LOGO_URL
|
|
34
|
-
EMAIL
|
|
35
|
-
USER
|
|
36
|
-
REQUEST
|
|
37
|
-
DOCS_URL
|
|
38
|
-
LOGIN_URL
|
|
39
|
-
CURRENT_YEAR
|
|
40
|
-
CURRENT_DATE
|
|
41
|
-
BODY
|
|
42
|
-
STYLES
|
|
43
|
-
RESET_URL
|
|
44
|
-
RESET_CODE
|
|
45
|
-
INVITE_URL
|
|
46
|
-
INVITE_CODE
|
|
47
|
-
CONTENTS
|
|
30
|
+
export enum InternalTemplateBinding {
|
|
31
|
+
PLATFORM_URL = "platformUrl",
|
|
32
|
+
COMPANY = "company",
|
|
33
|
+
LOGO_URL = "logoUrl",
|
|
34
|
+
EMAIL = "email",
|
|
35
|
+
USER = "user",
|
|
36
|
+
REQUEST = "request",
|
|
37
|
+
DOCS_URL = "docsUrl",
|
|
38
|
+
LOGIN_URL = "loginUrl",
|
|
39
|
+
CURRENT_YEAR = "currentYear",
|
|
40
|
+
CURRENT_DATE = "currentDate",
|
|
41
|
+
BODY = "body",
|
|
42
|
+
STYLES = "styles",
|
|
43
|
+
RESET_URL = "resetUrl",
|
|
44
|
+
RESET_CODE = "resetCode",
|
|
45
|
+
INVITE_URL = "inviteUrl",
|
|
46
|
+
INVITE_CODE = "inviteUrl",
|
|
47
|
+
CONTENTS = "contents",
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
const TemplateBindings = {
|
|
50
|
+
export const TemplateBindings = {
|
|
51
51
|
PLATFORM_URL: {
|
|
52
|
-
name:
|
|
52
|
+
name: InternalTemplateBinding.PLATFORM_URL,
|
|
53
53
|
description: "The URL used to access the budibase platform",
|
|
54
54
|
},
|
|
55
55
|
COMPANY: {
|
|
56
|
-
name:
|
|
56
|
+
name: InternalTemplateBinding.COMPANY,
|
|
57
57
|
description: "The name of your organization",
|
|
58
58
|
},
|
|
59
59
|
LOGO_URL: {
|
|
60
|
-
name:
|
|
60
|
+
name: InternalTemplateBinding.LOGO_URL,
|
|
61
61
|
description: "The URL of your organizations logo.",
|
|
62
62
|
},
|
|
63
63
|
EMAIL: {
|
|
64
|
-
name:
|
|
64
|
+
name: InternalTemplateBinding.EMAIL,
|
|
65
65
|
description: "The recipients email address.",
|
|
66
66
|
},
|
|
67
67
|
USER: {
|
|
68
|
-
name:
|
|
68
|
+
name: InternalTemplateBinding.USER,
|
|
69
69
|
description: "The recipients user object.",
|
|
70
70
|
},
|
|
71
71
|
REQUEST: {
|
|
72
|
-
name:
|
|
72
|
+
name: InternalTemplateBinding.REQUEST,
|
|
73
73
|
description: "Additional request metadata.",
|
|
74
74
|
},
|
|
75
75
|
DOCS_URL: {
|
|
76
|
-
name:
|
|
76
|
+
name: InternalTemplateBinding.DOCS_URL,
|
|
77
77
|
description: "Organization documentation URL.",
|
|
78
78
|
},
|
|
79
79
|
LOGIN_URL: {
|
|
80
|
-
name:
|
|
80
|
+
name: InternalTemplateBinding.LOGIN_URL,
|
|
81
81
|
description: "The URL used to log into the organization budibase instance.",
|
|
82
82
|
},
|
|
83
83
|
CURRENT_YEAR: {
|
|
84
|
-
name:
|
|
84
|
+
name: InternalTemplateBinding.CURRENT_YEAR,
|
|
85
85
|
description: "The current year.",
|
|
86
86
|
},
|
|
87
87
|
CURRENT_DATE: {
|
|
88
|
-
name:
|
|
88
|
+
name: InternalTemplateBinding.CURRENT_DATE,
|
|
89
89
|
description: "The current date.",
|
|
90
90
|
},
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const TemplateMetadata = {
|
|
94
|
-
[
|
|
93
|
+
export const TemplateMetadata = {
|
|
94
|
+
[TemplateType.EMAIL]: [
|
|
95
95
|
{
|
|
96
96
|
name: "Base format",
|
|
97
97
|
description:
|
|
@@ -100,11 +100,11 @@ const TemplateMetadata = {
|
|
|
100
100
|
purpose: EmailTemplatePurpose.BASE,
|
|
101
101
|
bindings: [
|
|
102
102
|
{
|
|
103
|
-
name:
|
|
103
|
+
name: InternalTemplateBinding.BODY,
|
|
104
104
|
description: "The main body of another email template.",
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
|
-
name:
|
|
107
|
+
name: InternalTemplateBinding.STYLES,
|
|
108
108
|
description: "The contents of the Styling email template.",
|
|
109
109
|
},
|
|
110
110
|
],
|
|
@@ -117,12 +117,12 @@ const TemplateMetadata = {
|
|
|
117
117
|
purpose: EmailTemplatePurpose.PASSWORD_RECOVERY,
|
|
118
118
|
bindings: [
|
|
119
119
|
{
|
|
120
|
-
name:
|
|
120
|
+
name: InternalTemplateBinding.RESET_URL,
|
|
121
121
|
description:
|
|
122
122
|
"The URL the recipient must click to reset their password.",
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
|
-
name:
|
|
125
|
+
name: InternalTemplateBinding.RESET_CODE,
|
|
126
126
|
description:
|
|
127
127
|
"The temporary password reset code used in the recipients password reset URL.",
|
|
128
128
|
},
|
|
@@ -144,12 +144,12 @@ const TemplateMetadata = {
|
|
|
144
144
|
purpose: EmailTemplatePurpose.INVITATION,
|
|
145
145
|
bindings: [
|
|
146
146
|
{
|
|
147
|
-
name:
|
|
147
|
+
name: InternalTemplateBinding.INVITE_URL,
|
|
148
148
|
description:
|
|
149
149
|
"The URL the recipient must click to accept the invitation and activate their account.",
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
|
-
name:
|
|
152
|
+
name: InternalTemplateBinding.INVITE_CODE,
|
|
153
153
|
description:
|
|
154
154
|
"The temporary invite code used in the recipients invitation URL.",
|
|
155
155
|
},
|
|
@@ -163,7 +163,7 @@ const TemplateMetadata = {
|
|
|
163
163
|
purpose: EmailTemplatePurpose.CUSTOM,
|
|
164
164
|
bindings: [
|
|
165
165
|
{
|
|
166
|
-
name:
|
|
166
|
+
name: InternalTemplateBinding.CONTENTS,
|
|
167
167
|
description: "Custom content body.",
|
|
168
168
|
},
|
|
169
169
|
],
|
|
@@ -172,12 +172,5 @@ const TemplateMetadata = {
|
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// all purpose combined
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
exports.TemplateTypes = TemplateTypes
|
|
179
|
-
exports.EmailTemplatePurpose = EmailTemplatePurpose
|
|
180
|
-
exports.TemplateMetadata = TemplateMetadata
|
|
181
|
-
exports.TemplateBindings = TemplateBindings
|
|
182
|
-
exports.InternalTemplateBindings = InternalTemplateBindings
|
|
183
|
-
exports.GLOBAL_OWNER = "global"
|
|
175
|
+
export { EmailTemplatePurpose as TemplatePurpose }
|
|
176
|
+
export const GLOBAL_OWNER = "global"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { readStaticFile } = require("../../utilities/fileSystem")
|
|
2
2
|
const {
|
|
3
3
|
EmailTemplatePurpose,
|
|
4
|
-
|
|
4
|
+
TemplateType,
|
|
5
5
|
TemplatePurpose,
|
|
6
6
|
GLOBAL_OWNER,
|
|
7
7
|
} = require("../index")
|
|
@@ -26,7 +26,7 @@ exports.EmailTemplates = {
|
|
|
26
26
|
exports.addBaseTemplates = (templates, type = null) => {
|
|
27
27
|
let purposeList
|
|
28
28
|
switch (type) {
|
|
29
|
-
case
|
|
29
|
+
case TemplateType.EMAIL:
|
|
30
30
|
purposeList = Object.values(EmailTemplatePurpose)
|
|
31
31
|
break
|
|
32
32
|
default:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const env = require("../environment")
|
|
2
|
-
const {
|
|
2
|
+
const { Header } = require("@budibase/backend-core/constants")
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* This is a restricted endpoint in the cloud.
|
|
@@ -7,7 +7,7 @@ const { Headers } = require("@budibase/backend-core/constants")
|
|
|
7
7
|
*/
|
|
8
8
|
module.exports = async (ctx, next) => {
|
|
9
9
|
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
10
|
-
const apiKey = ctx.request.headers[
|
|
10
|
+
const apiKey = ctx.request.headers[Header.API_KEY]
|
|
11
11
|
if (apiKey !== env.INTERNAL_API_KEY) {
|
|
12
12
|
ctx.throw(403, "Unauthorized")
|
|
13
13
|
}
|
|
@@ -20,18 +20,18 @@ describe("tenancy middleware", () => {
|
|
|
20
20
|
const user = await config.createTenant()
|
|
21
21
|
await config.createSession(user)
|
|
22
22
|
const res = await config.api.self.getSelf(user)
|
|
23
|
-
expect(res.headers[constants.
|
|
23
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(user.tenantId)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
it("should get tenant id from header", async () => {
|
|
27
27
|
const tenantId = structures.uuid()
|
|
28
28
|
const headers = {
|
|
29
|
-
[constants.
|
|
29
|
+
[constants.Header.TENANT_ID]: tenantId,
|
|
30
30
|
}
|
|
31
31
|
const res = await config.request
|
|
32
32
|
.get(`/api/global/configs/checklist`)
|
|
33
33
|
.set(headers)
|
|
34
|
-
expect(res.headers[constants.
|
|
34
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
it("should get tenant id from query param", async () => {
|
|
@@ -39,7 +39,7 @@ describe("tenancy middleware", () => {
|
|
|
39
39
|
const res = await config.request.get(
|
|
40
40
|
`/api/global/configs/checklist?tenantId=${tenantId}`
|
|
41
41
|
)
|
|
42
|
-
expect(res.headers[constants.
|
|
42
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
it("should get tenant id from subdomain", async () => {
|
|
@@ -50,7 +50,7 @@ describe("tenancy middleware", () => {
|
|
|
50
50
|
const res = await config.request
|
|
51
51
|
.get(`/api/global/configs/checklist`)
|
|
52
52
|
.set(headers)
|
|
53
|
-
expect(res.headers[constants.
|
|
53
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(tenantId)
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
it("should get tenant id from path variable", async () => {
|
|
@@ -61,13 +61,13 @@ describe("tenancy middleware", () => {
|
|
|
61
61
|
username: user.email,
|
|
62
62
|
password: user.password,
|
|
63
63
|
})
|
|
64
|
-
expect(res.headers[constants.
|
|
64
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(user.tenantId)
|
|
65
65
|
})
|
|
66
66
|
|
|
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
70
|
expect(res.text).toBe("Tenant id not set")
|
|
71
|
-
expect(res.headers[constants.
|
|
71
|
+
expect(res.headers[constants.Header.TENANT_ID]).toBe(undefined)
|
|
72
72
|
})
|
|
73
73
|
})
|
|
@@ -4,12 +4,10 @@ dbConfig.init()
|
|
|
4
4
|
import env from "../environment"
|
|
5
5
|
import controllers from "./controllers"
|
|
6
6
|
const supertest = require("supertest")
|
|
7
|
-
import {
|
|
7
|
+
import { Config } from "../constants"
|
|
8
8
|
import {
|
|
9
9
|
users,
|
|
10
10
|
tenancy,
|
|
11
|
-
Cookies,
|
|
12
|
-
Headers,
|
|
13
11
|
sessions,
|
|
14
12
|
auth,
|
|
15
13
|
constants,
|
|
@@ -131,7 +129,7 @@ class TestConfiguration {
|
|
|
131
129
|
const userRes = await this.api.users.getUser(res.userId, {
|
|
132
130
|
headers: {
|
|
133
131
|
...this.internalAPIHeaders(),
|
|
134
|
-
[constants.
|
|
132
|
+
[constants.Header.TENANT_ID]: res.tenantId,
|
|
135
133
|
},
|
|
136
134
|
})
|
|
137
135
|
|
|
@@ -188,8 +186,8 @@ class TestConfiguration {
|
|
|
188
186
|
const authCookie = auth.jwt.sign(authToken, env.JWT_SECRET)
|
|
189
187
|
return {
|
|
190
188
|
Accept: "application/json",
|
|
191
|
-
...this.cookieHeader([`${
|
|
192
|
-
[
|
|
189
|
+
...this.cookieHeader([`${constants.Cookie.Auth}=${authCookie}`]),
|
|
190
|
+
[constants.Header.CSRF_TOKEN]: CSRF_TOKEN,
|
|
193
191
|
}
|
|
194
192
|
}
|
|
195
193
|
|
|
@@ -205,7 +203,7 @@ class TestConfiguration {
|
|
|
205
203
|
}
|
|
206
204
|
|
|
207
205
|
internalAPIHeaders() {
|
|
208
|
-
return { [constants.
|
|
206
|
+
return { [constants.Header.API_KEY]: env.INTERNAL_API_KEY }
|
|
209
207
|
}
|
|
210
208
|
|
|
211
209
|
adminOnlyResponse = () => {
|
|
@@ -274,7 +272,7 @@ class TestConfiguration {
|
|
|
274
272
|
// CONFIGS - SETTINGS
|
|
275
273
|
|
|
276
274
|
async saveSettingsConfig() {
|
|
277
|
-
await this.deleteConfig(
|
|
275
|
+
await this.deleteConfig(Config.SETTINGS)
|
|
278
276
|
await this._req(
|
|
279
277
|
structures.configs.settings(),
|
|
280
278
|
null,
|
|
@@ -285,14 +283,19 @@ class TestConfiguration {
|
|
|
285
283
|
// CONFIGS - GOOGLE
|
|
286
284
|
|
|
287
285
|
async saveGoogleConfig() {
|
|
288
|
-
await this.deleteConfig(
|
|
286
|
+
await this.deleteConfig(Config.GOOGLE)
|
|
289
287
|
await this._req(structures.configs.google(), null, controllers.config.save)
|
|
290
288
|
}
|
|
291
289
|
|
|
292
290
|
// CONFIGS - OIDC
|
|
293
291
|
|
|
292
|
+
getOIDConfigCookie(configId: string) {
|
|
293
|
+
const token = auth.jwt.sign(configId, env.JWT_SECRET)
|
|
294
|
+
return this.cookieHeader([[`${constants.Cookie.OIDC_CONFIG}=${token}`]])
|
|
295
|
+
}
|
|
296
|
+
|
|
294
297
|
async saveOIDCConfig() {
|
|
295
|
-
await this.deleteConfig(
|
|
298
|
+
await this.deleteConfig(Config.OIDC)
|
|
296
299
|
const config = structures.configs.oidc()
|
|
297
300
|
|
|
298
301
|
await this._req(config, null, controllers.config.save)
|
|
@@ -302,12 +305,12 @@ class TestConfiguration {
|
|
|
302
305
|
// CONFIGS - SMTP
|
|
303
306
|
|
|
304
307
|
async saveSmtpConfig() {
|
|
305
|
-
await this.deleteConfig(
|
|
308
|
+
await this.deleteConfig(Config.SMTP)
|
|
306
309
|
await this._req(structures.configs.smtp(), null, controllers.config.save)
|
|
307
310
|
}
|
|
308
311
|
|
|
309
312
|
async saveEtherealSmtpConfig() {
|
|
310
|
-
await this.deleteConfig(
|
|
313
|
+
await this.deleteConfig(Config.SMTP)
|
|
311
314
|
await this._req(
|
|
312
315
|
structures.configs.smtpEthereal(),
|
|
313
316
|
null,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { Config } = require("../../constants")
|
|
2
2
|
const { utils } = require("@budibase/backend-core")
|
|
3
3
|
|
|
4
4
|
exports.oidc = conf => {
|
|
5
5
|
return {
|
|
6
|
-
type:
|
|
6
|
+
type: Config.OIDC,
|
|
7
7
|
config: {
|
|
8
8
|
configs: [
|
|
9
9
|
{
|
|
@@ -23,7 +23,7 @@ exports.oidc = conf => {
|
|
|
23
23
|
|
|
24
24
|
exports.google = conf => {
|
|
25
25
|
return {
|
|
26
|
-
type:
|
|
26
|
+
type: Config.GOOGLE,
|
|
27
27
|
config: {
|
|
28
28
|
clientID: "clientId",
|
|
29
29
|
clientSecret: "clientSecret",
|
|
@@ -35,7 +35,7 @@ exports.google = conf => {
|
|
|
35
35
|
|
|
36
36
|
exports.smtp = conf => {
|
|
37
37
|
return {
|
|
38
|
-
type:
|
|
38
|
+
type: Config.SMTP,
|
|
39
39
|
config: {
|
|
40
40
|
port: 12345,
|
|
41
41
|
host: "smtptesthost.com",
|
|
@@ -49,7 +49,7 @@ exports.smtp = conf => {
|
|
|
49
49
|
|
|
50
50
|
exports.smtpEthereal = () => {
|
|
51
51
|
return {
|
|
52
|
-
type:
|
|
52
|
+
type: Config.SMTP,
|
|
53
53
|
config: {
|
|
54
54
|
port: 587,
|
|
55
55
|
host: "smtp.ethereal.email",
|
|
@@ -65,7 +65,7 @@ exports.smtpEthereal = () => {
|
|
|
65
65
|
|
|
66
66
|
exports.settings = conf => {
|
|
67
67
|
return {
|
|
68
|
-
type:
|
|
68
|
+
type: Config.SETTINGS,
|
|
69
69
|
config: {
|
|
70
70
|
platformUrl: "http://localhost:10000",
|
|
71
71
|
logoUrl: "",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const fetch = require("node-fetch")
|
|
2
|
-
const {
|
|
2
|
+
const { Header } = require("@budibase/backend-core/constants")
|
|
3
3
|
const { getTenantId, isTenantIdSet } = require("@budibase/backend-core/tenancy")
|
|
4
4
|
const { checkSlashesInUrl } = require("../utilities")
|
|
5
5
|
const env = require("../environment")
|
|
@@ -9,9 +9,9 @@ async function makeAppRequest(url, method, body) {
|
|
|
9
9
|
return
|
|
10
10
|
}
|
|
11
11
|
const request = { headers: {} }
|
|
12
|
-
request.headers[
|
|
12
|
+
request.headers[Header.API_KEY] = env.INTERNAL_API_KEY
|
|
13
13
|
if (isTenantIdSet()) {
|
|
14
|
-
request.headers[
|
|
14
|
+
request.headers[Header.TENANT_ID] = getTenantId()
|
|
15
15
|
}
|
|
16
16
|
if (body) {
|
|
17
17
|
request.headers["Content-Type"] = "application/json"
|
|
@@ -1,15 +1,33 @@
|
|
|
1
|
+
import env from "../environment"
|
|
2
|
+
import { EmailTemplatePurpose, TemplateType, Config } from "../constants"
|
|
3
|
+
import { getTemplateByPurpose } from "../constants/templates"
|
|
4
|
+
import { getSettingsTemplateContext } from "./templates"
|
|
5
|
+
import { processString } from "@budibase/string-templates"
|
|
6
|
+
import { getResetPasswordCode, getInviteCode } from "./redis"
|
|
7
|
+
import { User, Database } from "@budibase/types"
|
|
8
|
+
import { tenancy, db as dbCore } from "@budibase/backend-core"
|
|
1
9
|
const nodemailer = require("nodemailer")
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
type SendEmailOpts = {
|
|
12
|
+
// workspaceId If finer grain controls being used then this will lookup config for workspace.
|
|
13
|
+
workspaceId?: string
|
|
14
|
+
// user If sending to an existing user the object can be provided, this is used in the context.
|
|
15
|
+
user: User
|
|
16
|
+
// from If sending from an address that is not what is configured in the SMTP config.
|
|
17
|
+
from?: string
|
|
18
|
+
// contents If sending a custom email then can supply contents which will be added to it.
|
|
19
|
+
contents?: string
|
|
20
|
+
// subject A custom subject can be specified if the config one is not desired.
|
|
21
|
+
subject?: string
|
|
22
|
+
// info Pass in a structure of information to be stored alongside the invitation.
|
|
23
|
+
info?: any
|
|
24
|
+
cc?: boolean
|
|
25
|
+
bcc?: boolean
|
|
26
|
+
automation?: boolean
|
|
27
|
+
}
|
|
10
28
|
|
|
11
29
|
const TEST_MODE = false
|
|
12
|
-
const TYPE =
|
|
30
|
+
const TYPE = TemplateType.EMAIL
|
|
13
31
|
|
|
14
32
|
const FULL_EMAIL_PURPOSES = [
|
|
15
33
|
EmailTemplatePurpose.INVITATION,
|
|
@@ -18,8 +36,8 @@ const FULL_EMAIL_PURPOSES = [
|
|
|
18
36
|
EmailTemplatePurpose.CUSTOM,
|
|
19
37
|
]
|
|
20
38
|
|
|
21
|
-
function createSMTPTransport(config) {
|
|
22
|
-
let options
|
|
39
|
+
function createSMTPTransport(config: any) {
|
|
40
|
+
let options: any
|
|
23
41
|
let secure = config.secure
|
|
24
42
|
// default it if not specified
|
|
25
43
|
if (secure == null) {
|
|
@@ -52,10 +70,15 @@ function createSMTPTransport(config) {
|
|
|
52
70
|
return nodemailer.createTransport(options)
|
|
53
71
|
}
|
|
54
72
|
|
|
55
|
-
async function getLinkCode(
|
|
73
|
+
async function getLinkCode(
|
|
74
|
+
purpose: EmailTemplatePurpose,
|
|
75
|
+
email: string,
|
|
76
|
+
user: User,
|
|
77
|
+
info: any = null
|
|
78
|
+
) {
|
|
56
79
|
switch (purpose) {
|
|
57
80
|
case EmailTemplatePurpose.PASSWORD_RECOVERY:
|
|
58
|
-
return getResetPasswordCode(user._id
|
|
81
|
+
return getResetPasswordCode(user._id!, info)
|
|
59
82
|
case EmailTemplatePurpose.INVITATION:
|
|
60
83
|
return getInviteCode(email, info)
|
|
61
84
|
default:
|
|
@@ -72,7 +95,12 @@ async function getLinkCode(purpose, email, user, info = null) {
|
|
|
72
95
|
* @param {string|null} contents if using a custom template can supply contents for context.
|
|
73
96
|
* @return {Promise<string>} returns the built email HTML if all provided parameters were valid.
|
|
74
97
|
*/
|
|
75
|
-
async function buildEmail(
|
|
98
|
+
async function buildEmail(
|
|
99
|
+
purpose: EmailTemplatePurpose,
|
|
100
|
+
email: string,
|
|
101
|
+
context: any,
|
|
102
|
+
{ user, contents }: any = {}
|
|
103
|
+
) {
|
|
76
104
|
// this isn't a full email
|
|
77
105
|
if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) {
|
|
78
106
|
throw `Unable to build an email of type ${purpose}`
|
|
@@ -113,15 +141,19 @@ async function buildEmail(purpose, email, context, { user, contents } = {}) {
|
|
|
113
141
|
* @param {boolean|null} automation Whether or not the configuration is being fetched for an email automation.
|
|
114
142
|
* @return {Promise<object|null>} returns the SMTP configuration if it exists
|
|
115
143
|
*/
|
|
116
|
-
async function getSmtpConfiguration(
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
async function getSmtpConfiguration(
|
|
145
|
+
db: Database,
|
|
146
|
+
workspaceId?: string,
|
|
147
|
+
automation?: boolean
|
|
148
|
+
) {
|
|
149
|
+
const params: any = {
|
|
150
|
+
type: Config.SMTP,
|
|
119
151
|
}
|
|
120
152
|
if (workspaceId) {
|
|
121
153
|
params.workspace = workspaceId
|
|
122
154
|
}
|
|
123
155
|
|
|
124
|
-
const customConfig = await getScopedConfig(db, params)
|
|
156
|
+
const customConfig = await dbCore.getScopedConfig(db, params)
|
|
125
157
|
|
|
126
158
|
if (customConfig) {
|
|
127
159
|
return customConfig
|
|
@@ -146,12 +178,12 @@ async function getSmtpConfiguration(db, workspaceId = null, automation) {
|
|
|
146
178
|
* Checks if a SMTP config exists based on passed in parameters.
|
|
147
179
|
* @return {Promise<boolean>} returns true if there is a configuration that can be used.
|
|
148
180
|
*/
|
|
149
|
-
|
|
181
|
+
export async function isEmailConfigured(workspaceId?: string) {
|
|
150
182
|
// when "testing" or smtp fallback is enabled simply return true
|
|
151
183
|
if (TEST_MODE || env.SMTP_FALLBACK_ENABLED) {
|
|
152
184
|
return true
|
|
153
185
|
}
|
|
154
|
-
const db = getGlobalDB()
|
|
186
|
+
const db = tenancy.getGlobalDB()
|
|
155
187
|
const config = await getSmtpConfiguration(db, workspaceId)
|
|
156
188
|
return config != null
|
|
157
189
|
}
|
|
@@ -161,48 +193,49 @@ exports.isEmailConfigured = async (workspaceId = null) => {
|
|
|
161
193
|
* send an email using it.
|
|
162
194
|
* @param {string} email The email address to send to.
|
|
163
195
|
* @param {string} purpose The purpose of the email being sent (e.g. reset password).
|
|
164
|
-
* @param {
|
|
165
|
-
* @param {object|undefined} user If sending to an existing user the object can be provided, this is used in the context.
|
|
166
|
-
* @param {string|undefined} from If sending from an address that is not what is configured in the SMTP config.
|
|
167
|
-
* @param {string|undefined} contents If sending a custom email then can supply contents which will be added to it.
|
|
168
|
-
* @param {string|undefined} subject A custom subject can be specified if the config one is not desired.
|
|
169
|
-
* @param {object|undefined} info Pass in a structure of information to be stored alongside the invitation.
|
|
170
|
-
* @param {boolean|undefined} disableFallback Prevent email being sent from SMTP fallback to avoid spam.
|
|
196
|
+
* @param {object} opts The options for sending the email.
|
|
171
197
|
* @return {Promise<object>} returns details about the attempt to send email, e.g. if it is successful; based on
|
|
172
198
|
* nodemailer response.
|
|
173
199
|
*/
|
|
174
|
-
|
|
175
|
-
email,
|
|
176
|
-
purpose,
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
const db = getGlobalDB()
|
|
180
|
-
let config =
|
|
200
|
+
export async function sendEmail(
|
|
201
|
+
email: string,
|
|
202
|
+
purpose: EmailTemplatePurpose,
|
|
203
|
+
opts: SendEmailOpts
|
|
204
|
+
) {
|
|
205
|
+
const db = tenancy.getGlobalDB()
|
|
206
|
+
let config =
|
|
207
|
+
(await getSmtpConfiguration(db, opts?.workspaceId, opts?.automation)) || {}
|
|
181
208
|
if (Object.keys(config).length === 0 && !TEST_MODE) {
|
|
182
209
|
throw "Unable to find SMTP configuration."
|
|
183
210
|
}
|
|
184
211
|
const transport = createSMTPTransport(config)
|
|
185
212
|
// if there is a link code needed this will retrieve it
|
|
186
|
-
const code = await getLinkCode(purpose, email, user, info)
|
|
187
|
-
|
|
213
|
+
const code = await getLinkCode(purpose, email, opts.user, opts?.info)
|
|
214
|
+
let context
|
|
215
|
+
if (code) {
|
|
216
|
+
context = await getSettingsTemplateContext(purpose, code)
|
|
217
|
+
}
|
|
188
218
|
|
|
189
|
-
let message = {
|
|
190
|
-
from: from || config.from,
|
|
219
|
+
let message: any = {
|
|
220
|
+
from: opts?.from || config.from,
|
|
191
221
|
html: await buildEmail(purpose, email, context, {
|
|
192
|
-
user,
|
|
193
|
-
contents,
|
|
222
|
+
user: opts?.user,
|
|
223
|
+
contents: opts?.contents,
|
|
194
224
|
}),
|
|
195
225
|
}
|
|
196
226
|
|
|
197
227
|
message = {
|
|
198
228
|
...message,
|
|
199
229
|
to: email,
|
|
200
|
-
cc: cc,
|
|
201
|
-
bcc: bcc,
|
|
230
|
+
cc: opts?.cc,
|
|
231
|
+
bcc: opts?.bcc,
|
|
202
232
|
}
|
|
203
233
|
|
|
204
|
-
if (subject || config.subject) {
|
|
205
|
-
message.subject = await processString(
|
|
234
|
+
if (opts?.subject || config.subject) {
|
|
235
|
+
message.subject = await processString(
|
|
236
|
+
opts?.subject || config.subject,
|
|
237
|
+
context
|
|
238
|
+
)
|
|
206
239
|
}
|
|
207
240
|
const response = await transport.sendMail(message)
|
|
208
241
|
if (TEST_MODE) {
|
|
@@ -216,7 +249,7 @@ exports.sendEmail = async (
|
|
|
216
249
|
* @param {object} config an SMTP configuration - this is based on the nodemailer API.
|
|
217
250
|
* @return {Promise<boolean>} returns true if the configuration is valid.
|
|
218
251
|
*/
|
|
219
|
-
|
|
252
|
+
export async function verifyConfig(config: any) {
|
|
220
253
|
const transport = createSMTPTransport(config)
|
|
221
254
|
await transport.verify()
|
|
222
255
|
}
|