@budibase/backend-core 2.11.45 → 2.12.1

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.
@@ -1,4 +1,4 @@
1
- import { BulkDocsResponse, ContextUser, SearchQuery, SearchUsersRequest, User } from "@budibase/types";
1
+ import { BulkDocsResponse, SearchQuery, SearchUsersRequest, User, ContextUser } from "@budibase/types";
2
2
  type GetOpts = {
3
3
  cleanup?: boolean;
4
4
  };
@@ -109,6 +109,10 @@ exports.customer = customer;
109
109
  function subscription() {
110
110
  return {
111
111
  amount: 10000,
112
+ amounts: {
113
+ user: 10000,
114
+ creator: 0,
115
+ },
112
116
  cancelAt: undefined,
113
117
  currency: "usd",
114
118
  currentPeriodEnd: 0,
@@ -117,6 +121,10 @@ function subscription() {
117
121
  duration: types_1.PriceDuration.MONTHLY,
118
122
  pastDueAt: undefined,
119
123
  quantity: 0,
124
+ quantities: {
125
+ user: 0,
126
+ creator: 0,
127
+ },
120
128
  status: "active",
121
129
  };
122
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"licenses.js","sourceRoot":"","sources":["../../../../../tests/core/utilities/structures/licenses.ts"],"names":[],"mappings":";;;AAAA,2CAcwB;AACxB,2CAAuC;AAEvC,SAAgB,KAAK;IACnB,OAAO;QACL,MAAM,EAAE,KAAK;QACb,aAAa,EAAE,KAAK;QACpB,QAAQ,EAAE,KAAK;QACf,QAAQ,EAAE,qBAAa,CAAC,OAAO;QAC/B,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,IAAI;KAChB,CAAA;AACH,CAAC;AAVD,sBAUC;AAEM,MAAM,IAAI,GAAG,CAAC,OAAiB,gBAAQ,CAAC,IAAI,EAAiB,EAAE;IACpE,OAAO;QACL,IAAI;QACJ,aAAa,EAAE,KAAK;QACpB,KAAK,EAAE,iBAAS,CAAC,QAAQ;QACzB,KAAK,EAAE,IAAI,KAAK,gBAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;KACpD,CAAA;AACH,CAAC,CAAA;AAPY,QAAA,IAAI,QAOhB;AAED,SAAgB,MAAM;IACpB,OAAO;QACL,KAAK,EAAE;YACL,OAAO,EAAE;gBACP,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,WAAW,EAAE;oBACX,IAAI,EAAE,SAAS;oBACf,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,SAAS;oBACf,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;aACF;YACD,MAAM,EAAE;gBACN,IAAI,EAAE;oBACJ,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,KAAK,EAAE;oBACL,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,UAAU;oBAChB,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,UAAU,EAAE;oBACV,IAAI,EAAE,aAAa;oBACnB,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,SAAS;oBACf,KAAK,EAAE,CAAC;oBACR,QAAQ,EAAE,EAAE;iBACb;aACF;SACF;QACD,QAAQ,EAAE;YACR,0BAA0B,EAAE;gBAC1B,IAAI,EAAE,iBAAiB;gBACvB,KAAK,EAAE,CAAC;gBACR,QAAQ,EAAE,EAAE;aACb;YACD,sBAAsB,EAAE;gBACtB,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,CAAC;gBACR,QAAQ,EAAE,EAAE;aACb;SACF;KACF,CAAA;AACH,CAAC;AAlED,wBAkEC;AAED,SAAgB,OAAO,CACrB,OAA6D,EAAE;IAE/D,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE;QACrC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,YAAY,EAAE;KAClD,CAAA;AACH,CAAC;AAPD,0BAOC;AAED,SAAgB,QAAQ;IACtB,OAAO;QACL,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,KAAK;KAChB,CAAA;AACH,CAAC;AALD,4BAKC;AAED,SAAgB,YAAY;IAC1B,OAAO;QACL,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,KAAK;QACf,gBAAgB,EAAE,CAAC;QACnB,kBAAkB,EAAE,CAAC;QACrB,WAAW,EAAE,CAAC;QACd,QAAQ,EAAE,qBAAa,CAAC,OAAO;QAC/B,SAAS,EAAE,SAAS;QACpB,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,QAAQ;KACjB,CAAA;AACH,CAAC;AAbD,oCAaC;AAUM,MAAM,OAAO,GAAG,CAAC,OAA4B,EAAE,EAAW,EAAE;IACjE,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE;QAC/B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAA,YAAI,EAAC,IAAI,CAAC,QAAQ,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO,EAAE;KACnC,CAAA;AACH,CAAC,CAAA;AAPY,QAAA,OAAO,WAOnB;AAED,SAAgB,cAAc,CAAC,OAA4B,EAAE;IAC3D,MAAM,IAAI,GAAG,IAAA,eAAO,EAAC,IAAI,CAAC,CAAA;IAC1B,uCACK,IAAI,KACP,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAClC,UAAU,EAAE,iBAAiB,EAAE,IAChC;AACH,CAAC;AAPD,wCAOC;AAED,SAAgB,iBAAiB,CAC/B,YAAoB,qBAAS,CAAC,IAAI,EAAE,EACpC,WAAmB,qBAAS,CAAC,IAAI,EAAE;IAEnC,OAAO;QACL,SAAS;QACT,QAAQ;KACT,CAAA;AACH,CAAC;AARD,8CAQC"}
1
+ {"version":3,"file":"licenses.js","sourceRoot":"","sources":["../../../../../tests/core/utilities/structures/licenses.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@budibase/backend-core",
3
- "version": "2.11.45",
3
+ "version": "2.12.1",
4
4
  "description": "Budibase backend core libraries used in server and worker",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -23,8 +23,8 @@
23
23
  "dependencies": {
24
24
  "@budibase/nano": "10.1.2",
25
25
  "@budibase/pouchdb-replication-stream": "1.2.10",
26
- "@budibase/shared-core": "2.11.45",
27
- "@budibase/types": "2.11.45",
26
+ "@budibase/shared-core": "2.12.1",
27
+ "@budibase/types": "2.12.1",
28
28
  "@techpass/passport-openidconnect": "0.3.2",
29
29
  "aws-cloudfront-sign": "3.0.2",
30
30
  "aws-sdk": "2.1030.0",
@@ -96,5 +96,5 @@
96
96
  }
97
97
  }
98
98
  },
99
- "gitHead": "c3b2735a78e2c16d36d6cee6e534c7f7dc39fa98"
99
+ "gitHead": "4ba2bc7442c259d1a5c69e0ae708b97d18fc7d4a"
100
100
  }
@@ -119,8 +119,8 @@ export class Writethrough {
119
119
  this.writeRateMs = writeRateMs
120
120
  }
121
121
 
122
- async put(doc: any) {
123
- return put(this.db, doc, this.writeRateMs)
122
+ async put(doc: any, writeRateMs: number = this.writeRateMs) {
123
+ return put(this.db, doc, writeRateMs)
124
124
  }
125
125
 
126
126
  async get(id: string) {
@@ -122,7 +122,9 @@ export async function roleToNumber(id?: string) {
122
122
  if (isBuiltin(id)) {
123
123
  return builtinRoleToNumber(id)
124
124
  }
125
- const hierarchy = (await getUserRoleHierarchy(id)) as RoleDoc[]
125
+ const hierarchy = (await getUserRoleHierarchy(id, {
126
+ defaultPublic: true,
127
+ })) as RoleDoc[]
126
128
  for (let role of hierarchy) {
127
129
  if (isBuiltin(role?.inherits)) {
128
130
  return builtinRoleToNumber(role.inherits) + 1
@@ -192,12 +194,15 @@ export async function getRole(
192
194
  /**
193
195
  * Simple function to get all the roles based on the top level user role ID.
194
196
  */
195
- async function getAllUserRoles(userRoleId?: string): Promise<RoleDoc[]> {
197
+ async function getAllUserRoles(
198
+ userRoleId?: string,
199
+ opts?: { defaultPublic?: boolean }
200
+ ): Promise<RoleDoc[]> {
196
201
  // admins have access to all roles
197
202
  if (userRoleId === BUILTIN_IDS.ADMIN) {
198
203
  return getAllRoles()
199
204
  }
200
- let currentRole = await getRole(userRoleId)
205
+ let currentRole = await getRole(userRoleId, opts)
201
206
  let roles = currentRole ? [currentRole] : []
202
207
  let roleIds = [userRoleId]
203
208
  // get all the inherited roles
@@ -226,12 +231,16 @@ export async function getUserRoleIdHierarchy(
226
231
  * Returns an ordered array of the user's inherited role IDs, this can be used
227
232
  * to determine if a user can access something that requires a specific role.
228
233
  * @param userRoleId The user's role ID, this can be found in their access token.
234
+ * @param opts optional - if want to default to public use this.
229
235
  * @returns returns an ordered array of the roles, with the first being their
230
236
  * highest level of access and the last being the lowest level.
231
237
  */
232
- export async function getUserRoleHierarchy(userRoleId?: string) {
238
+ export async function getUserRoleHierarchy(
239
+ userRoleId?: string,
240
+ opts?: { defaultPublic?: boolean }
241
+ ) {
233
242
  // special case, if they don't have a role then they are a public user
234
- return getAllUserRoles(userRoleId)
243
+ return getAllUserRoles(userRoleId, opts)
235
244
  }
236
245
 
237
246
  // this function checks that the provided permissions are in an array format
package/src/users/db.ts CHANGED
@@ -25,12 +25,17 @@ import {
25
25
  import {
26
26
  getAccountHolderFromUserIds,
27
27
  isAdmin,
28
+ isCreator,
28
29
  validateUniqueUser,
29
30
  } from "./utils"
30
31
  import { searchExistingEmails } from "./lookup"
31
32
  import { hash } from "../utils"
32
33
 
33
- type QuotaUpdateFn = (change: number, cb?: () => Promise<any>) => Promise<any>
34
+ type QuotaUpdateFn = (
35
+ change: number,
36
+ creatorsChange: number,
37
+ cb?: () => Promise<any>
38
+ ) => Promise<any>
34
39
  type GroupUpdateFn = (groupId: string, userIds: string[]) => Promise<any>
35
40
  type FeatureFn = () => Promise<Boolean>
36
41
  type GroupGetFn = (ids: string[]) => Promise<UserGroup[]>
@@ -245,7 +250,8 @@ export class UserDB {
245
250
  }
246
251
 
247
252
  const change = dbUser ? 0 : 1 // no change if there is existing user
248
- return UserDB.quotas.addUsers(change, async () => {
253
+ const creatorsChange = isCreator(dbUser) !== isCreator(user) ? 1 : 0
254
+ return UserDB.quotas.addUsers(change, creatorsChange, async () => {
249
255
  await validateUniqueUser(email, tenantId)
250
256
 
251
257
  let builtUser = await UserDB.buildUser(user, opts, tenantId, dbUser)
@@ -307,6 +313,7 @@ export class UserDB {
307
313
 
308
314
  let usersToSave: any[] = []
309
315
  let newUsers: any[] = []
316
+ let newCreators: any[] = []
310
317
 
311
318
  const emails = newUsersRequested.map((user: User) => user.email)
312
319
  const existingEmails = await searchExistingEmails(emails)
@@ -327,59 +334,66 @@ export class UserDB {
327
334
  }
328
335
  newUser.userGroups = groups
329
336
  newUsers.push(newUser)
337
+ if (isCreator(newUser)) {
338
+ newCreators.push(newUser)
339
+ }
330
340
  }
331
341
 
332
342
  const account = await accountSdk.getAccountByTenantId(tenantId)
333
- return UserDB.quotas.addUsers(newUsers.length, async () => {
334
- // create the promises array that will be called by bulkDocs
335
- newUsers.forEach((user: any) => {
336
- usersToSave.push(
337
- UserDB.buildUser(
338
- user,
339
- {
340
- hashPassword: true,
341
- requirePassword: user.requirePassword,
342
- },
343
- tenantId,
344
- undefined, // no dbUser
345
- account
343
+ return UserDB.quotas.addUsers(
344
+ newUsers.length,
345
+ newCreators.length,
346
+ async () => {
347
+ // create the promises array that will be called by bulkDocs
348
+ newUsers.forEach((user: any) => {
349
+ usersToSave.push(
350
+ UserDB.buildUser(
351
+ user,
352
+ {
353
+ hashPassword: true,
354
+ requirePassword: user.requirePassword,
355
+ },
356
+ tenantId,
357
+ undefined, // no dbUser
358
+ account
359
+ )
346
360
  )
347
- )
348
- })
361
+ })
349
362
 
350
- const usersToBulkSave = await Promise.all(usersToSave)
351
- await usersCore.bulkUpdateGlobalUsers(usersToBulkSave)
363
+ const usersToBulkSave = await Promise.all(usersToSave)
364
+ await usersCore.bulkUpdateGlobalUsers(usersToBulkSave)
352
365
 
353
- // Post-processing of bulk added users, e.g. events and cache operations
354
- for (const user of usersToBulkSave) {
355
- // TODO: Refactor to bulk insert users into the info db
356
- // instead of relying on looping tenant creation
357
- await platform.users.addUser(tenantId, user._id, user.email)
358
- await eventHelpers.handleSaveEvents(user, undefined)
359
- }
360
-
361
- const saved = usersToBulkSave.map(user => {
362
- return {
363
- _id: user._id,
364
- email: user.email,
366
+ // Post-processing of bulk added users, e.g. events and cache operations
367
+ for (const user of usersToBulkSave) {
368
+ // TODO: Refactor to bulk insert users into the info db
369
+ // instead of relying on looping tenant creation
370
+ await platform.users.addUser(tenantId, user._id, user.email)
371
+ await eventHelpers.handleSaveEvents(user, undefined)
365
372
  }
366
- })
367
373
 
368
- // now update the groups
369
- if (Array.isArray(saved) && groups) {
370
- const groupPromises = []
371
- const createdUserIds = saved.map(user => user._id)
372
- for (let groupId of groups) {
373
- groupPromises.push(UserDB.groups.addUsers(groupId, createdUserIds))
374
+ const saved = usersToBulkSave.map(user => {
375
+ return {
376
+ _id: user._id,
377
+ email: user.email,
378
+ }
379
+ })
380
+
381
+ // now update the groups
382
+ if (Array.isArray(saved) && groups) {
383
+ const groupPromises = []
384
+ const createdUserIds = saved.map(user => user._id)
385
+ for (let groupId of groups) {
386
+ groupPromises.push(UserDB.groups.addUsers(groupId, createdUserIds))
387
+ }
388
+ await Promise.all(groupPromises)
374
389
  }
375
- await Promise.all(groupPromises)
376
- }
377
390
 
378
- return {
379
- successful: saved,
380
- unsuccessful,
391
+ return {
392
+ successful: saved,
393
+ unsuccessful,
394
+ }
381
395
  }
382
- })
396
+ )
383
397
  }
384
398
 
385
399
  static async bulkDelete(userIds: string[]): Promise<BulkUserDeleted> {
@@ -419,11 +433,12 @@ export class UserDB {
419
433
  _deleted: true,
420
434
  }))
421
435
  const dbResponse = await usersCore.bulkUpdateGlobalUsers(toDelete)
436
+ const creatorsToDelete = usersToDelete.filter(isCreator)
422
437
 
423
- await UserDB.quotas.removeUsers(toDelete.length)
424
438
  for (let user of usersToDelete) {
425
439
  await bulkDeleteProcessing(user)
426
440
  }
441
+ await UserDB.quotas.removeUsers(toDelete.length, creatorsToDelete.length)
427
442
 
428
443
  // Build Response
429
444
  // index users by id
@@ -472,7 +487,8 @@ export class UserDB {
472
487
 
473
488
  await db.remove(userId, dbUser._rev)
474
489
 
475
- await UserDB.quotas.removeUsers(1)
490
+ const creatorsToDelete = isCreator(dbUser) ? 1 : 0
491
+ await UserDB.quotas.removeUsers(1, creatorsToDelete)
476
492
  await eventHelpers.handleDeleteEvents(dbUser)
477
493
  await cache.user.invalidateUser(userId)
478
494
  await sessions.invalidateSessions(userId, { reason: "deletion" })
@@ -14,11 +14,11 @@ import {
14
14
  } from "../db"
15
15
  import {
16
16
  BulkDocsResponse,
17
- ContextUser,
18
17
  SearchQuery,
19
18
  SearchQueryOperators,
20
19
  SearchUsersRequest,
21
20
  User,
21
+ ContextUser,
22
22
  DatabaseQueryOpts,
23
23
  } from "@budibase/types"
24
24
  import { getGlobalDB } from "../context"
@@ -0,0 +1,54 @@
1
+ const _ = require('lodash/fp')
2
+ const {structures} = require("../../../tests")
3
+
4
+ jest.mock("../../../src/context")
5
+ jest.mock("../../../src/db")
6
+
7
+ const context = require("../../../src/context")
8
+ const db = require("../../../src/db")
9
+
10
+ const {getCreatorCount} = require('../../../src/users/users')
11
+
12
+ describe("Users", () => {
13
+
14
+ let getGlobalDBMock
15
+ let getGlobalUserParamsMock
16
+ let paginationMock
17
+
18
+ beforeEach(() => {
19
+ jest.resetAllMocks()
20
+
21
+ getGlobalDBMock = jest.spyOn(context, "getGlobalDB")
22
+ getGlobalUserParamsMock = jest.spyOn(db, "getGlobalUserParams")
23
+ paginationMock = jest.spyOn(db, "pagination")
24
+ })
25
+
26
+ it("Retrieves the number of creators", async () => {
27
+ const getUsers = (offset, limit, creators = false) => {
28
+ const range = _.range(offset, limit)
29
+ const opts = creators ? {builder: {global: true}} : undefined
30
+ return range.map(() => structures.users.user(opts))
31
+ }
32
+ const page1Data = getUsers(0, 8)
33
+ const page2Data = getUsers(8, 12, true)
34
+ getGlobalDBMock.mockImplementation(() => ({
35
+ name : "fake-db",
36
+ allDocs: () => ({
37
+ rows: [...page1Data, ...page2Data]
38
+ })
39
+ }))
40
+ paginationMock.mockImplementationOnce(() => ({
41
+ data: page1Data,
42
+ hasNextPage: true,
43
+ nextPage: "1"
44
+ }))
45
+ paginationMock.mockImplementation(() => ({
46
+ data: page2Data,
47
+ hasNextPage: false,
48
+ nextPage: undefined
49
+ }))
50
+ const creatorsCount = await getCreatorCount()
51
+ expect(creatorsCount).toBe(4)
52
+ expect(paginationMock).toHaveBeenCalledTimes(2)
53
+ })
54
+ })
@@ -123,6 +123,10 @@ export function customer(): Customer {
123
123
  export function subscription(): Subscription {
124
124
  return {
125
125
  amount: 10000,
126
+ amounts: {
127
+ user: 10000,
128
+ creator: 0,
129
+ },
126
130
  cancelAt: undefined,
127
131
  currency: "usd",
128
132
  currentPeriodEnd: 0,
@@ -131,6 +135,10 @@ export function subscription(): Subscription {
131
135
  duration: PriceDuration.MONTHLY,
132
136
  pastDueAt: undefined,
133
137
  quantity: 0,
138
+ quantities: {
139
+ user: 0,
140
+ creator: 0,
141
+ },
134
142
  status: "active",
135
143
  }
136
144
  }