@budibase/worker 2.5.6-alpha.9 → 2.5.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/jest.config.ts CHANGED
@@ -20,11 +20,11 @@ const config: Config.InitialOptions = {
20
20
  }
21
21
 
22
22
  // add pro sources if they exist
23
- if (fs.existsSync("../pro/packages")) {
24
- config.moduleNameMapper!["@budibase/pro/(.*)"] =
25
- "<rootDir>/../pro/packages/pro/$1"
26
- config.moduleNameMapper!["@budibase/pro"] =
27
- "<rootDir>/../pro/packages/pro/src"
23
+ if (fs.existsSync("../../../budibase-pro")) {
24
+ config.moduleNameMapper["@budibase/pro/(.*)"] =
25
+ "<rootDir>/../../../budibase-pro/packages/pro/$1"
26
+ config.moduleNameMapper["@budibase/pro"] =
27
+ "<rootDir>/../../../budibase-pro/packages/pro/src"
28
28
  }
29
29
 
30
30
  export default config
package/nodemon.json CHANGED
@@ -1,10 +1,6 @@
1
1
  {
2
- "watch": ["src", "../backend-core", "../pro/packages/pro"],
2
+ "watch": ["src", "../backend-core", "../../../budibase-pro/packages/pro"],
3
3
  "ext": "js,ts,json",
4
- "ignore": [
5
- "src/**/*.spec.ts",
6
- "src/**/*.spec.js",
7
- "../backend-core/dist/**/*"
8
- ],
4
+ "ignore": ["src/**/*.spec.ts", "src/**/*.spec.js", "../backend-core/dist/**/*"],
9
5
  "exec": "ts-node src/index.ts"
10
6
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/worker",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.5.6-alpha.9",
4
+ "version": "2.5.7",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -22,7 +22,6 @@
22
22
  "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION",
23
23
  "dev:stack:init": "node ./scripts/dev/manage.js init",
24
24
  "dev:builder": "npm run dev:stack:init && nodemon",
25
- "dev:built": "yarn run dev:stack:init && yarn run run:docker",
26
25
  "test": "bash scripts/test.sh",
27
26
  "test:watch": "jest --watch",
28
27
  "env:multi:enable": "node scripts/multiTenancy.js enable",
@@ -37,10 +36,10 @@
37
36
  "author": "Budibase",
38
37
  "license": "GPL-3.0",
39
38
  "dependencies": {
40
- "@budibase/backend-core": "2.5.6-alpha.9",
41
- "@budibase/pro": "2.5.6-alpha.6",
42
- "@budibase/string-templates": "2.5.6-alpha.9",
43
- "@budibase/types": "2.5.6-alpha.9",
39
+ "@budibase/backend-core": "^2.5.7",
40
+ "@budibase/pro": "2.5.6",
41
+ "@budibase/string-templates": "^2.5.7",
42
+ "@budibase/types": "^2.5.7",
44
43
  "@koa/router": "8.0.8",
45
44
  "@sentry/node": "6.17.7",
46
45
  "@techpass/passport-openidconnect": "0.3.2",
@@ -57,6 +56,7 @@
57
56
  "koa-body": "4.2.0",
58
57
  "koa-compress": "4.0.1",
59
58
  "koa-passport": "4.1.4",
59
+ "koa-pino-logger": "3.0.0",
60
60
  "koa-send": "5.0.1",
61
61
  "koa-session": "5.13.1",
62
62
  "koa-static": "5.0.0",
@@ -66,6 +66,7 @@
66
66
  "passport-google-oauth": "2.0.0",
67
67
  "passport-jwt": "4.0.0",
68
68
  "passport-local": "1.0.0",
69
+ "pino-pretty": "4.8.0",
69
70
  "pouchdb": "7.3.0",
70
71
  "pouchdb-all-dbs": "1.1.1",
71
72
  "server-destroy": "1.0.1"
@@ -78,7 +79,6 @@
78
79
  "@types/jsonwebtoken": "8.5.1",
79
80
  "@types/koa": "2.13.4",
80
81
  "@types/koa__router": "8.0.8",
81
- "@types/lodash": "^4.14.191",
82
82
  "@types/node": "14.18.20",
83
83
  "@types/node-fetch": "2.6.1",
84
84
  "@types/pouchdb": "6.4.0",
@@ -89,7 +89,6 @@
89
89
  "copyfiles": "2.4.1",
90
90
  "eslint": "6.8.0",
91
91
  "jest": "28.1.1",
92
- "lodash": "4.17.21",
93
92
  "nodemon": "2.0.15",
94
93
  "pouchdb-adapter-memory": "7.2.2",
95
94
  "prettier": "2.3.1",
@@ -102,5 +101,5 @@
102
101
  "typescript": "4.7.3",
103
102
  "update-dotenv": "1.1.1"
104
103
  },
105
- "gitHead": "560204d82570bd22b987e6e35f8e659e9c047425"
104
+ "gitHead": "6c37b6a6c69a1da43a5c0930419e743cc18b5b42"
106
105
  }
@@ -30,7 +30,6 @@ async function init() {
30
30
  DEPLOYMENT_ENVIRONMENT: "development",
31
31
  TENANT_FEATURE_FLAGS: "*:LICENSING,*:USER_GROUPS,*:ONBOARDING_TOUR",
32
32
  ENABLE_EMAIL_TEST_MODE: 1,
33
- HTTP_LOGGING: 0,
34
33
  }
35
34
  let envFile = ""
36
35
  Object.keys(envFileJson).forEach(key => {
@@ -177,7 +177,7 @@ export const destroy = async (ctx: any) => {
177
177
  ctx.throw(400, "Unable to delete self.")
178
178
  }
179
179
 
180
- await userSdk.destroy(id)
180
+ await userSdk.destroy(id, ctx.user)
181
181
 
182
182
  ctx.body = {
183
183
  message: `User ${id} deleted.`,
@@ -197,7 +197,7 @@ export const search = async (ctx: any) => {
197
197
  if (body.paginated === false) {
198
198
  await getAppUsers(ctx)
199
199
  } else {
200
- const paginated = await userSdk.core.paginatedUsers(body)
200
+ const paginated = await userSdk.paginatedUsers(body)
201
201
  // user hashed password shouldn't ever be returned
202
202
  for (let user of paginated.data) {
203
203
  if (user) {
package/src/api/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Router from "@koa/router"
2
2
  const compress = require("koa-compress")
3
- import zlib from "zlib"
3
+ const zlib = require("zlib")
4
4
  import { routes } from "./routes"
5
5
  import { middleware as pro } from "@budibase/pro"
6
6
  import { auth, middleware } from "@budibase/backend-core"
@@ -58,13 +58,6 @@ function oidcValidation() {
58
58
  }).unknown(true)
59
59
  }
60
60
 
61
- function scimValidation() {
62
- // prettier-ignore
63
- return Joi.object({
64
- enabled: Joi.boolean().required(),
65
- }).unknown(true)
66
- }
67
-
68
61
  function buildConfigSaveValidation() {
69
62
  // prettier-ignore
70
63
  return auth.joiValidator.body(Joi.object({
@@ -81,8 +74,7 @@ function buildConfigSaveValidation() {
81
74
  { is: ConfigType.SETTINGS, then: settingValidation() },
82
75
  { is: ConfigType.ACCOUNT, then: Joi.object().unknown(true) },
83
76
  { is: ConfigType.GOOGLE, then: googleValidation() },
84
- { is: ConfigType.OIDC, then: oidcValidation() },
85
- { is: ConfigType.SCIM, then: scimValidation() }
77
+ { is: ConfigType.OIDC, then: oidcValidation() }
86
78
  ],
87
79
  }),
88
80
  }).required().unknown(true),
@@ -48,7 +48,7 @@ describe("/api/global/users", () => {
48
48
  400
49
49
  )
50
50
 
51
- expect(res.body.message).toBe(`Unavailable`)
51
+ expect(res.body.message).toBe("Unavailable")
52
52
  expect(sendMailMock).toHaveBeenCalledTimes(0)
53
53
  expect(code).toBeUndefined()
54
54
  expect(events.user.invited).toBeCalledTimes(0)
@@ -225,9 +225,7 @@ describe("/api/global/users", () => {
225
225
 
226
226
  const response = await config.api.users.saveUser(user, 400)
227
227
 
228
- expect(response.body.message).toBe(
229
- `Email already in use: '${user.email}'`
230
- )
228
+ expect(response.body.message).toBe(`Unavailable`)
231
229
  expect(events.user.created).toBeCalledTimes(0)
232
230
  })
233
231
 
@@ -239,9 +237,7 @@ describe("/api/global/users", () => {
239
237
  delete user._id
240
238
  const response = await config.api.users.saveUser(user, 400)
241
239
 
242
- expect(response.body.message).toBe(
243
- `Email already in use: '${user.email}'`
244
- )
240
+ expect(response.body.message).toBe(`Unavailable`)
245
241
  expect(events.user.created).toBeCalledTimes(0)
246
242
  })
247
243
  })
@@ -253,9 +249,7 @@ describe("/api/global/users", () => {
253
249
 
254
250
  const response = await config.api.users.saveUser(user, 400)
255
251
 
256
- expect(response.body.message).toBe(
257
- `Email already in use: '${user.email}'`
258
- )
252
+ expect(response.body.message).toBe(`Unavailable`)
259
253
  expect(events.user.created).toBeCalledTimes(0)
260
254
  })
261
255
 
@@ -1,5 +1,5 @@
1
1
  import Router from "@koa/router"
2
- import { api as pro } from "@budibase/pro"
2
+ import { api } from "@budibase/pro"
3
3
  import userRoutes from "./global/users"
4
4
  import configRoutes from "./global/configs"
5
5
  import workspaceRoutes from "./global/workspaces"
@@ -17,6 +17,9 @@ import migrationRoutes from "./system/migrations"
17
17
  import accountRoutes from "./system/accounts"
18
18
  import restoreRoutes from "./system/restore"
19
19
 
20
+ let userGroupRoutes = api.groups
21
+ let auditLogRoutes = api.auditLogs
22
+
20
23
  export const routes: Router[] = [
21
24
  configRoutes,
22
25
  userRoutes,
@@ -30,11 +33,10 @@ export const routes: Router[] = [
30
33
  statusRoutes,
31
34
  selfRoutes,
32
35
  licenseRoutes,
33
- pro.groups,
34
- pro.auditLogs,
36
+ userGroupRoutes,
37
+ auditLogRoutes,
35
38
  migrationRoutes,
36
39
  accountRoutes,
37
40
  restoreRoutes,
38
41
  eventRoutes,
39
- pro.scim,
40
42
  ]
@@ -0,0 +1,10 @@
1
+ import apm from "elastic-apm-node"
2
+
3
+ // enable APM if configured
4
+ if (process.env.ELASTIC_APM_ENABLED) {
5
+ console.log("Starting elastic-apm-node")
6
+ apm.start({
7
+ serviceName: process.env.SERVICE,
8
+ environment: process.env.BUDIBASE_ENVIRONMENT,
9
+ })
10
+ }
@@ -47,6 +47,7 @@ const environment = {
47
47
  // flags
48
48
  NODE_ENV: process.env.NODE_ENV,
49
49
  SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED || ""),
50
+ LOG_LEVEL: process.env.LOG_LEVEL,
50
51
  MULTI_TENANCY: process.env.MULTI_TENANCY,
51
52
  DISABLE_ACCOUNT_PORTAL: process.env.DISABLE_ACCOUNT_PORTAL,
52
53
  SMTP_FALLBACK_ENABLED: process.env.SMTP_FALLBACK_ENABLED,
package/src/index.ts CHANGED
@@ -2,6 +2,10 @@ if (process.env.DD_APM_ENABLED) {
2
2
  require("./ddApm")
3
3
  }
4
4
 
5
+ if (process.env.ELASTIC_APM_ENABLED) {
6
+ require("./elasticApm")
7
+ }
8
+
5
9
  // need to load environment first
6
10
  import env from "./environment"
7
11
  import { Scope } from "@sentry/node"
@@ -27,11 +31,10 @@ import api from "./api"
27
31
  import * as redis from "./utilities/redis"
28
32
  const Sentry = require("@sentry/node")
29
33
  const koaSession = require("koa-session")
34
+ const logger = require("koa-pino-logger")
30
35
  const { userAgent } = require("koa-useragent")
31
36
 
32
37
  import destroyable from "server-destroy"
33
- import { initPro } from "./initPro"
34
- import { handleScimBody } from "./middleware/handleScimBody"
35
38
 
36
39
  // configure events to use the pro audit log write
37
40
  // can't integrate directly into backend-core due to cyclic issues
@@ -51,12 +54,10 @@ const app: Application = new Koa()
51
54
  app.keys = ["secret", "key"]
52
55
 
53
56
  // set up top level koa middleware
54
- app.use(handleScimBody)
55
57
  app.use(koaBody({ multipart: true }))
56
-
57
58
  app.use(koaSession(app))
58
- app.use(middleware.correlation)
59
- app.use(middleware.pino)
59
+ app.use(middleware.logging)
60
+ app.use(logger(logging.pinoSettings()))
60
61
  app.use(userAgent)
61
62
 
62
63
  // authentication
@@ -107,7 +108,6 @@ const shutdown = () => {
107
108
 
108
109
  export default server.listen(parseInt(env.PORT || "4002"), async () => {
109
110
  console.log(`Worker running on ${JSON.stringify(server.address())}`)
110
- await initPro()
111
111
  await redis.init()
112
112
  })
113
113
 
@@ -1,4 +1,5 @@
1
1
  import env from "../../environment"
2
+ import * as apps from "../../utilities/appService"
2
3
  import * as eventHelpers from "./events"
3
4
  import {
4
5
  accounts,
@@ -14,8 +15,6 @@ import {
14
15
  utils,
15
16
  ViewName,
16
17
  env as coreEnv,
17
- context,
18
- EmailUnavailableError,
19
18
  } from "@budibase/backend-core"
20
19
  import {
21
20
  AccountMetadata,
@@ -29,6 +28,7 @@ import {
29
28
  PlatformUser,
30
29
  PlatformUserByEmail,
31
30
  RowResponse,
31
+ SearchUsersRequest,
32
32
  User,
33
33
  SaveUserOpts,
34
34
  Account,
@@ -38,6 +38,8 @@ import { EmailTemplatePurpose } from "../../constants"
38
38
  import * as pro from "@budibase/pro"
39
39
  import * as accountSdk from "../accounts"
40
40
 
41
+ const PAGE_LIMIT = 8
42
+
41
43
  export const allUsers = async () => {
42
44
  const db = tenancy.getGlobalDB()
43
45
  const response = await db.allDocs(
@@ -67,6 +69,43 @@ export const getUsersByAppAccess = async (appId?: string) => {
67
69
  return response
68
70
  }
69
71
 
72
+ export const paginatedUsers = async ({
73
+ page,
74
+ email,
75
+ appId,
76
+ }: SearchUsersRequest = {}) => {
77
+ const db = tenancy.getGlobalDB()
78
+ // get one extra document, to have the next page
79
+ const opts: any = {
80
+ include_docs: true,
81
+ limit: PAGE_LIMIT + 1,
82
+ }
83
+ // add a startkey if the page was specified (anchor)
84
+ if (page) {
85
+ opts.startkey = page
86
+ }
87
+ // property specifies what to use for the page/anchor
88
+ let userList,
89
+ property = "_id",
90
+ getKey
91
+ if (appId) {
92
+ userList = await usersCore.searchGlobalUsersByApp(appId, opts)
93
+ getKey = (doc: any) => usersCore.getGlobalUserByAppPage(appId, doc)
94
+ } else if (email) {
95
+ userList = await usersCore.searchGlobalUsersByEmail(email, opts)
96
+ property = "email"
97
+ } else {
98
+ // no search, query allDocs
99
+ const response = await db.allDocs(dbUtils.getGlobalUserParams(null, opts))
100
+ userList = response.rows.map((row: any) => row.doc)
101
+ }
102
+ return dbUtils.pagination(userList, PAGE_LIMIT, {
103
+ paginate: true,
104
+ property,
105
+ getKey,
106
+ })
107
+ }
108
+
70
109
  export async function getUserByEmail(email: string) {
71
110
  return usersCore.getGlobalUserByEmail(email)
72
111
  }
@@ -159,7 +198,7 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
159
198
  if (env.MULTI_TENANCY) {
160
199
  const tenantUser = await getPlatformUser(email)
161
200
  if (tenantUser != null && tenantUser.tenantId !== tenantId) {
162
- throw new EmailUnavailableError(email)
201
+ throw `Unavailable`
163
202
  }
164
203
  }
165
204
 
@@ -167,7 +206,7 @@ const validateUniqueUser = async (email: string, tenantId: string) => {
167
206
  if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
168
207
  const account = await accounts.getAccount(email)
169
208
  if (account && account.verified && account.tenantId !== tenantId) {
170
- throw new EmailUnavailableError(email)
209
+ throw `Unavailable`
171
210
  }
172
211
  }
173
212
  }
@@ -238,7 +277,7 @@ export const save = async (
238
277
  // no id was specified - load from email instead
239
278
  dbUser = await usersCore.getGlobalUserByEmail(email)
240
279
  if (dbUser && dbUser._id !== _id) {
241
- throw new EmailUnavailableError(email)
280
+ throw `Unavailable`
242
281
  }
243
282
  }
244
283
 
@@ -278,6 +317,9 @@ export const save = async (
278
317
  await platform.users.addUser(tenantId, builtUser._id!, builtUser.email)
279
318
  await cache.user.invalidateUser(response.id)
280
319
 
320
+ // let server know to sync user
321
+ await apps.syncUserInApps(_id, dbUser)
322
+
281
323
  await Promise.all(groupPromises)
282
324
 
283
325
  // finally returned the saved user from the db
@@ -427,6 +469,7 @@ export const bulkCreate = async (
427
469
  // instead of relying on looping tenant creation
428
470
  await platform.users.addUser(tenantId, user._id, user.email)
429
471
  await eventHelpers.handleSaveEvents(user, undefined)
472
+ await apps.syncUserInApps(user._id)
430
473
  }
431
474
 
432
475
  const saved = usersToBulkSave.map(user => {
@@ -540,7 +583,7 @@ export const bulkDelete = async (
540
583
  return response
541
584
  }
542
585
 
543
- export const destroy = async (id: string) => {
586
+ export const destroy = async (id: string, currentUser: any) => {
544
587
  const db = tenancy.getGlobalDB()
545
588
  const dbUser = (await db.get(id)) as User
546
589
  const userId = dbUser._id as string
@@ -550,7 +593,7 @@ export const destroy = async (id: string) => {
550
593
  const email = dbUser.email
551
594
  const account = await accounts.getAccount(email)
552
595
  if (account) {
553
- if (dbUser.userId === context.getIdentity()!._id) {
596
+ if (email === currentUser.email) {
554
597
  throw new HTTPError('Please visit "Account" to delete this user', 400)
555
598
  } else {
556
599
  throw new HTTPError("Account holder cannot be deleted", 400)
@@ -565,6 +608,8 @@ export const destroy = async (id: string) => {
565
608
  await eventHelpers.handleDeleteEvents(dbUser)
566
609
  await cache.user.invalidateUser(userId)
567
610
  await sessions.invalidateSessions(userId, { reason: "deletion" })
611
+ // let server know to sync user
612
+ await apps.syncUserInApps(userId, dbUser)
568
613
  }
569
614
 
570
615
  const bulkDeleteProcessing = async (dbUser: User) => {
@@ -573,6 +618,8 @@ const bulkDeleteProcessing = async (dbUser: User) => {
573
618
  await eventHelpers.handleDeleteEvents(dbUser)
574
619
  await cache.user.invalidateUser(userId)
575
620
  await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
621
+ // let server know to sync user
622
+ await apps.syncUserInApps(userId, dbUser)
576
623
  }
577
624
 
578
625
  export const invite = async (
@@ -20,18 +20,9 @@ import {
20
20
  auth,
21
21
  constants,
22
22
  env as coreEnv,
23
- db as dbCore,
24
- encryption,
25
- utils,
26
23
  } from "@budibase/backend-core"
27
24
  import structures, { CSRF_TOKEN } from "./structures"
28
- import {
29
- SaveUserResponse,
30
- User,
31
- AuthToken,
32
- SCIMConfig,
33
- ConfigType,
34
- } from "@budibase/types"
25
+ import { SaveUserResponse, User, AuthToken } from "@budibase/types"
35
26
  import API from "./api"
36
27
 
37
28
  class TestConfiguration {
@@ -40,7 +31,6 @@ class TestConfiguration {
40
31
  api: API
41
32
  tenantId: string
42
33
  user?: User
43
- apiKey?: string
44
34
  userPassword = "test"
45
35
 
46
36
  constructor(opts: { openServer: boolean } = { openServer: true }) {
@@ -59,12 +49,6 @@ class TestConfiguration {
59
49
  this.api = new API(this)
60
50
  }
61
51
 
62
- async useNewTenant() {
63
- this.tenantId = structures.tenant.id()
64
-
65
- await this.beforeAll()
66
- }
67
-
68
52
  getRequest() {
69
53
  return this.request
70
54
  }
@@ -217,12 +201,6 @@ class TestConfiguration {
217
201
  return { [constants.Header.API_KEY]: coreEnv.INTERNAL_API_KEY }
218
202
  }
219
203
 
220
- bearerAPIHeaders() {
221
- return {
222
- [constants.Header.AUTHORIZATION]: `Bearer ${this.apiKey}`,
223
- }
224
- }
225
-
226
204
  adminOnlyResponse = () => {
227
205
  return { message: "Admin user only endpoint.", status: 403 }
228
206
  }
@@ -235,20 +213,6 @@ class TestConfiguration {
235
213
  })
236
214
  await context.doInTenant(this.tenantId!, async () => {
237
215
  this.user = await this.createUser(user)
238
-
239
- const db = context.getGlobalDB()
240
-
241
- const id = dbCore.generateDevInfoID(this.user._id)
242
- // TODO: dry
243
- this.apiKey = encryption.encrypt(
244
- `${this.tenantId}${dbCore.SEPARATOR}${utils.newid()}`
245
- )
246
- const devInfo = {
247
- _id: id,
248
- userId: this.user._id,
249
- apiKey: this.apiKey,
250
- }
251
- await db.put(devInfo)
252
216
  })
253
217
  }
254
218
 
@@ -341,19 +305,6 @@ class TestConfiguration {
341
305
  controllers.config.save
342
306
  )
343
307
  }
344
-
345
- // CONFIGS - SCIM
346
-
347
- async setSCIMConfig(enabled: boolean) {
348
- await this.deleteConfig(Config.SCIM)
349
- const config: SCIMConfig = {
350
- type: ConfigType.SCIM,
351
- config: { enabled },
352
- }
353
-
354
- await this._req(config, null, controllers.config.save)
355
- return config
356
- }
357
308
  }
358
309
 
359
310
  export default TestConfiguration
@@ -15,9 +15,6 @@ import { RolesAPI } from "./roles"
15
15
  import { TemplatesAPI } from "./templates"
16
16
  import { LicenseAPI } from "./license"
17
17
  import { AuditLogAPI } from "./auditLogs"
18
- import { ScimUsersAPI } from "./scim/users"
19
- import { ScimGroupsAPI } from "./scim/groups"
20
-
21
18
  export default class API {
22
19
  accounts: AccountAPI
23
20
  auth: AuthAPI
@@ -35,8 +32,6 @@ export default class API {
35
32
  templates: TemplatesAPI
36
33
  license: LicenseAPI
37
34
  auditLogs: AuditLogAPI
38
- scimUsersAPI: ScimUsersAPI
39
- scimGroupsAPI: ScimGroupsAPI
40
35
 
41
36
  constructor(config: TestConfiguration) {
42
37
  this.accounts = new AccountAPI(config)
@@ -55,7 +50,5 @@ export default class API {
55
50
  this.templates = new TemplatesAPI(config)
56
51
  this.license = new LicenseAPI(config)
57
52
  this.auditLogs = new AuditLogAPI(config)
58
- this.scimUsersAPI = new ScimUsersAPI(config)
59
- this.scimGroupsAPI = new ScimGroupsAPI(config)
60
53
  }
61
54
  }
@@ -2,6 +2,7 @@ process.env.SELF_HOSTED = "0"
2
2
  process.env.NODE_ENV = "jest"
3
3
  process.env.JWT_SECRET = "test-jwtsecret"
4
4
  process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
5
+ process.env.ENABLE_4XX_HTTP_LOGGING = "0"
5
6
  process.env.MULTI_TENANCY = "1"
6
7
  process.env.MINIO_URL = "http://localhost"
7
8
  process.env.MINIO_ACCESS_KEY = "test"
@@ -1,3 +1,5 @@
1
+ import "./logging"
2
+
1
3
  import { mocks, testContainerUtils } from "@budibase/backend-core/tests"
2
4
  import env from "../environment"
3
5
  import { env as coreEnv, timers } from "@budibase/backend-core"
@@ -0,0 +1,34 @@
1
+ export enum LogLevel {
2
+ TRACE = "trace",
3
+ DEBUG = "debug",
4
+ INFO = "info",
5
+ WARN = "warn",
6
+ ERROR = "error",
7
+ }
8
+
9
+ const LOG_INDEX: { [key in LogLevel]: number } = {
10
+ [LogLevel.TRACE]: 1,
11
+ [LogLevel.DEBUG]: 2,
12
+ [LogLevel.INFO]: 3,
13
+ [LogLevel.WARN]: 4,
14
+ [LogLevel.ERROR]: 5,
15
+ }
16
+
17
+ const setIndex = LOG_INDEX[process.env.LOG_LEVEL as LogLevel]
18
+
19
+ if (setIndex > LOG_INDEX.trace) {
20
+ global.console.trace = jest.fn()
21
+ }
22
+
23
+ if (setIndex > LOG_INDEX.debug) {
24
+ global.console.debug = jest.fn()
25
+ }
26
+
27
+ if (setIndex > LOG_INDEX.info) {
28
+ global.console.info = jest.fn()
29
+ global.console.log = jest.fn()
30
+ }
31
+
32
+ if (setIndex > LOG_INDEX.warn) {
33
+ global.console.warn = jest.fn()
34
+ }
@@ -0,0 +1,46 @@
1
+ import fetch from "node-fetch"
2
+ import {
3
+ constants,
4
+ tenancy,
5
+ logging,
6
+ env as coreEnv,
7
+ } from "@budibase/backend-core"
8
+ import { checkSlashesInUrl } from "../utilities"
9
+ import env from "../environment"
10
+ import { SyncUserRequest, User } from "@budibase/types"
11
+
12
+ async function makeAppRequest(url: string, method: string, body: any) {
13
+ if (env.isTest()) {
14
+ return
15
+ }
16
+ const request: any = { headers: {} }
17
+ request.headers[constants.Header.API_KEY] = coreEnv.INTERNAL_API_KEY
18
+ if (tenancy.isTenantIdSet()) {
19
+ request.headers[constants.Header.TENANT_ID] = tenancy.getTenantId()
20
+ }
21
+ if (body) {
22
+ request.headers["Content-Type"] = "application/json"
23
+ request.body = JSON.stringify(body)
24
+ }
25
+ request.method = method
26
+
27
+ // add x-budibase-correlation-id header
28
+ logging.correlation.setHeader(request.headers)
29
+
30
+ return fetch(checkSlashesInUrl(env.APPS_URL + url), request)
31
+ }
32
+
33
+ export async function syncUserInApps(userId: string, previousUser?: User) {
34
+ const body: SyncUserRequest = {
35
+ previousUser,
36
+ }
37
+
38
+ const response = await makeAppRequest(
39
+ `/api/users/metadata/sync/${userId}`,
40
+ "POST",
41
+ body
42
+ )
43
+ if (response && response.status !== 200) {
44
+ throw "Unable to sync user."
45
+ }
46
+ }