@budibase/worker 2.6.19-alpha.0 → 2.6.20

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.6.19-alpha.0",
4
+ "version": "2.6.20",
5
5
  "description": "Budibase background service",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -37,10 +37,10 @@
37
37
  "author": "Budibase",
38
38
  "license": "GPL-3.0",
39
39
  "dependencies": {
40
- "@budibase/backend-core": "2.6.19-alpha.0",
41
- "@budibase/pro": "2.6.19-alpha.0",
42
- "@budibase/string-templates": "2.6.19-alpha.0",
43
- "@budibase/types": "2.6.19-alpha.0",
40
+ "@budibase/backend-core": "^2.6.20",
41
+ "@budibase/pro": "2.6.19",
42
+ "@budibase/string-templates": "^2.6.20",
43
+ "@budibase/types": "^2.6.20",
44
44
  "@koa/router": "8.0.8",
45
45
  "@sentry/node": "6.17.7",
46
46
  "@techpass/passport-openidconnect": "0.3.2",
@@ -102,5 +102,5 @@
102
102
  "typescript": "4.7.3",
103
103
  "update-dotenv": "1.1.1"
104
104
  },
105
- "gitHead": "82e867c0f5b41fe3af88333effeb88f29b8b4d23"
105
+ "gitHead": "174f78b7e28e2071743eeccd29634690c1bb5e5a"
106
106
  }
@@ -69,11 +69,9 @@ const bulkCreate = async (users: User[], groupIds: string[]) => {
69
69
  return await userSdk.bulkCreate(users, groupIds)
70
70
  }
71
71
 
72
- export const bulkUpdate = async (
73
- ctx: Ctx<BulkUserRequest, BulkUserResponse>
74
- ) => {
72
+ export const bulkUpdate = async (ctx: any) => {
75
73
  const currentUserId = ctx.user._id
76
- const input = ctx.request.body
74
+ const input = ctx.request.body as BulkUserRequest
77
75
  let created, deleted
78
76
  try {
79
77
  if (input.create) {
@@ -85,7 +83,7 @@ export const bulkUpdate = async (
85
83
  } catch (err: any) {
86
84
  ctx.throw(err.status || 400, err?.message || err)
87
85
  }
88
- ctx.body = { created, deleted }
86
+ ctx.body = { created, deleted } as BulkUserResponse
89
87
  }
90
88
 
91
89
  const parseBooleanParam = (param: any) => {
@@ -186,15 +184,15 @@ export const destroy = async (ctx: any) => {
186
184
  }
187
185
  }
188
186
 
189
- export const getAppUsers = async (ctx: Ctx<SearchUsersRequest>) => {
190
- const body = ctx.request.body
187
+ export const getAppUsers = async (ctx: any) => {
188
+ const body = ctx.request.body as SearchUsersRequest
191
189
  const users = await userSdk.getUsersByAppAccess(body?.appId)
192
190
 
193
191
  ctx.body = { data: users }
194
192
  }
195
193
 
196
- export const search = async (ctx: Ctx<SearchUsersRequest>) => {
197
- const body = ctx.request.body
194
+ export const search = async (ctx: any) => {
195
+ const body = ctx.request.body as SearchUsersRequest
198
196
 
199
197
  if (body.paginated === false) {
200
198
  await getAppUsers(ctx)
@@ -240,8 +238,8 @@ export const tenantUserLookup = async (ctx: any) => {
240
238
  /*
241
239
  Encapsulate the app user onboarding flows here.
242
240
  */
243
- export const onboardUsers = async (ctx: Ctx<InviteUsersRequest>) => {
244
- const request = ctx.request.body
241
+ export const onboardUsers = async (ctx: any) => {
242
+ const request = ctx.request.body as InviteUsersRequest | BulkUserRequest
245
243
  const isBulkCreate = "create" in request
246
244
 
247
245
  const emailConfigured = await isEmailConfigured()
@@ -257,7 +255,7 @@ export const onboardUsers = async (ctx: Ctx<InviteUsersRequest>) => {
257
255
  } else if (emailConfigured) {
258
256
  onboardingResponse = await inviteMultiple(ctx)
259
257
  } else if (!emailConfigured) {
260
- const inviteRequest = ctx.request.body
258
+ const inviteRequest = ctx.request.body as InviteUsersRequest
261
259
 
262
260
  let createdPasswords: any = {}
263
261
 
@@ -297,10 +295,10 @@ export const onboardUsers = async (ctx: Ctx<InviteUsersRequest>) => {
297
295
  }
298
296
  }
299
297
 
300
- export const invite = async (ctx: Ctx<InviteUserRequest>) => {
301
- const request = ctx.request.body
298
+ export const invite = async (ctx: any) => {
299
+ const request = ctx.request.body as InviteUserRequest
302
300
 
303
- let multiRequest = [request]
301
+ let multiRequest = [request] as InviteUsersRequest
304
302
  const response = await userSdk.invite(multiRequest)
305
303
 
306
304
  // explicitly throw for single user invite
@@ -320,8 +318,8 @@ export const invite = async (ctx: Ctx<InviteUserRequest>) => {
320
318
  }
321
319
  }
322
320
 
323
- export const inviteMultiple = async (ctx: Ctx<InviteUsersRequest>) => {
324
- const request = ctx.request.body
321
+ export const inviteMultiple = async (ctx: any) => {
322
+ const request = ctx.request.body as InviteUsersRequest
325
323
  ctx.body = await userSdk.invite(request)
326
324
  }
327
325
 
@@ -426,6 +424,7 @@ export const inviteAccept = async (
426
424
  if (err.code === ErrorCode.USAGE_LIMIT_EXCEEDED) {
427
425
  // explicitly re-throw limit exceeded errors
428
426
  ctx.throw(400, err)
427
+ return
429
428
  }
430
429
  console.warn("Error inviting user", err)
431
430
  ctx.throw(400, "Unable to create new user, invitation invalid.")
@@ -1,9 +1,5 @@
1
1
  import { events } from "@budibase/backend-core"
2
- import { generator } from "@budibase/backend-core/tests"
3
2
  import { structures, TestConfiguration, mocks } from "../../../../tests"
4
- import { UserGroup } from "@budibase/types"
5
-
6
- mocks.licenses.useGroups()
7
3
 
8
4
  describe("/api/global/groups", () => {
9
5
  const config = new TestConfiguration()
@@ -17,7 +13,6 @@ describe("/api/global/groups", () => {
17
13
  })
18
14
 
19
15
  beforeEach(async () => {
20
- jest.resetAllMocks()
21
16
  mocks.licenses.useGroups()
22
17
  })
23
18
 
@@ -29,63 +24,6 @@ describe("/api/global/groups", () => {
29
24
  expect(events.group.updated).not.toBeCalled()
30
25
  expect(events.group.permissionsEdited).not.toBeCalled()
31
26
  })
32
-
33
- it("should not allow undefined names", async () => {
34
- const group = { ...structures.groups.UserGroup(), name: undefined } as any
35
- const response = await config.api.groups.saveGroup(group, { expect: 400 })
36
- expect(JSON.parse(response.text).message).toEqual(
37
- 'Invalid body - "name" is required'
38
- )
39
- })
40
-
41
- it("should not allow empty names", async () => {
42
- const group = { ...structures.groups.UserGroup(), name: "" }
43
- const response = await config.api.groups.saveGroup(group, { expect: 400 })
44
- expect(JSON.parse(response.text).message).toEqual(
45
- 'Invalid body - "name" is not allowed to be empty'
46
- )
47
- })
48
-
49
- it("should not allow whitespace names", async () => {
50
- const group = { ...structures.groups.UserGroup(), name: " " }
51
- const response = await config.api.groups.saveGroup(group, { expect: 400 })
52
- expect(JSON.parse(response.text).message).toEqual(
53
- 'Invalid body - "name" is not allowed to be empty'
54
- )
55
- })
56
-
57
- it("should trim names", async () => {
58
- const group = { ...structures.groups.UserGroup(), name: " group name " }
59
- await config.api.groups.saveGroup(group)
60
- expect(events.group.created).toBeCalledWith(
61
- expect.objectContaining({ name: "group name" })
62
- )
63
- })
64
-
65
- describe("name max length", () => {
66
- const maxLength = 50
67
-
68
- it(`should allow names shorter than ${maxLength} characters`, async () => {
69
- const group = {
70
- ...structures.groups.UserGroup(),
71
- name: structures.generator.word({ length: maxLength }),
72
- }
73
- await config.api.groups.saveGroup(group, { expect: 200 })
74
- })
75
-
76
- it(`should not allow names longer than ${maxLength} characters`, async () => {
77
- const group = {
78
- ...structures.groups.UserGroup(),
79
- name: structures.generator.word({ length: maxLength + 1 }),
80
- }
81
- const response = await config.api.groups.saveGroup(group, {
82
- expect: 400,
83
- })
84
- expect(JSON.parse(response.text).message).toEqual(
85
- 'Invalid body - "name" length must be less than or equal to 50 characters long'
86
- )
87
- })
88
- })
89
27
  })
90
28
 
91
29
  describe("update", () => {
@@ -117,118 +55,4 @@ describe("/api/global/groups", () => {
117
55
  })
118
56
  })
119
57
  })
120
-
121
- describe("find users", () => {
122
- describe("without users", () => {
123
- let group: UserGroup
124
- beforeAll(async () => {
125
- group = structures.groups.UserGroup()
126
- await config.api.groups.saveGroup(group)
127
- })
128
-
129
- it("should return empty", async () => {
130
- const result = await config.api.groups.searchUsers(group._id!)
131
- expect(result.body).toEqual({
132
- users: [],
133
- bookmark: undefined,
134
- hasNextPage: false,
135
- })
136
- })
137
- })
138
-
139
- describe("existing users", () => {
140
- let groupId: string
141
- let users: { _id: string; email: string }[] = []
142
-
143
- beforeAll(async () => {
144
- groupId = (
145
- await config.api.groups.saveGroup(structures.groups.UserGroup())
146
- ).body._id
147
-
148
- await Promise.all(
149
- Array.from({ length: 30 }).map(async (_, i) => {
150
- const email = `user${i}@${generator.domain()}`
151
- const user = await config.api.users.saveUser({
152
- ...structures.users.user(),
153
- email,
154
- })
155
- users.push({ _id: user.body._id, email })
156
- })
157
- )
158
- users = users.sort((a, b) => a._id.localeCompare(b._id))
159
- await config.api.groups.updateGroupUsers(groupId, {
160
- add: users.map(u => u._id),
161
- remove: [],
162
- })
163
- })
164
-
165
- describe("pagination", () => {
166
- it("should return first page", async () => {
167
- const result = await config.api.groups.searchUsers(groupId)
168
- expect(result.body).toEqual({
169
- users: users.slice(0, 10),
170
- bookmark: users[10]._id,
171
- hasNextPage: true,
172
- })
173
- })
174
-
175
- it("given a bookmark, should return skip items", async () => {
176
- const result = await config.api.groups.searchUsers(groupId, {
177
- bookmark: users[7]._id,
178
- })
179
- expect(result.body).toEqual({
180
- users: users.slice(7, 17),
181
- bookmark: users[17]._id,
182
- hasNextPage: true,
183
- })
184
- })
185
-
186
- it("bookmarking the last page, should return last page info", async () => {
187
- const result = await config.api.groups.searchUsers(groupId, {
188
- bookmark: users[20]._id,
189
- })
190
- expect(result.body).toEqual({
191
- users: users.slice(20),
192
- bookmark: undefined,
193
- hasNextPage: false,
194
- })
195
- })
196
- })
197
-
198
- describe("search by email", () => {
199
- it('should be able to search "starting" by email', async () => {
200
- const result = await config.api.groups.searchUsers(groupId, {
201
- emailSearch: `user1`,
202
- })
203
-
204
- const matchedUsers = users
205
- .filter(u => u.email.startsWith("user1"))
206
- .sort((a, b) => a.email.localeCompare(b.email))
207
-
208
- expect(result.body).toEqual({
209
- users: matchedUsers.slice(0, 10),
210
- bookmark: matchedUsers[10].email,
211
- hasNextPage: true,
212
- })
213
- })
214
-
215
- it("should be able to bookmark when searching by email", async () => {
216
- const matchedUsers = users
217
- .filter(u => u.email.startsWith("user1"))
218
- .sort((a, b) => a.email.localeCompare(b.email))
219
-
220
- const result = await config.api.groups.searchUsers(groupId, {
221
- emailSearch: `user1`,
222
- bookmark: matchedUsers[4].email,
223
- })
224
-
225
- expect(result.body).toEqual({
226
- users: matchedUsers.slice(4),
227
- bookmark: undefined,
228
- hasNextPage: false,
229
- })
230
- })
231
- })
232
- })
233
- })
234
58
  })
@@ -7,13 +7,13 @@ export class GroupsAPI extends TestAPI {
7
7
  super(config)
8
8
  }
9
9
 
10
- saveGroup = (group: UserGroup, { expect } = { expect: 200 }) => {
10
+ saveGroup = (group: UserGroup) => {
11
11
  return this.request
12
12
  .post(`/api/global/groups`)
13
13
  .send(group)
14
14
  .set(this.config.defaultHeaders())
15
15
  .expect("Content-Type", /json/)
16
- .expect(expect)
16
+ .expect(200)
17
17
  }
18
18
 
19
19
  deleteGroup = (id: string, rev: string) => {
@@ -23,34 +23,4 @@ export class GroupsAPI extends TestAPI {
23
23
  .expect("Content-Type", /json/)
24
24
  .expect(200)
25
25
  }
26
-
27
- searchUsers = (
28
- id: string,
29
- params?: { bookmark?: string; emailSearch?: string }
30
- ) => {
31
- let url = `/api/global/groups/${id}/users?`
32
- if (params?.bookmark) {
33
- url += `bookmark=${params.bookmark}&`
34
- }
35
- if (params?.emailSearch) {
36
- url += `emailSearch=${params.emailSearch}&`
37
- }
38
- return this.request
39
- .get(url)
40
- .set(this.config.defaultHeaders())
41
- .expect("Content-Type", /json/)
42
- .expect(200)
43
- }
44
-
45
- updateGroupUsers = (
46
- id: string,
47
- body: { add: string[]; remove: string[] }
48
- ) => {
49
- return this.request
50
- .post(`/api/global/groups/${id}/users`)
51
- .send(body)
52
- .set(this.config.defaultHeaders())
53
- .expect("Content-Type", /json/)
54
- .expect(200)
55
- }
56
26
  }
@@ -1,25 +1,10 @@
1
- import { generator } from "@budibase/backend-core/tests"
2
- import { db } from "@budibase/backend-core"
3
- import { UserGroupRoles } from "@budibase/types"
4
-
5
1
  export const UserGroup = () => {
6
- const appsCount = generator.integer({ min: 0, max: 3 })
7
- const roles = Array.from({ length: appsCount }).reduce(
8
- (p: UserGroupRoles, v) => {
9
- return {
10
- ...p,
11
- [db.generateAppID()]: generator.pickone(["ADMIN", "POWER", "BASIC"]),
12
- }
13
- },
14
- {}
15
- )
16
-
17
2
  let group = {
18
3
  apps: [],
19
- color: generator.color(),
20
- icon: generator.word(),
21
- name: generator.word({ length: 2 }),
22
- roles: roles,
4
+ color: "var(--spectrum-global-color-blue-600)",
5
+ icon: "UserGroup",
6
+ name: "New group",
7
+ roles: { app_uuid1: "ADMIN", app_uuid2: "POWER" },
23
8
  users: [],
24
9
  }
25
10
  return group
@@ -7,7 +7,7 @@ function getExpirySecondsForDB(db: string) {
7
7
  // a hour
8
8
  return 3600
9
9
  case redis.utils.Databases.INVITATIONS:
10
- // a week
10
+ // a day
11
11
  return 604800
12
12
  }
13
13
  }
package/tsconfig.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "@budibase/types": ["../types/src"],
10
10
  "@budibase/backend-core": ["../backend-core/src"],
11
11
  "@budibase/backend-core/*": ["../backend-core/*"],
12
- "@budibase/pro": ["../pro/packages/pro/src"]
12
+ "@budibase/pro": ["../../../budibase-pro/packages/pro/src"]
13
13
  }
14
14
  },
15
15
  "ts-node": {