@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.
- package/dist/index.js +61 -48
- package/dist/index.js.map +3 -3
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +4 -4
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/cache/writethrough.d.ts +1 -1
- package/dist/src/cache/writethrough.js +2 -2
- package/dist/src/cache/writethrough.js.map +1 -1
- package/dist/src/security/roles.d.ts +4 -1
- package/dist/src/security/roles.js +8 -5
- package/dist/src/security/roles.js.map +1 -1
- package/dist/src/users/db.d.ts +1 -1
- package/dist/src/users/db.js +11 -4
- package/dist/src/users/db.js.map +1 -1
- package/dist/src/users/users.d.ts +1 -1
- package/dist/tests/core/utilities/structures/licenses.js +8 -0
- package/dist/tests/core/utilities/structures/licenses.js.map +1 -1
- package/package.json +4 -4
- package/src/cache/writethrough.ts +2 -2
- package/src/security/roles.ts +14 -5
- package/src/users/db.ts +62 -46
- package/src/users/users.ts +1 -1
- package/tests/core/users/users.spec.js +54 -0
- package/tests/core/utilities/structures/licenses.ts +8 -0
|
@@ -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":"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
|
|
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.
|
|
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.
|
|
27
|
-
"@budibase/types": "2.
|
|
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": "
|
|
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,
|
|
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) {
|
package/src/security/roles.ts
CHANGED
|
@@ -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
|
|
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(
|
|
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(
|
|
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 = (
|
|
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
|
-
|
|
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(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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
|
-
|
|
351
|
-
|
|
363
|
+
const usersToBulkSave = await Promise.all(usersToSave)
|
|
364
|
+
await usersCore.bulkUpdateGlobalUsers(usersToBulkSave)
|
|
352
365
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
-
|
|
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" })
|
package/src/users/users.ts
CHANGED
|
@@ -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
|
}
|