@budibase/worker 2.8.29 → 2.8.31-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/jest.config.ts +0 -2
- package/nodemon.json +9 -6
- package/package.json +12 -27
- package/scripts/test.sh +2 -2
- package/src/api/controllers/global/auth.ts +5 -5
- package/src/api/controllers/global/configs.ts +3 -3
- package/src/api/controllers/global/email.ts +3 -3
- package/src/api/controllers/global/roles.ts +7 -7
- package/src/api/controllers/global/self.ts +4 -4
- package/src/api/controllers/global/users.ts +14 -14
- package/src/api/controllers/system/logs.ts +13 -0
- package/src/api/routes/global/tests/appBuilder.spec.ts +62 -0
- package/src/api/routes/global/tests/auth.spec.ts +3 -3
- package/src/api/routes/global/tests/scim.spec.ts +2 -2
- package/src/api/routes/global/tests/self.spec.ts +2 -2
- package/src/api/routes/global/tests/users.spec.ts +2 -2
- package/src/api/routes/index.ts +8 -0
- package/src/api/routes/system/logs.ts +9 -0
- package/src/api/routes/system/tests/status.spec.ts +7 -4
- package/src/environment.ts +5 -1
- package/src/initPro.ts +1 -8
- package/src/migrations/functions/globalInfoSyncUsers.ts +1 -1
- package/src/sdk/auth/auth.ts +8 -9
- package/src/sdk/users/index.ts +5 -0
- package/src/sdk/users/tests/users.spec.ts +8 -8
- package/src/sdk/users/users.ts +7 -590
- package/src/tests/TestConfiguration.ts +4 -4
- package/src/tests/api/users.ts +20 -0
- package/src/tests/mocks/index.ts +1 -1
- package/tsconfig.json +2 -4
- package/src/sdk/users/events.ts +0 -176
package/jest.config.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Config } from "@jest/types"
|
|
2
2
|
import * as fs from "fs"
|
|
3
|
-
const preset = require("ts-jest/jest-preset")
|
|
4
3
|
|
|
5
4
|
const config: Config.InitialOptions = {
|
|
6
|
-
...preset,
|
|
7
5
|
preset: "@trendyol/jest-testcontainers",
|
|
8
6
|
setupFiles: ["./src/tests/jestEnv.ts"],
|
|
9
7
|
setupFilesAfterEnv: ["./src/tests/jestSetup.ts"],
|
package/nodemon.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"watch": [
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"../
|
|
2
|
+
"watch": [
|
|
3
|
+
"src",
|
|
4
|
+
"../backend-core",
|
|
5
|
+
"../pro",
|
|
6
|
+
"../types",
|
|
7
|
+
"../shared-core",
|
|
8
|
+
"../string-templates"
|
|
8
9
|
],
|
|
10
|
+
"ext": "js,ts,json",
|
|
11
|
+
"ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../*/dist/**/*"],
|
|
9
12
|
"exec": "yarn build && node dist/index.js"
|
|
10
13
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/worker",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.31-alpha.0",
|
|
5
5
|
"description": "Budibase background service",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"prebuild": "rimraf dist/",
|
|
16
16
|
"build": "node ../../scripts/build.js",
|
|
17
|
-
"check:types": "tsc -p tsconfig.
|
|
17
|
+
"check:types": "tsc -p tsconfig.json --noEmit --paths null",
|
|
18
18
|
"build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput",
|
|
19
19
|
"run:docker": "node dist/index.js",
|
|
20
20
|
"debug": "yarn build && node --expose-gc --inspect=9223 dist/index.js",
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"author": "Budibase",
|
|
39
39
|
"license": "GPL-3.0",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@budibase/backend-core": "2.8.
|
|
42
|
-
"@budibase/pro": "2.8.
|
|
43
|
-
"@budibase/string-templates": "2.8.
|
|
44
|
-
"@budibase/types": "2.8.
|
|
41
|
+
"@budibase/backend-core": "2.8.31-alpha.0",
|
|
42
|
+
"@budibase/pro": "2.8.31-alpha.0",
|
|
43
|
+
"@budibase/string-templates": "2.8.31-alpha.0",
|
|
44
|
+
"@budibase/types": "2.8.31-alpha.0",
|
|
45
45
|
"@koa/router": "8.0.8",
|
|
46
46
|
"@sentry/node": "6.17.7",
|
|
47
47
|
"@techpass/passport-openidconnect": "0.3.2",
|
|
@@ -74,10 +74,10 @@
|
|
|
74
74
|
"server-destroy": "1.0.1"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@swc/core": "
|
|
78
|
-
"@swc/jest": "
|
|
79
|
-
"@trendyol/jest-testcontainers": "
|
|
80
|
-
"@types/jest": "
|
|
77
|
+
"@swc/core": "1.3.71",
|
|
78
|
+
"@swc/jest": "0.2.27",
|
|
79
|
+
"@trendyol/jest-testcontainers": "2.1.1",
|
|
80
|
+
"@types/jest": "29.5.3",
|
|
81
81
|
"@types/jsonwebtoken": "8.5.1",
|
|
82
82
|
"@types/koa": "2.13.4",
|
|
83
83
|
"@types/koa__router": "8.0.8",
|
|
@@ -91,32 +91,17 @@
|
|
|
91
91
|
"@typescript-eslint/parser": "5.45.0",
|
|
92
92
|
"copyfiles": "2.4.1",
|
|
93
93
|
"eslint": "6.8.0",
|
|
94
|
-
"jest": "
|
|
94
|
+
"jest": "29.6.2",
|
|
95
95
|
"lodash": "4.17.21",
|
|
96
96
|
"nodemon": "2.0.15",
|
|
97
97
|
"pouchdb-adapter-memory": "7.2.2",
|
|
98
98
|
"rimraf": "3.0.2",
|
|
99
99
|
"supertest": "6.2.2",
|
|
100
100
|
"timekeeper": "2.2.0",
|
|
101
|
-
"ts-jest": "28.0.4",
|
|
102
101
|
"ts-node": "10.8.1",
|
|
103
102
|
"tsconfig-paths": "4.0.0",
|
|
104
103
|
"typescript": "4.7.3",
|
|
105
104
|
"update-dotenv": "1.1.1"
|
|
106
105
|
},
|
|
107
|
-
"
|
|
108
|
-
"targets": {
|
|
109
|
-
"dev:builder": {
|
|
110
|
-
"dependsOn": [
|
|
111
|
-
{
|
|
112
|
-
"projects": [
|
|
113
|
-
"@budibase/backend-core"
|
|
114
|
-
],
|
|
115
|
-
"target": "build"
|
|
116
|
-
}
|
|
117
|
-
]
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
"gitHead": "c5b487659606add604ff3211f422c26c4924bc35"
|
|
106
|
+
"gitHead": "38e2c52eb34c0fae42da6e7f346996c379cd281f"
|
|
122
107
|
}
|
package/scripts/test.sh
CHANGED
|
@@ -4,8 +4,8 @@ set -e
|
|
|
4
4
|
if [[ -n $CI ]]
|
|
5
5
|
then
|
|
6
6
|
# --runInBand performs better in ci where resources are limited
|
|
7
|
-
echo "jest --coverage --runInBand --forceExit"
|
|
8
|
-
jest --coverage --runInBand --forceExit
|
|
7
|
+
echo "jest --coverage --runInBand --forceExit --bail"
|
|
8
|
+
jest --coverage --runInBand --forceExit --bail
|
|
9
9
|
else
|
|
10
10
|
# --maxWorkers performs better in development
|
|
11
11
|
echo "jest --coverage --maxWorkers=2 --forceExit"
|
|
@@ -55,8 +55,8 @@ async function passportCallback(
|
|
|
55
55
|
export const login = async (ctx: Ctx<LoginRequest>, next: any) => {
|
|
56
56
|
const email = ctx.request.body.username
|
|
57
57
|
|
|
58
|
-
const user = await userSdk.getUserByEmail(email)
|
|
59
|
-
if (user && (await userSdk.isPreventPasswordActions(user))) {
|
|
58
|
+
const user = await userSdk.db.getUserByEmail(email)
|
|
59
|
+
if (user && (await userSdk.db.isPreventPasswordActions(user))) {
|
|
60
60
|
ctx.throw(403, "Invalid credentials")
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -174,7 +174,7 @@ export const googlePreAuth = async (ctx: any, next: any) => {
|
|
|
174
174
|
const strategy = await google.strategyFactory(
|
|
175
175
|
config,
|
|
176
176
|
callbackUrl,
|
|
177
|
-
userSdk.save
|
|
177
|
+
userSdk.db.save
|
|
178
178
|
)
|
|
179
179
|
|
|
180
180
|
return passport.authenticate(strategy, {
|
|
@@ -193,7 +193,7 @@ export const googleCallback = async (ctx: any, next: any) => {
|
|
|
193
193
|
const strategy = await google.strategyFactory(
|
|
194
194
|
config,
|
|
195
195
|
callbackUrl,
|
|
196
|
-
userSdk.save
|
|
196
|
+
userSdk.db.save
|
|
197
197
|
)
|
|
198
198
|
|
|
199
199
|
return passport.authenticate(
|
|
@@ -228,7 +228,7 @@ export const oidcStrategyFactory = async (ctx: any, configId: any) => {
|
|
|
228
228
|
|
|
229
229
|
//Remote Config
|
|
230
230
|
const enrichedConfig = await oidc.fetchStrategyConfig(config, callbackUrl)
|
|
231
|
-
return oidc.strategyFactory(enrichedConfig, userSdk.save)
|
|
231
|
+
return oidc.strategyFactory(enrichedConfig, userSdk.db.save)
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
/**
|
|
@@ -507,17 +507,17 @@ export async function configChecklist(ctx: Ctx) {
|
|
|
507
507
|
smtp: {
|
|
508
508
|
checked: !!smtpConfig,
|
|
509
509
|
label: "Set up email",
|
|
510
|
-
link: "/builder/portal/
|
|
510
|
+
link: "/builder/portal/settings/email",
|
|
511
511
|
},
|
|
512
512
|
adminUser: {
|
|
513
513
|
checked: userExists,
|
|
514
514
|
label: "Create your first user",
|
|
515
|
-
link: "/builder/portal/
|
|
515
|
+
link: "/builder/portal/users/users",
|
|
516
516
|
},
|
|
517
517
|
sso: {
|
|
518
518
|
checked: !!googleConfig || !!oidcConfig,
|
|
519
519
|
label: "Set up single sign-on",
|
|
520
|
-
link: "/builder/portal/
|
|
520
|
+
link: "/builder/portal/settings/auth",
|
|
521
521
|
},
|
|
522
522
|
}
|
|
523
523
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sendEmail as sendEmailFn } from "../../../utilities/email"
|
|
2
2
|
import { tenancy } from "@budibase/backend-core"
|
|
3
|
-
import { BBContext } from "@budibase/types"
|
|
3
|
+
import { BBContext, User } from "@budibase/types"
|
|
4
4
|
|
|
5
5
|
export async function sendEmail(ctx: BBContext) {
|
|
6
6
|
let {
|
|
@@ -16,10 +16,10 @@ export async function sendEmail(ctx: BBContext) {
|
|
|
16
16
|
automation,
|
|
17
17
|
invite,
|
|
18
18
|
} = ctx.request.body
|
|
19
|
-
let user
|
|
19
|
+
let user: any
|
|
20
20
|
if (userId) {
|
|
21
21
|
const db = tenancy.getGlobalDB()
|
|
22
|
-
user = await db.get(userId)
|
|
22
|
+
user = await db.get<User>(userId)
|
|
23
23
|
}
|
|
24
24
|
const response = await sendEmailFn(email, purpose, {
|
|
25
25
|
workspaceId,
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
cache,
|
|
6
6
|
tenancy,
|
|
7
7
|
} from "@budibase/backend-core"
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
8
|
+
import sdk from "../../../sdk"
|
|
9
|
+
import { Ctx, App } from "@budibase/types"
|
|
10
10
|
|
|
11
|
-
export async function fetch(ctx:
|
|
11
|
+
export async function fetch(ctx: Ctx) {
|
|
12
12
|
const tenantId = ctx.user!.tenantId
|
|
13
13
|
// always use the dev apps as they'll be most up to date (true)
|
|
14
14
|
const apps = (await dbCore.getAllApps({ tenantId, all: true })) as App[]
|
|
@@ -31,11 +31,11 @@ export async function fetch(ctx: BBContext) {
|
|
|
31
31
|
ctx.body = response
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export async function find(ctx:
|
|
34
|
+
export async function find(ctx: Ctx) {
|
|
35
35
|
const appId = ctx.params.appId
|
|
36
36
|
await context.doInAppContext(dbCore.getDevAppID(appId), async () => {
|
|
37
37
|
const db = context.getAppDB()
|
|
38
|
-
const app = await db.get(dbCore.DocumentType.APP_METADATA)
|
|
38
|
+
const app = await db.get<App>(dbCore.DocumentType.APP_METADATA)
|
|
39
39
|
ctx.body = {
|
|
40
40
|
roles: await roles.getAllRoles(),
|
|
41
41
|
name: app.name,
|
|
@@ -45,10 +45,10 @@ export async function find(ctx: BBContext) {
|
|
|
45
45
|
})
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export async function removeAppRole(ctx:
|
|
48
|
+
export async function removeAppRole(ctx: Ctx) {
|
|
49
49
|
const { appId } = ctx.params
|
|
50
50
|
const db = tenancy.getGlobalDB()
|
|
51
|
-
const users = await allUsers()
|
|
51
|
+
const users = await sdk.users.db.allUsers()
|
|
52
52
|
const bulk = []
|
|
53
53
|
const cacheInvalidations = []
|
|
54
54
|
for (let user of users) {
|
|
@@ -44,7 +44,7 @@ export async function generateAPIKey(ctx: any) {
|
|
|
44
44
|
const id = dbCore.generateDevInfoID(userId)
|
|
45
45
|
let devInfo
|
|
46
46
|
try {
|
|
47
|
-
devInfo = await db.get(id)
|
|
47
|
+
devInfo = await db.get<any>(id)
|
|
48
48
|
} catch (err) {
|
|
49
49
|
devInfo = { _id: id, userId }
|
|
50
50
|
}
|
|
@@ -91,7 +91,7 @@ export async function getSelf(ctx: any) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// get the main body of the user
|
|
94
|
-
const user = await userSdk.getUser(userId)
|
|
94
|
+
const user = await userSdk.db.getUser(userId)
|
|
95
95
|
ctx.body = await groups.enrichUserRolesFromGroups(user)
|
|
96
96
|
|
|
97
97
|
// add the feature flags for this tenant
|
|
@@ -106,12 +106,12 @@ export async function updateSelf(
|
|
|
106
106
|
) {
|
|
107
107
|
const update = ctx.request.body
|
|
108
108
|
|
|
109
|
-
let user = await userSdk.getUser(ctx.user._id!)
|
|
109
|
+
let user = await userSdk.db.getUser(ctx.user._id!)
|
|
110
110
|
user = {
|
|
111
111
|
...user,
|
|
112
112
|
...update,
|
|
113
113
|
}
|
|
114
|
-
user = await userSdk.save(user, { requirePassword: false })
|
|
114
|
+
user = await userSdk.db.save(user, { requirePassword: false })
|
|
115
115
|
|
|
116
116
|
if (update.password) {
|
|
117
117
|
// Log all other sessions out apart from the current one
|
|
@@ -41,7 +41,7 @@ export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
|
|
|
41
41
|
const currentUserId = ctx.user?._id
|
|
42
42
|
const requestUser = ctx.request.body
|
|
43
43
|
|
|
44
|
-
const user = await userSdk.save(requestUser, { currentUserId })
|
|
44
|
+
const user = await userSdk.db.save(requestUser, { currentUserId })
|
|
45
45
|
|
|
46
46
|
ctx.body = {
|
|
47
47
|
_id: user._id!,
|
|
@@ -57,7 +57,7 @@ const bulkDelete = async (userIds: string[], currentUserId: string) => {
|
|
|
57
57
|
if (userIds?.indexOf(currentUserId) !== -1) {
|
|
58
58
|
throw new Error("Unable to delete self.")
|
|
59
59
|
}
|
|
60
|
-
return await userSdk.bulkDelete(userIds)
|
|
60
|
+
return await userSdk.db.bulkDelete(userIds)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const bulkCreate = async (users: User[], groupIds: string[]) => {
|
|
@@ -66,7 +66,7 @@ const bulkCreate = async (users: User[], groupIds: string[]) => {
|
|
|
66
66
|
"Max limit for upload is 1000 users. Please reduce file size and try again."
|
|
67
67
|
)
|
|
68
68
|
}
|
|
69
|
-
return await userSdk.bulkCreate(users, groupIds)
|
|
69
|
+
return await userSdk.db.bulkCreate(users, groupIds)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export const bulkUpdate = async (
|
|
@@ -141,7 +141,7 @@ export const adminUser = async (
|
|
|
141
141
|
// always bust checklist beforehand, if an error occurs but can proceed, don't get
|
|
142
142
|
// stuck in a cycle
|
|
143
143
|
await cache.bustCache(cache.CacheKey.CHECKLIST)
|
|
144
|
-
const finalUser = await userSdk.save(user, {
|
|
144
|
+
const finalUser = await userSdk.db.save(user, {
|
|
145
145
|
hashPassword,
|
|
146
146
|
requirePassword,
|
|
147
147
|
})
|
|
@@ -167,7 +167,7 @@ export const adminUser = async (
|
|
|
167
167
|
export const countByApp = async (ctx: any) => {
|
|
168
168
|
const appId = ctx.params.appId
|
|
169
169
|
try {
|
|
170
|
-
ctx.body = await userSdk.countUsersByApp(appId)
|
|
170
|
+
ctx.body = await userSdk.db.countUsersByApp(appId)
|
|
171
171
|
} catch (err: any) {
|
|
172
172
|
ctx.throw(err.status || 400, err)
|
|
173
173
|
}
|
|
@@ -179,7 +179,7 @@ export const destroy = async (ctx: any) => {
|
|
|
179
179
|
ctx.throw(400, "Unable to delete self.")
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
await userSdk.destroy(id)
|
|
182
|
+
await userSdk.db.destroy(id)
|
|
183
183
|
|
|
184
184
|
ctx.body = {
|
|
185
185
|
message: `User ${id} deleted.`,
|
|
@@ -188,7 +188,7 @@ export const destroy = async (ctx: any) => {
|
|
|
188
188
|
|
|
189
189
|
export const getAppUsers = async (ctx: Ctx<SearchUsersRequest>) => {
|
|
190
190
|
const body = ctx.request.body
|
|
191
|
-
const users = await userSdk.getUsersByAppAccess(body?.appId)
|
|
191
|
+
const users = await userSdk.db.getUsersByAppAccess(body?.appId)
|
|
192
192
|
|
|
193
193
|
ctx.body = { data: users }
|
|
194
194
|
}
|
|
@@ -212,7 +212,7 @@ export const search = async (ctx: Ctx<SearchUsersRequest>) => {
|
|
|
212
212
|
|
|
213
213
|
// called internally by app server user fetch
|
|
214
214
|
export const fetch = async (ctx: any) => {
|
|
215
|
-
const all = await userSdk.allUsers()
|
|
215
|
+
const all = await userSdk.db.allUsers()
|
|
216
216
|
// user hashed password shouldn't ever be returned
|
|
217
217
|
for (let user of all) {
|
|
218
218
|
if (user) {
|
|
@@ -224,12 +224,12 @@ export const fetch = async (ctx: any) => {
|
|
|
224
224
|
|
|
225
225
|
// called internally by app server user find
|
|
226
226
|
export const find = async (ctx: any) => {
|
|
227
|
-
ctx.body = await userSdk.getUser(ctx.params.id)
|
|
227
|
+
ctx.body = await userSdk.db.getUser(ctx.params.id)
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
export const tenantUserLookup = async (ctx: any) => {
|
|
231
231
|
const id = ctx.params.id
|
|
232
|
-
const user = await userSdk.getPlatformUser(id)
|
|
232
|
+
const user = await userSdk.core.getPlatformUser(id)
|
|
233
233
|
if (user) {
|
|
234
234
|
ctx.body = user
|
|
235
235
|
} else {
|
|
@@ -252,7 +252,7 @@ export const onboardUsers = async (ctx: Ctx<InviteUsersRequest>) => {
|
|
|
252
252
|
// @ts-ignore
|
|
253
253
|
const { users, groups, roles } = request.create
|
|
254
254
|
const assignUsers = users.map((user: User) => (user.roles = roles))
|
|
255
|
-
onboardingResponse = await userSdk.bulkCreate(assignUsers, groups)
|
|
255
|
+
onboardingResponse = await userSdk.db.bulkCreate(assignUsers, groups)
|
|
256
256
|
ctx.body = onboardingResponse
|
|
257
257
|
} else if (emailConfigured) {
|
|
258
258
|
onboardingResponse = await inviteMultiple(ctx)
|
|
@@ -277,7 +277,7 @@ export const onboardUsers = async (ctx: Ctx<InviteUsersRequest>) => {
|
|
|
277
277
|
tenantId: tenancy.getTenantId(),
|
|
278
278
|
}
|
|
279
279
|
})
|
|
280
|
-
let bulkCreateReponse = await userSdk.bulkCreate(users, [])
|
|
280
|
+
let bulkCreateReponse = await userSdk.db.bulkCreate(users, [])
|
|
281
281
|
|
|
282
282
|
// Apply temporary credentials
|
|
283
283
|
let createWithCredentials = {
|
|
@@ -410,9 +410,9 @@ export const inviteAccept = async (
|
|
|
410
410
|
...info,
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
const saved = await userSdk.save(request)
|
|
413
|
+
const saved = await userSdk.db.save(request)
|
|
414
414
|
const db = tenancy.getGlobalDB()
|
|
415
|
-
const user = await db.get(saved._id)
|
|
415
|
+
const user = await db.get<User>(saved._id)
|
|
416
416
|
await events.user.inviteAccepted(user)
|
|
417
417
|
return saved
|
|
418
418
|
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UserCtx } from "@budibase/types"
|
|
2
|
+
import { installation, logging } from "@budibase/backend-core"
|
|
3
|
+
|
|
4
|
+
export async function getLogs(ctx: UserCtx) {
|
|
5
|
+
const logReadStream = logging.system.getLogReadStream()
|
|
6
|
+
|
|
7
|
+
const { installId } = await installation.getInstall()
|
|
8
|
+
|
|
9
|
+
const fileName = `${installId}-${Date.now()}.log`
|
|
10
|
+
|
|
11
|
+
ctx.set("content-disposition", `attachment; filename=${fileName}`)
|
|
12
|
+
ctx.body = logReadStream
|
|
13
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { TestConfiguration, structures } from "../../../../tests"
|
|
2
|
+
import { mocks } from "@budibase/backend-core/tests"
|
|
3
|
+
import { User } from "@budibase/types"
|
|
4
|
+
|
|
5
|
+
const MOCK_APP_ID = "app_a"
|
|
6
|
+
|
|
7
|
+
describe("/api/global/users/:userId/app/builder", () => {
|
|
8
|
+
const config = new TestConfiguration()
|
|
9
|
+
|
|
10
|
+
beforeAll(async () => {
|
|
11
|
+
await config.beforeAll()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
afterAll(async () => {
|
|
15
|
+
await config.afterAll()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
async function newUser() {
|
|
19
|
+
const base = structures.users.user()
|
|
20
|
+
return await config.createUser(base)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function getUser(userId: string) {
|
|
24
|
+
const response = await config.api.users.getUser(userId)
|
|
25
|
+
return response.body as User
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("Confirm pro license", () => {
|
|
29
|
+
it("should 400 with licensing", async () => {
|
|
30
|
+
const user = await newUser()
|
|
31
|
+
const resp = await config.api.users.grantBuilderToApp(
|
|
32
|
+
user._id!,
|
|
33
|
+
MOCK_APP_ID,
|
|
34
|
+
400
|
|
35
|
+
)
|
|
36
|
+
expect(resp.body.message).toContain("Feature not enabled")
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe("PATCH /api/global/users/:userId/app/:appId/builder", () => {
|
|
41
|
+
it("should be able to grant a user access to a particular app", async () => {
|
|
42
|
+
mocks.licenses.useAppBuilders()
|
|
43
|
+
const user = await newUser()
|
|
44
|
+
await config.api.users.grantBuilderToApp(user._id!, MOCK_APP_ID)
|
|
45
|
+
const updated = await getUser(user._id!)
|
|
46
|
+
expect(updated.builder?.apps![0]).toBe(MOCK_APP_ID)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe("DELETE /api/global/users/:userId/app/:appId/builder", () => {
|
|
51
|
+
it("should allow revoking access", async () => {
|
|
52
|
+
mocks.licenses.useAppBuilders()
|
|
53
|
+
const user = await newUser()
|
|
54
|
+
await config.api.users.grantBuilderToApp(user._id!, MOCK_APP_ID)
|
|
55
|
+
let updated = await getUser(user._id!)
|
|
56
|
+
expect(updated.builder?.apps![0]).toBe(MOCK_APP_ID)
|
|
57
|
+
await config.api.users.revokeBuilderFromApp(user._id!, MOCK_APP_ID)
|
|
58
|
+
updated = await getUser(user._id!)
|
|
59
|
+
expect(updated.builder?.apps!.length).toBe(0)
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
})
|
|
@@ -41,7 +41,7 @@ describe("/api/global/auth", () => {
|
|
|
41
41
|
|
|
42
42
|
async function createSSOUser() {
|
|
43
43
|
return config.doInTenant(async () => {
|
|
44
|
-
return userSdk.save(structures.users.ssoUser(), {
|
|
44
|
+
return userSdk.db.save(structures.users.ssoUser(), {
|
|
45
45
|
requirePassword: false,
|
|
46
46
|
})
|
|
47
47
|
})
|
|
@@ -206,7 +206,7 @@ describe("/api/global/auth", () => {
|
|
|
206
206
|
const newPassword = "newpassword"
|
|
207
207
|
const res = await config.api.auth.updatePassword(code!, newPassword)
|
|
208
208
|
|
|
209
|
-
user = await config.getUser(user.email)
|
|
209
|
+
user = (await config.getUser(user.email))!
|
|
210
210
|
delete user.password
|
|
211
211
|
|
|
212
212
|
expect(res.body).toEqual({ message: "password reset successfully." })
|
|
@@ -245,7 +245,7 @@ describe("/api/global/auth", () => {
|
|
|
245
245
|
const ssoUser = user as SSOUser
|
|
246
246
|
ssoUser.providerType = structures.sso.providerType()
|
|
247
247
|
delete ssoUser.password
|
|
248
|
-
await config.doInTenant(() => userSdk.save(ssoUser))
|
|
248
|
+
await config.doInTenant(() => userSdk.db.save(ssoUser))
|
|
249
249
|
|
|
250
250
|
await testSSOUser(code!)
|
|
251
251
|
})
|
|
@@ -314,7 +314,7 @@ describe("scim", () => {
|
|
|
314
314
|
|
|
315
315
|
const user = await config.getUser(email)
|
|
316
316
|
expect(user).toBeDefined()
|
|
317
|
-
expect(user
|
|
317
|
+
expect(user!.email).toEqual(email)
|
|
318
318
|
})
|
|
319
319
|
|
|
320
320
|
it("if multiple emails are provided, the first primary one is used as email", async () => {
|
|
@@ -345,7 +345,7 @@ describe("scim", () => {
|
|
|
345
345
|
|
|
346
346
|
const user = await config.getUser(email)
|
|
347
347
|
expect(user).toBeDefined()
|
|
348
|
-
expect(user
|
|
348
|
+
expect(user!.email).toEqual(email)
|
|
349
349
|
})
|
|
350
350
|
|
|
351
351
|
it("if no email is provided and the user name is not an email, an exception is thrown", async () => {
|
|
@@ -36,7 +36,7 @@ describe("/api/global/self", () => {
|
|
|
36
36
|
})
|
|
37
37
|
.expect(200)
|
|
38
38
|
|
|
39
|
-
const dbUser = await config.getUser(user.email)
|
|
39
|
+
const dbUser = (await config.getUser(user.email))!
|
|
40
40
|
|
|
41
41
|
user._rev = dbUser._rev
|
|
42
42
|
user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
|
|
@@ -58,7 +58,7 @@ describe("/api/global/self", () => {
|
|
|
58
58
|
})
|
|
59
59
|
.expect(200)
|
|
60
60
|
|
|
61
|
-
const dbUser = await config.getUser(user.email)
|
|
61
|
+
const dbUser = (await config.getUser(user.email))!
|
|
62
62
|
|
|
63
63
|
user._rev = dbUser._rev
|
|
64
64
|
user.dayPassRecordedAt = mocks.date.MOCK_DATE.toISOString()
|
|
@@ -66,7 +66,7 @@ describe("/api/global/users", () => {
|
|
|
66
66
|
expect(res.body._id).toBeDefined()
|
|
67
67
|
const user = await config.getUser(email)
|
|
68
68
|
expect(user).toBeDefined()
|
|
69
|
-
expect(user
|
|
69
|
+
expect(user!._id).toEqual(res.body._id)
|
|
70
70
|
expect(events.user.inviteAccepted).toBeCalledTimes(1)
|
|
71
71
|
expect(events.user.inviteAccepted).toBeCalledWith(user)
|
|
72
72
|
})
|
|
@@ -480,7 +480,7 @@ describe("/api/global/users", () => {
|
|
|
480
480
|
function createSSOUser() {
|
|
481
481
|
return config.doInTenant(() => {
|
|
482
482
|
const user = structures.users.ssoUser()
|
|
483
|
-
return userSdk.save(user, { requirePassword: false })
|
|
483
|
+
return userSdk.db.save(user, { requirePassword: false })
|
|
484
484
|
})
|
|
485
485
|
}
|
|
486
486
|
|
package/src/api/routes/index.ts
CHANGED
|
@@ -16,10 +16,14 @@ import licenseRoutes from "./global/license"
|
|
|
16
16
|
import migrationRoutes from "./system/migrations"
|
|
17
17
|
import accountRoutes from "./system/accounts"
|
|
18
18
|
import restoreRoutes from "./system/restore"
|
|
19
|
+
import systemLogRoutes from "./system/logs"
|
|
20
|
+
|
|
21
|
+
import env from "../../environment"
|
|
19
22
|
|
|
20
23
|
export const routes: Router[] = [
|
|
21
24
|
configRoutes,
|
|
22
25
|
userRoutes,
|
|
26
|
+
pro.users,
|
|
23
27
|
workspaceRoutes,
|
|
24
28
|
authRoutes,
|
|
25
29
|
templateRoutes,
|
|
@@ -38,3 +42,7 @@ export const routes: Router[] = [
|
|
|
38
42
|
eventRoutes,
|
|
39
43
|
pro.scim,
|
|
40
44
|
]
|
|
45
|
+
|
|
46
|
+
if (env.SELF_HOSTED) {
|
|
47
|
+
routes.push(systemLogRoutes)
|
|
48
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Router from "@koa/router"
|
|
2
|
+
import { middleware } from "@budibase/backend-core"
|
|
3
|
+
import * as controller from "../../controllers/system/logs"
|
|
4
|
+
|
|
5
|
+
const router: Router = new Router()
|
|
6
|
+
|
|
7
|
+
router.get("/api/system/logs", middleware.adminOnly, controller.getLogs)
|
|
8
|
+
|
|
9
|
+
export default router
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HealthStatusResponse } from "@budibase/types"
|
|
1
2
|
import { TestConfiguration } from "../../../../tests"
|
|
2
3
|
import { accounts as _accounts } from "@budibase/backend-core"
|
|
3
4
|
const accounts = jest.mocked(_accounts)
|
|
@@ -31,13 +32,15 @@ describe("/api/system/status", () => {
|
|
|
31
32
|
})
|
|
32
33
|
|
|
33
34
|
it("returns status in cloud", async () => {
|
|
34
|
-
const value = {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
const value: HealthStatusResponse = {
|
|
36
|
+
passing: false,
|
|
37
|
+
checks: {
|
|
38
|
+
login: false,
|
|
39
|
+
search: false,
|
|
37
40
|
},
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
accounts.getStatus.
|
|
43
|
+
accounts.getStatus.mockResolvedValue(value)
|
|
41
44
|
|
|
42
45
|
const res = await config.api.status.getStatus()
|
|
43
46
|
|
package/src/environment.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { env as coreEnv } from "@budibase/backend-core"
|
|
2
|
+
import { ServiceType } from "@budibase/types"
|
|
3
|
+
import { join } from "path"
|
|
4
|
+
|
|
5
|
+
coreEnv._set("SERVICE_TYPE", ServiceType.WORKER)
|
|
2
6
|
|
|
3
7
|
function isDev() {
|
|
4
8
|
return process.env.NODE_ENV !== "production"
|
package/src/initPro.ts
CHANGED
|
@@ -2,12 +2,5 @@ import { sdk as proSdk } from "@budibase/pro"
|
|
|
2
2
|
import * as userSdk from "./sdk/users"
|
|
3
3
|
|
|
4
4
|
export const initPro = async () => {
|
|
5
|
-
await proSdk.init({
|
|
6
|
-
scimUserServiceConfig: {
|
|
7
|
-
functions: {
|
|
8
|
-
saveUser: userSdk.save,
|
|
9
|
-
removeUser: (id: string) => userSdk.destroy(id),
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
})
|
|
5
|
+
await proSdk.init({})
|
|
13
6
|
}
|
|
@@ -10,7 +10,7 @@ import { platform } from "@budibase/backend-core"
|
|
|
10
10
|
* Re-sync the global-db users to the global-info db users
|
|
11
11
|
*/
|
|
12
12
|
export const run = async (globalDb: any) => {
|
|
13
|
-
const users = (await usersSdk.allUsers()) as User[]
|
|
13
|
+
const users = (await usersSdk.db.allUsers()) as User[]
|
|
14
14
|
const promises = []
|
|
15
15
|
for (let user of users) {
|
|
16
16
|
promises.push(
|