@budibase/worker 2.2.25 → 2.2.27-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +1 -1
- package/coverage/clover.xml +1393 -1364
- package/coverage/coverage-final.json +83 -77
- package/coverage/lcov-report/index.html +133 -133
- package/coverage/lcov-report/src/api/controllers/global/auth.ts.html +52 -52
- package/coverage/lcov-report/src/api/controllers/global/configs.ts.html +161 -218
- package/coverage/lcov-report/src/api/controllers/global/email.ts.html +4 -4
- package/coverage/lcov-report/src/api/controllers/global/events.ts.html +136 -0
- package/coverage/lcov-report/src/api/controllers/global/index.html +85 -70
- package/coverage/lcov-report/src/api/controllers/global/license.ts.html +16 -16
- package/coverage/lcov-report/src/api/controllers/global/roles.ts.html +77 -77
- package/coverage/lcov-report/src/api/controllers/global/self.ts.html +20 -20
- package/coverage/lcov-report/src/api/controllers/global/templates.ts.html +54 -54
- package/coverage/lcov-report/src/api/controllers/global/users.ts.html +82 -43
- package/coverage/lcov-report/src/api/controllers/global/workspaces.ts.html +9 -9
- package/coverage/lcov-report/src/api/controllers/system/accounts.ts.html +5 -5
- package/coverage/lcov-report/src/api/controllers/system/environment.ts.html +4 -4
- package/coverage/lcov-report/src/api/controllers/system/index.html +11 -11
- package/coverage/lcov-report/src/api/controllers/system/migrations.ts.html +5 -5
- package/coverage/lcov-report/src/api/controllers/system/restore.ts.html +4 -4
- package/coverage/lcov-report/src/api/controllers/system/status.ts.html +5 -5
- package/coverage/lcov-report/src/api/controllers/system/tenants.ts.html +7 -7
- package/coverage/lcov-report/src/api/index.html +1 -1
- package/coverage/lcov-report/src/api/index.ts.html +37 -25
- package/coverage/lcov-report/src/api/routes/global/auth.ts.html +14 -14
- package/coverage/lcov-report/src/api/routes/global/configs.ts.html +25 -25
- package/coverage/lcov-report/src/api/routes/global/email.ts.html +13 -13
- package/coverage/lcov-report/src/api/routes/global/events.ts.html +109 -0
- package/coverage/lcov-report/src/api/routes/global/index.html +37 -22
- package/coverage/lcov-report/src/api/routes/global/license.ts.html +9 -9
- package/coverage/lcov-report/src/api/routes/global/roles.ts.html +10 -10
- package/coverage/lcov-report/src/api/routes/global/self.ts.html +11 -11
- package/coverage/lcov-report/src/api/routes/global/templates.ts.html +14 -14
- package/coverage/lcov-report/src/api/routes/global/users.ts.html +62 -20
- package/coverage/lcov-report/src/api/routes/global/workspaces.ts.html +12 -12
- package/coverage/lcov-report/src/api/routes/index.html +7 -7
- package/coverage/lcov-report/src/api/routes/index.ts.html +29 -23
- package/coverage/lcov-report/src/api/routes/system/accounts.ts.html +10 -10
- package/coverage/lcov-report/src/api/routes/system/environment.ts.html +9 -9
- package/coverage/lcov-report/src/api/routes/system/index.html +15 -15
- package/coverage/lcov-report/src/api/routes/system/migrations.ts.html +10 -10
- package/coverage/lcov-report/src/api/routes/system/restore.ts.html +9 -9
- package/coverage/lcov-report/src/api/routes/system/status.ts.html +9 -9
- package/coverage/lcov-report/src/api/routes/system/tenants.ts.html +10 -10
- package/coverage/lcov-report/src/api/routes/validation/index.html +3 -3
- package/coverage/lcov-report/src/api/routes/validation/index.ts.html +2 -2
- package/coverage/lcov-report/src/api/routes/validation/users.ts.html +14 -14
- package/coverage/lcov-report/src/constants/index.html +17 -17
- package/coverage/lcov-report/src/constants/index.ts.html +77 -53
- package/coverage/lcov-report/src/constants/templates/index.html +19 -19
- package/coverage/lcov-report/src/constants/templates/index.ts.html +42 -42
- package/coverage/lcov-report/src/db/index.html +3 -3
- package/coverage/lcov-report/src/db/index.ts.html +10 -10
- package/coverage/lcov-report/src/environment.ts.html +44 -29
- package/coverage/lcov-report/src/index.html +27 -27
- package/coverage/lcov-report/src/index.ts.html +55 -55
- package/coverage/lcov-report/src/middleware/cloudRestricted.ts.html +5 -5
- package/coverage/lcov-report/src/middleware/index.html +1 -1
- package/coverage/lcov-report/src/migrations/functions/globalInfoSyncUsers.ts.html +9 -9
- package/coverage/lcov-report/src/migrations/functions/index.html +11 -11
- package/coverage/lcov-report/src/migrations/index.html +15 -15
- package/coverage/lcov-report/src/migrations/index.ts.html +27 -27
- package/coverage/lcov-report/src/sdk/accounts/accounts.ts.html +13 -13
- package/coverage/lcov-report/src/sdk/accounts/index.html +13 -13
- package/coverage/lcov-report/src/sdk/accounts/index.ts.html +2 -2
- package/coverage/lcov-report/src/sdk/index.html +5 -5
- package/coverage/lcov-report/src/sdk/index.ts.html +6 -6
- package/coverage/lcov-report/src/sdk/users/events.ts.html +82 -58
- package/coverage/lcov-report/src/sdk/users/index.html +29 -29
- package/coverage/lcov-report/src/sdk/users/index.ts.html +2 -2
- package/coverage/lcov-report/src/sdk/users/users.ts.html +176 -119
- package/coverage/lcov-report/src/tests/TestConfiguration.ts.html +119 -95
- package/coverage/lcov-report/src/tests/api/accounts.ts.html +7 -7
- package/coverage/lcov-report/src/tests/api/auth.ts.html +8 -8
- package/coverage/lcov-report/src/tests/api/base.ts.html +5 -5
- package/coverage/lcov-report/src/tests/api/configs.ts.html +9 -9
- package/coverage/lcov-report/src/tests/api/email.ts.html +6 -6
- package/coverage/lcov-report/src/tests/api/environment.ts.html +6 -6
- package/coverage/lcov-report/src/tests/api/groups.ts.html +163 -0
- package/coverage/lcov-report/src/tests/api/index.html +91 -31
- package/coverage/lcov-report/src/tests/api/index.ts.html +62 -29
- package/coverage/lcov-report/src/tests/api/license.ts.html +136 -0
- package/coverage/lcov-report/src/tests/api/migrations.ts.html +8 -8
- package/coverage/lcov-report/src/tests/api/restore.ts.html +7 -7
- package/coverage/lcov-report/src/tests/api/roles.ts.html +181 -0
- package/coverage/lcov-report/src/tests/api/self.ts.html +7 -7
- package/coverage/lcov-report/src/tests/api/status.ts.html +6 -6
- package/coverage/lcov-report/src/tests/api/templates.ts.html +175 -0
- package/coverage/lcov-report/src/tests/api/tenants.ts.html +10 -10
- package/coverage/lcov-report/src/tests/api/users.ts.html +28 -25
- package/coverage/lcov-report/src/tests/controllers.ts.html +14 -14
- package/coverage/lcov-report/src/tests/index.html +34 -34
- package/coverage/lcov-report/src/tests/index.ts.html +19 -55
- package/coverage/lcov-report/src/tests/mocks/{email.js.html → email.ts.html} +5 -5
- package/coverage/lcov-report/src/tests/mocks/index.html +6 -6
- package/coverage/lcov-report/src/tests/mocks/index.ts.html +10 -10
- package/coverage/lcov-report/src/tests/structures/configs.ts.html +11 -11
- package/coverage/lcov-report/src/tests/structures/groups.ts.html +15 -15
- package/coverage/lcov-report/src/tests/structures/index.html +25 -25
- package/coverage/lcov-report/src/tests/structures/index.ts.html +17 -17
- package/coverage/lcov-report/src/tests/structures/users.ts.html +16 -16
- package/coverage/lcov-report/src/utilities/appService.ts.html +45 -18
- package/coverage/lcov-report/src/utilities/email.ts.html +28 -28
- package/coverage/lcov-report/src/utilities/fileSystem.ts.html +4 -4
- package/coverage/lcov-report/src/utilities/index.html +27 -27
- package/coverage/lcov-report/src/utilities/index.ts.html +2 -2
- package/coverage/lcov-report/src/utilities/redis.ts.html +20 -20
- package/coverage/lcov-report/src/utilities/templates.ts.html +6 -6
- package/coverage/lcov-report/src/utilities/users.ts.html +3 -3
- package/coverage/lcov.info +2777 -2582
- package/jest.config.ts +7 -2
- package/package.json +10 -7
- package/scripts/dev/manage.js +2 -2
- package/src/api/controllers/global/auth.ts +1 -1
- package/src/api/controllers/global/configs.ts +112 -131
- package/src/api/controllers/global/events.ts +17 -0
- package/src/api/controllers/global/users.ts +14 -1
- package/src/api/index.ts +4 -0
- package/src/api/routes/global/auth.ts +1 -1
- package/src/api/routes/global/configs.ts +7 -7
- package/src/api/routes/global/email.ts +1 -1
- package/src/api/routes/global/events.ts +8 -0
- package/src/api/routes/global/license.ts +1 -1
- package/src/api/routes/global/roles.ts +1 -1
- package/src/api/routes/global/self.ts +1 -1
- package/src/api/routes/global/templates.ts +1 -1
- package/src/api/routes/global/tests/groups.spec.ts +58 -0
- package/src/api/routes/global/tests/license.spec.ts +0 -2
- package/src/api/routes/global/tests/roles.spec.ts +66 -5
- package/src/api/routes/global/tests/templates.spec.ts +81 -9
- package/src/api/routes/global/tests/users.spec.ts +2 -2
- package/src/api/routes/global/users.ts +15 -1
- package/src/api/routes/global/workspaces.ts +1 -1
- package/src/api/routes/index.ts +2 -0
- package/src/api/routes/system/accounts.ts +1 -1
- package/src/api/routes/system/environment.ts +1 -1
- package/src/api/routes/system/migrations.ts +1 -1
- package/src/api/routes/system/restore.ts +1 -1
- package/src/api/routes/system/status.ts +1 -1
- package/src/api/routes/system/tenants.ts +1 -1
- package/src/api/routes/system/tests/environment.spec.ts +1 -1
- package/src/constants/index.ts +13 -5
- package/src/db/index.ts +1 -1
- package/src/environment.ts +6 -1
- package/src/index.ts +5 -5
- package/src/middleware/cloudRestricted.ts +1 -1
- package/src/sdk/users/events.ts +8 -0
- package/src/sdk/users/users.ts +23 -4
- package/src/tests/TestConfiguration.ts +11 -3
- package/src/tests/api/groups.ts +26 -0
- package/src/tests/api/index.ts +12 -1
- package/src/tests/api/license.ts +17 -0
- package/src/tests/api/roles.ts +32 -0
- package/src/tests/api/templates.ts +30 -0
- package/src/tests/api/users.ts +2 -1
- package/src/tests/index.ts +6 -18
- package/src/tests/jestEnv.ts +11 -0
- package/src/tests/jestSetup.ts +3 -15
- package/src/tests/mocks/{email.js → email.ts} +1 -1
- package/src/tests/mocks/index.ts +4 -4
- package/src/tests/structures/configs.ts +2 -2
- package/src/tests/structures/groups.ts +1 -1
- package/src/tests/structures/index.ts +4 -4
- package/src/tests/structures/users.ts +1 -1
- package/src/utilities/appService.ts +12 -3
- package/tsconfig.json +2 -2
|
@@ -1,11 +1,47 @@
|
|
|
1
|
-
import { TestConfiguration } from "../../../../tests"
|
|
1
|
+
import { structures, TestConfiguration } from "../../../../tests"
|
|
2
|
+
import { context, db, permissions, roles } from "@budibase/backend-core"
|
|
3
|
+
import { Mock } from "jest-mock"
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
jest.mock("@budibase/backend-core", () => {
|
|
6
|
+
const core = jest.requireActual("@budibase/backend-core")
|
|
7
|
+
return {
|
|
8
|
+
...core,
|
|
9
|
+
db: {
|
|
10
|
+
...core.db,
|
|
11
|
+
},
|
|
12
|
+
context: {
|
|
13
|
+
...core.context,
|
|
14
|
+
getAppDB: jest.fn(),
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const appDb = db.getDB("app_test")
|
|
20
|
+
const mockAppDB = context.getAppDB as Mock
|
|
21
|
+
mockAppDB.mockReturnValue(appDb)
|
|
22
|
+
|
|
23
|
+
async function addAppMetadata() {
|
|
24
|
+
await appDb.put({
|
|
25
|
+
_id: "app_metadata",
|
|
26
|
+
appId: "app_test",
|
|
27
|
+
name: "New App",
|
|
28
|
+
version: "version",
|
|
29
|
+
url: "url",
|
|
30
|
+
})
|
|
31
|
+
}
|
|
4
32
|
|
|
5
33
|
describe("/api/global/roles", () => {
|
|
6
34
|
const config = new TestConfiguration()
|
|
35
|
+
const role = new roles.Role(
|
|
36
|
+
db.generateRoleID("newRole"),
|
|
37
|
+
roles.BUILTIN_ROLE_IDS.BASIC,
|
|
38
|
+
permissions.BuiltinPermissionID.READ_ONLY
|
|
39
|
+
)
|
|
7
40
|
|
|
8
41
|
beforeAll(async () => {
|
|
42
|
+
console.debug(role)
|
|
43
|
+
appDb.put(role)
|
|
44
|
+
await addAppMetadata()
|
|
9
45
|
await config.beforeAll()
|
|
10
46
|
})
|
|
11
47
|
|
|
@@ -18,10 +54,35 @@ describe("/api/global/roles", () => {
|
|
|
18
54
|
})
|
|
19
55
|
|
|
20
56
|
describe("GET /api/global/roles", () => {
|
|
21
|
-
it("retrieves roles", () => {
|
|
57
|
+
it("retrieves roles", async () => {
|
|
58
|
+
const res = await config.api.roles.get()
|
|
59
|
+
expect(res.body).toBeDefined()
|
|
60
|
+
expect(res.body["app_test"].roles.length).toEqual(5)
|
|
61
|
+
expect(res.body["app_test"].roles.map((r: any) => r._id)).toContain(
|
|
62
|
+
role._id
|
|
63
|
+
)
|
|
64
|
+
})
|
|
22
65
|
})
|
|
23
66
|
|
|
24
|
-
describe("GET
|
|
67
|
+
describe("GET api/global/roles/:appId", () => {
|
|
68
|
+
it("finds a role by appId", async () => {
|
|
69
|
+
const res = await config.api.roles.find("app_test")
|
|
70
|
+
expect(res.body).toBeDefined()
|
|
71
|
+
expect(res.body.name).toEqual("New App")
|
|
72
|
+
})
|
|
73
|
+
})
|
|
25
74
|
|
|
26
|
-
describe("DELETE /api/global/roles/:appId", () => {
|
|
75
|
+
describe("DELETE /api/global/roles/:appId", () => {
|
|
76
|
+
it("removes an app role", async () => {
|
|
77
|
+
let user = structures.users.user()
|
|
78
|
+
user.roles = {
|
|
79
|
+
app_test: "role1",
|
|
80
|
+
}
|
|
81
|
+
const userResponse = await config.createUser(user)
|
|
82
|
+
const res = await config.api.roles.remove("app_test")
|
|
83
|
+
const updatedUser = await config.api.users.getUser(userResponse._id!)
|
|
84
|
+
expect(updatedUser.body.roles).not.toHaveProperty("app_test")
|
|
85
|
+
expect(res.body.message).toEqual("App role removed from all users")
|
|
86
|
+
})
|
|
87
|
+
})
|
|
27
88
|
})
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EmailTemplatePurpose,
|
|
3
|
+
TemplateMetadata,
|
|
4
|
+
TemplateType,
|
|
5
|
+
} from "../../../../constants"
|
|
1
6
|
import { TestConfiguration } from "../../../../tests"
|
|
2
7
|
|
|
3
8
|
// TODO
|
|
@@ -18,18 +23,85 @@ describe("/api/global/template", () => {
|
|
|
18
23
|
})
|
|
19
24
|
|
|
20
25
|
describe("GET /api/global/template/definitions", () => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
describe("POST /api/global/template", () => {})
|
|
26
|
+
describe("retrieves definitions", () => {
|
|
27
|
+
it("checks description definitions", async () => {
|
|
28
|
+
let result = await config.api.templates.definitions()
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
expect(result.body.info[EmailTemplatePurpose.BASE].description).toEqual(
|
|
31
|
+
TemplateMetadata[TemplateType.EMAIL][0].description
|
|
32
|
+
)
|
|
33
|
+
expect(
|
|
34
|
+
result.body.info[EmailTemplatePurpose.PASSWORD_RECOVERY].description
|
|
35
|
+
).toEqual(TemplateMetadata[TemplateType.EMAIL][1].description)
|
|
36
|
+
expect(
|
|
37
|
+
result.body.info[EmailTemplatePurpose.WELCOME].description
|
|
38
|
+
).toEqual(TemplateMetadata[TemplateType.EMAIL][2].description)
|
|
39
|
+
expect(
|
|
40
|
+
result.body.info[EmailTemplatePurpose.INVITATION].description
|
|
41
|
+
).toEqual(TemplateMetadata[TemplateType.EMAIL][3].description)
|
|
42
|
+
expect(
|
|
43
|
+
result.body.info[EmailTemplatePurpose.CUSTOM].description
|
|
44
|
+
).toEqual(TemplateMetadata[TemplateType.EMAIL][4].description)
|
|
45
|
+
})
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
it("checks description bindings", async () => {
|
|
48
|
+
let result = await config.api.templates.definitions()
|
|
29
49
|
|
|
30
|
-
|
|
50
|
+
expect(result.body.bindings[EmailTemplatePurpose.BASE]).toEqual(
|
|
51
|
+
TemplateMetadata[TemplateType.EMAIL][0].bindings
|
|
52
|
+
)
|
|
53
|
+
expect(
|
|
54
|
+
result.body.bindings[EmailTemplatePurpose.PASSWORD_RECOVERY]
|
|
55
|
+
).toEqual(TemplateMetadata[TemplateType.EMAIL][1].bindings)
|
|
56
|
+
expect(result.body.bindings[EmailTemplatePurpose.WELCOME]).toEqual(
|
|
57
|
+
TemplateMetadata[TemplateType.EMAIL][2].bindings
|
|
58
|
+
)
|
|
59
|
+
expect(result.body.bindings[EmailTemplatePurpose.INVITATION]).toEqual(
|
|
60
|
+
TemplateMetadata[TemplateType.EMAIL][3].bindings
|
|
61
|
+
)
|
|
62
|
+
expect(result.body.bindings[EmailTemplatePurpose.CUSTOM]).toEqual(
|
|
63
|
+
TemplateMetadata[TemplateType.EMAIL][4].bindings
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
31
68
|
|
|
32
|
-
describe("
|
|
69
|
+
describe("POST /api/global/template", () => {
|
|
70
|
+
it("adds a new template", async () => {
|
|
71
|
+
let purpose = "base"
|
|
72
|
+
let contents = "Test contents"
|
|
73
|
+
let updatedTemplate = {
|
|
74
|
+
contents: contents,
|
|
75
|
+
purpose: purpose,
|
|
76
|
+
type: "email",
|
|
77
|
+
}
|
|
78
|
+
await config.api.templates.saveTemplate(updatedTemplate)
|
|
79
|
+
let res = await config.api.templates.getTemplate()
|
|
80
|
+
let newTemplate = res.body.find((t: any) => (t.purpose = purpose))
|
|
81
|
+
expect(newTemplate.contents).toEqual(contents)
|
|
82
|
+
})
|
|
83
|
+
})
|
|
33
84
|
|
|
34
|
-
describe("
|
|
85
|
+
describe("GET /api/global/template", () => {
|
|
86
|
+
it("fetches templates", async () => {
|
|
87
|
+
let res = await config.api.templates.getTemplate()
|
|
88
|
+
expect(
|
|
89
|
+
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.BASE)
|
|
90
|
+
).toBeDefined()
|
|
91
|
+
expect(
|
|
92
|
+
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.CUSTOM)
|
|
93
|
+
).toBeDefined()
|
|
94
|
+
expect(
|
|
95
|
+
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.INVITATION)
|
|
96
|
+
).toBeDefined()
|
|
97
|
+
expect(
|
|
98
|
+
res.body.find(
|
|
99
|
+
(t: any) => t.purpose === EmailTemplatePurpose.PASSWORD_RECOVERY
|
|
100
|
+
)
|
|
101
|
+
).toBeDefined()
|
|
102
|
+
expect(
|
|
103
|
+
res.body.find((t: any) => t.purpose === EmailTemplatePurpose.WELCOME)
|
|
104
|
+
).toBeDefined()
|
|
105
|
+
})
|
|
106
|
+
})
|
|
35
107
|
})
|
|
@@ -116,7 +116,7 @@ describe("/api/global/users", () => {
|
|
|
116
116
|
|
|
117
117
|
it("should ignore users existing in other tenants", async () => {
|
|
118
118
|
const user = await config.createUser()
|
|
119
|
-
jest.
|
|
119
|
+
jest.clearAllMocks()
|
|
120
120
|
|
|
121
121
|
await tenancy.doInTenant(TENANT_1, async () => {
|
|
122
122
|
const response = await config.api.users.bulkCreateUsers([user])
|
|
@@ -229,7 +229,7 @@ describe("/api/global/users", () => {
|
|
|
229
229
|
|
|
230
230
|
it("should not be able to create user that exists in other tenant", async () => {
|
|
231
231
|
const user = await config.createUser()
|
|
232
|
-
jest.
|
|
232
|
+
jest.clearAllMocks()
|
|
233
233
|
|
|
234
234
|
await tenancy.doInTenant(TENANT_1, async () => {
|
|
235
235
|
delete user._id
|
|
@@ -38,6 +38,13 @@ function buildInviteMultipleValidation() {
|
|
|
38
38
|
))
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
function buildInviteLookupValidation() {
|
|
42
|
+
// prettier-ignore
|
|
43
|
+
return auth.joiValidator.params(Joi.object({
|
|
44
|
+
code: Joi.string().required()
|
|
45
|
+
}).unknown(true))
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
const createUserAdminOnly = (ctx: any, next: any) => {
|
|
42
49
|
if (!ctx.request.body._id) {
|
|
43
50
|
return auth.adminOnly(ctx, next)
|
|
@@ -51,6 +58,8 @@ function buildInviteAcceptValidation() {
|
|
|
51
58
|
return auth.joiValidator.body(Joi.object({
|
|
52
59
|
inviteCode: Joi.string().required(),
|
|
53
60
|
password: Joi.string().required(),
|
|
61
|
+
firstName: Joi.string().required(),
|
|
62
|
+
lastName: Joi.string().optional(),
|
|
54
63
|
}).required().unknown(true))
|
|
55
64
|
}
|
|
56
65
|
|
|
@@ -91,6 +100,11 @@ router
|
|
|
91
100
|
)
|
|
92
101
|
|
|
93
102
|
// non-global endpoints
|
|
103
|
+
.get(
|
|
104
|
+
"/api/global/users/invite/:code",
|
|
105
|
+
buildInviteLookupValidation(),
|
|
106
|
+
controller.checkInvite
|
|
107
|
+
)
|
|
94
108
|
.post(
|
|
95
109
|
"/api/global/users/invite/accept",
|
|
96
110
|
buildInviteAcceptValidation(),
|
|
@@ -113,4 +127,4 @@ router
|
|
|
113
127
|
selfController.updateSelf
|
|
114
128
|
)
|
|
115
129
|
|
|
116
|
-
export
|
|
130
|
+
export default router
|
package/src/api/routes/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import templateRoutes from "./global/templates"
|
|
|
7
7
|
import emailRoutes from "./global/email"
|
|
8
8
|
import authRoutes from "./global/auth"
|
|
9
9
|
import roleRoutes from "./global/roles"
|
|
10
|
+
import eventRoutes from "./global/events"
|
|
10
11
|
import environmentRoutes from "./system/environment"
|
|
11
12
|
import tenantsRoutes from "./system/tenants"
|
|
12
13
|
import statusRoutes from "./system/status"
|
|
@@ -34,4 +35,5 @@ export const routes: Router[] = [
|
|
|
34
35
|
migrationRoutes,
|
|
35
36
|
accountRoutes,
|
|
36
37
|
restoreRoutes,
|
|
38
|
+
eventRoutes,
|
|
37
39
|
]
|
package/src/constants/index.ts
CHANGED
|
@@ -27,6 +27,14 @@ export enum EmailTemplatePurpose {
|
|
|
27
27
|
CUSTOM = "custom",
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export enum TemplateMetadataNames {
|
|
31
|
+
BASE = "Base format",
|
|
32
|
+
PASSWORD_RECOVERY = "Password recovery",
|
|
33
|
+
WELCOME = "User welcome",
|
|
34
|
+
INVITATION = "User invitation",
|
|
35
|
+
CUSTOM = "Custom",
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
export enum InternalTemplateBinding {
|
|
31
39
|
PLATFORM_URL = "platformUrl",
|
|
32
40
|
COMPANY = "company",
|
|
@@ -93,7 +101,7 @@ export const TemplateBindings = {
|
|
|
93
101
|
export const TemplateMetadata = {
|
|
94
102
|
[TemplateType.EMAIL]: [
|
|
95
103
|
{
|
|
96
|
-
name:
|
|
104
|
+
name: TemplateMetadataNames.BASE,
|
|
97
105
|
description:
|
|
98
106
|
"This is the base template, all others are based on it. The {{ body }} will be replaced with another email template.",
|
|
99
107
|
category: "miscellaneous",
|
|
@@ -110,7 +118,7 @@ export const TemplateMetadata = {
|
|
|
110
118
|
],
|
|
111
119
|
},
|
|
112
120
|
{
|
|
113
|
-
name:
|
|
121
|
+
name: TemplateMetadataNames.PASSWORD_RECOVERY,
|
|
114
122
|
description:
|
|
115
123
|
"When a user requests a password reset they will receive an email built with this template.",
|
|
116
124
|
category: "user management",
|
|
@@ -129,7 +137,7 @@ export const TemplateMetadata = {
|
|
|
129
137
|
],
|
|
130
138
|
},
|
|
131
139
|
{
|
|
132
|
-
name:
|
|
140
|
+
name: TemplateMetadataNames.WELCOME,
|
|
133
141
|
description:
|
|
134
142
|
"When a new user is added they will be sent a welcome email using this template.",
|
|
135
143
|
category: "user management",
|
|
@@ -137,7 +145,7 @@ export const TemplateMetadata = {
|
|
|
137
145
|
bindings: [],
|
|
138
146
|
},
|
|
139
147
|
{
|
|
140
|
-
name:
|
|
148
|
+
name: TemplateMetadataNames.INVITATION,
|
|
141
149
|
description:
|
|
142
150
|
"When inviting a user via the email on-boarding this template will be used.",
|
|
143
151
|
category: "user management",
|
|
@@ -156,7 +164,7 @@ export const TemplateMetadata = {
|
|
|
156
164
|
],
|
|
157
165
|
},
|
|
158
166
|
{
|
|
159
|
-
name:
|
|
167
|
+
name: TemplateMetadataNames.CUSTOM,
|
|
160
168
|
description:
|
|
161
169
|
"A custom template, this is currently used for SMTP email actions in automations.",
|
|
162
170
|
category: "automations",
|
package/src/db/index.ts
CHANGED
package/src/environment.ts
CHANGED
|
@@ -91,6 +91,11 @@ for (let [key, value] of Object.entries(environment)) {
|
|
|
91
91
|
// @ts-ignore
|
|
92
92
|
environment[key] = 0
|
|
93
93
|
}
|
|
94
|
+
// handle the edge case of "false" to disable an environment variable
|
|
95
|
+
if (value === "false") {
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
environment[key] = 0
|
|
98
|
+
}
|
|
94
99
|
}
|
|
95
100
|
|
|
96
|
-
export
|
|
101
|
+
export default environment
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { Event } from "@sentry/types/dist/event"
|
|
|
14
14
|
import Application from "koa"
|
|
15
15
|
import { bootstrap } from "global-agent"
|
|
16
16
|
import * as db from "./db"
|
|
17
|
-
import { auth, logging, events,
|
|
17
|
+
import { auth, logging, events, middleware } from "@budibase/backend-core"
|
|
18
18
|
db.init()
|
|
19
19
|
import Koa from "koa"
|
|
20
20
|
import koaBody from "koa-body"
|
|
@@ -24,7 +24,7 @@ import * as redis from "./utilities/redis"
|
|
|
24
24
|
const Sentry = require("@sentry/node")
|
|
25
25
|
const koaSession = require("koa-session")
|
|
26
26
|
const logger = require("koa-pino-logger")
|
|
27
|
-
|
|
27
|
+
import destroyable from "server-destroy"
|
|
28
28
|
|
|
29
29
|
// this will setup http and https proxies form env variables
|
|
30
30
|
bootstrap()
|
|
@@ -36,7 +36,8 @@ app.keys = ["secret", "key"]
|
|
|
36
36
|
// set up top level koa middleware
|
|
37
37
|
app.use(koaBody({ multipart: true }))
|
|
38
38
|
app.use(koaSession(app))
|
|
39
|
-
app.use(
|
|
39
|
+
app.use(middleware.logging)
|
|
40
|
+
app.use(logger(logging.pinoSettings()))
|
|
40
41
|
|
|
41
42
|
// authentication
|
|
42
43
|
app.use(auth.passport.initialize())
|
|
@@ -79,11 +80,10 @@ server.on("close", async () => {
|
|
|
79
80
|
|
|
80
81
|
const shutdown = () => {
|
|
81
82
|
server.close()
|
|
82
|
-
// @ts-ignore
|
|
83
83
|
server.destroy()
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
export
|
|
86
|
+
export default server.listen(parseInt(env.PORT || "4002"), async () => {
|
|
87
87
|
console.log(`Worker running on ${JSON.stringify(server.address())}`)
|
|
88
88
|
await redis.init()
|
|
89
89
|
})
|
|
@@ -6,7 +6,7 @@ import { BBContext } from "@budibase/types"
|
|
|
6
6
|
* This is a restricted endpoint in the cloud.
|
|
7
7
|
* Ensure that the correct API key has been supplied.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export default async (ctx: BBContext, next: any) => {
|
|
10
10
|
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
11
11
|
const apiKey = ctx.request.headers[constants.Header.API_KEY]
|
|
12
12
|
if (apiKey !== env.INTERNAL_API_KEY) {
|
package/src/sdk/users/events.ts
CHANGED
|
@@ -73,6 +73,10 @@ export const handleSaveEvents = async (
|
|
|
73
73
|
await events.user.permissionAdminRemoved(user)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
if (isOnboardingComplete(user, existingUser)) {
|
|
77
|
+
await events.user.onboardingComplete(user)
|
|
78
|
+
}
|
|
79
|
+
|
|
76
80
|
if (
|
|
77
81
|
!existingUser.forceResetPassword &&
|
|
78
82
|
user.forceResetPassword &&
|
|
@@ -114,6 +118,10 @@ const isRemovingAdmin = (user: any, existingUser: any) => {
|
|
|
114
118
|
return isRemovingPermission(user, existingUser, isAdmin)
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
const isOnboardingComplete = (user: any, existingUser: any) => {
|
|
122
|
+
return !existingUser?.onboardedAt && typeof user.onboardedAt === "string"
|
|
123
|
+
}
|
|
124
|
+
|
|
117
125
|
/**
|
|
118
126
|
* Check if a permission is being added to a new or existing user.
|
|
119
127
|
*/
|
package/src/sdk/users/users.ts
CHANGED
|
@@ -25,11 +25,13 @@ import {
|
|
|
25
25
|
InviteUsersRequest,
|
|
26
26
|
InviteUsersResponse,
|
|
27
27
|
MigrationType,
|
|
28
|
+
PlatformUser,
|
|
28
29
|
PlatformUserByEmail,
|
|
29
30
|
RowResponse,
|
|
30
31
|
SearchUsersRequest,
|
|
31
32
|
User,
|
|
32
33
|
ThirdPartyUser,
|
|
34
|
+
isUser,
|
|
33
35
|
} from "@budibase/types"
|
|
34
36
|
import { sendEmail } from "../../utilities/email"
|
|
35
37
|
import { EmailTemplatePurpose } from "../../constants"
|
|
@@ -153,10 +155,26 @@ const buildUser = async (
|
|
|
153
155
|
return fullUser
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
// lookup, could be email or userId, either will return a doc
|
|
159
|
+
export const getPlatformUser = async (
|
|
160
|
+
identifier: string
|
|
161
|
+
): Promise<PlatformUser | null> => {
|
|
162
|
+
// use the view here and allow to find anyone regardless of casing
|
|
163
|
+
// Use lowercase to ensure email login is case insensitive
|
|
164
|
+
const response = dbUtils.queryPlatformView(
|
|
165
|
+
ViewName.PLATFORM_USERS_LOWERCASE,
|
|
166
|
+
{
|
|
167
|
+
keys: [identifier.toLowerCase()],
|
|
168
|
+
include_docs: true,
|
|
169
|
+
}
|
|
170
|
+
) as Promise<PlatformUser>
|
|
171
|
+
return response
|
|
172
|
+
}
|
|
173
|
+
|
|
156
174
|
const validateUniqueUser = async (email: string, tenantId: string) => {
|
|
157
175
|
// check budibase users in other tenants
|
|
158
176
|
if (env.MULTI_TENANCY) {
|
|
159
|
-
const tenantUser = await
|
|
177
|
+
const tenantUser = await getPlatformUser(email)
|
|
160
178
|
if (tenantUser != null && tenantUser.tenantId !== tenantId) {
|
|
161
179
|
throw `Unavailable`
|
|
162
180
|
}
|
|
@@ -248,8 +266,9 @@ export const save = async (
|
|
|
248
266
|
await eventHelpers.handleSaveEvents(builtUser, dbUser)
|
|
249
267
|
await addTenant(tenantId, _id, email)
|
|
250
268
|
await cache.user.invalidateUser(response.id)
|
|
269
|
+
|
|
251
270
|
// let server know to sync user
|
|
252
|
-
await apps.syncUserInApps(_id)
|
|
271
|
+
await apps.syncUserInApps(_id, dbUser)
|
|
253
272
|
|
|
254
273
|
await Promise.all(groupPromises)
|
|
255
274
|
|
|
@@ -555,7 +574,7 @@ export const destroy = async (id: string, currentUser: any) => {
|
|
|
555
574
|
await cache.user.invalidateUser(userId)
|
|
556
575
|
await sessions.invalidateSessions(userId, { reason: "deletion" })
|
|
557
576
|
// let server know to sync user
|
|
558
|
-
await apps.syncUserInApps(userId)
|
|
577
|
+
await apps.syncUserInApps(userId, dbUser)
|
|
559
578
|
}
|
|
560
579
|
|
|
561
580
|
const bulkDeleteProcessing = async (dbUser: User) => {
|
|
@@ -565,7 +584,7 @@ const bulkDeleteProcessing = async (dbUser: User) => {
|
|
|
565
584
|
await cache.user.invalidateUser(userId)
|
|
566
585
|
await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
|
|
567
586
|
// let server know to sync user
|
|
568
|
-
await apps.syncUserInApps(userId)
|
|
587
|
+
await apps.syncUserInApps(userId, dbUser)
|
|
569
588
|
}
|
|
570
589
|
|
|
571
590
|
export const invite = async (
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import "./mocks"
|
|
1
|
+
import mocks from "./mocks"
|
|
2
|
+
|
|
3
|
+
// init the licensing mock
|
|
4
|
+
import * as pro from "@budibase/pro"
|
|
5
|
+
mocks.licenses.init(pro)
|
|
6
|
+
|
|
7
|
+
// use unlimited license by default
|
|
8
|
+
mocks.licenses.useUnlimited()
|
|
9
|
+
|
|
2
10
|
import * as dbConfig from "../db"
|
|
3
11
|
dbConfig.init()
|
|
4
12
|
import env from "../environment"
|
|
@@ -43,7 +51,7 @@ class TestConfiguration {
|
|
|
43
51
|
|
|
44
52
|
if (opts.openServer) {
|
|
45
53
|
env.PORT = "0" // random port
|
|
46
|
-
this.server = require("../index")
|
|
54
|
+
this.server = require("../index").default
|
|
47
55
|
// we need the request for logging in, involves cookies, hard to fake
|
|
48
56
|
this.request = supertest(this.server)
|
|
49
57
|
}
|
|
@@ -319,4 +327,4 @@ class TestConfiguration {
|
|
|
319
327
|
}
|
|
320
328
|
}
|
|
321
329
|
|
|
322
|
-
export
|
|
330
|
+
export default TestConfiguration
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { UserGroup } from "@budibase/types"
|
|
2
|
+
import TestConfiguration from "../TestConfiguration"
|
|
3
|
+
import { TestAPI } from "./base"
|
|
4
|
+
|
|
5
|
+
export class GroupsAPI extends TestAPI {
|
|
6
|
+
constructor(config: TestConfiguration) {
|
|
7
|
+
super(config)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
saveGroup = (group: UserGroup) => {
|
|
11
|
+
return this.request
|
|
12
|
+
.post(`/api/global/groups`)
|
|
13
|
+
.send(group)
|
|
14
|
+
.set(this.config.defaultHeaders())
|
|
15
|
+
.expect("Content-Type", /json/)
|
|
16
|
+
.expect(200)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
deleteGroup = (id: string, rev: string) => {
|
|
20
|
+
return this.request
|
|
21
|
+
.delete(`/api/global/groups/${id}/${rev}`)
|
|
22
|
+
.set(this.config.defaultHeaders())
|
|
23
|
+
.expect("Content-Type", /json/)
|
|
24
|
+
.expect(200)
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/tests/api/index.ts
CHANGED
|
@@ -10,7 +10,10 @@ import { MigrationAPI } from "./migrations"
|
|
|
10
10
|
import { StatusAPI } from "./status"
|
|
11
11
|
import { RestoreAPI } from "./restore"
|
|
12
12
|
import { TenantAPI } from "./tenants"
|
|
13
|
-
|
|
13
|
+
import { GroupsAPI } from "./groups"
|
|
14
|
+
import { RolesAPI } from "./roles"
|
|
15
|
+
import { TemplatesAPI } from "./templates"
|
|
16
|
+
import { LicenseAPI } from "./license"
|
|
14
17
|
export default class API {
|
|
15
18
|
accounts: AccountAPI
|
|
16
19
|
auth: AuthAPI
|
|
@@ -23,6 +26,10 @@ export default class API {
|
|
|
23
26
|
status: StatusAPI
|
|
24
27
|
restore: RestoreAPI
|
|
25
28
|
tenants: TenantAPI
|
|
29
|
+
groups: GroupsAPI
|
|
30
|
+
roles: RolesAPI
|
|
31
|
+
templates: TemplatesAPI
|
|
32
|
+
license: LicenseAPI
|
|
26
33
|
|
|
27
34
|
constructor(config: TestConfiguration) {
|
|
28
35
|
this.accounts = new AccountAPI(config)
|
|
@@ -36,5 +43,9 @@ export default class API {
|
|
|
36
43
|
this.status = new StatusAPI(config)
|
|
37
44
|
this.restore = new RestoreAPI(config)
|
|
38
45
|
this.tenants = new TenantAPI(config)
|
|
46
|
+
this.groups = new GroupsAPI(config)
|
|
47
|
+
this.roles = new RolesAPI(config)
|
|
48
|
+
this.templates = new TemplatesAPI(config)
|
|
49
|
+
this.license = new LicenseAPI(config)
|
|
39
50
|
}
|
|
40
51
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import TestConfiguration from "../TestConfiguration"
|
|
2
|
+
import { TestAPI } from "./base"
|
|
3
|
+
|
|
4
|
+
export class LicenseAPI extends TestAPI {
|
|
5
|
+
constructor(config: TestConfiguration) {
|
|
6
|
+
super(config)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
activate = async (licenseKey: string) => {
|
|
10
|
+
return this.request
|
|
11
|
+
.post("/api/global/license/activate")
|
|
12
|
+
.send({ licenseKey: licenseKey })
|
|
13
|
+
.set(this.config.defaultHeaders())
|
|
14
|
+
.expect("Content-Type", /json/)
|
|
15
|
+
.expect(200)
|
|
16
|
+
}
|
|
17
|
+
}
|