@budibase/backend-core 3.2.5 → 3.2.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/dist/index.js +7 -1
- package/dist/index.js.map +2 -2
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +11 -4
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/environment.d.ts +1 -0
- package/dist/src/environment.js +6 -1
- package/dist/src/environment.js.map +1 -1
- package/package.json +11 -4
- package/src/accounts/accounts.ts +0 -82
- package/src/accounts/api.ts +0 -59
- package/src/accounts/index.ts +0 -1
- package/src/auth/auth.ts +0 -210
- package/src/auth/index.ts +0 -1
- package/src/auth/tests/auth.spec.ts +0 -14
- package/src/blacklist/blacklist.ts +0 -54
- package/src/blacklist/index.ts +0 -1
- package/src/blacklist/tests/blacklist.spec.ts +0 -46
- package/src/cache/appMetadata.ts +0 -88
- package/src/cache/base/index.ts +0 -150
- package/src/cache/docWritethrough.ts +0 -105
- package/src/cache/generic.ts +0 -33
- package/src/cache/index.ts +0 -8
- package/src/cache/invite.ts +0 -86
- package/src/cache/passwordReset.ts +0 -49
- package/src/cache/tests/docWritethrough.spec.ts +0 -296
- package/src/cache/tests/user.spec.ts +0 -145
- package/src/cache/tests/writethrough.spec.ts +0 -139
- package/src/cache/user.ts +0 -154
- package/src/cache/writethrough.ts +0 -133
- package/src/configs/configs.ts +0 -263
- package/src/configs/index.ts +0 -1
- package/src/configs/tests/configs.spec.ts +0 -184
- package/src/constants/db.ts +0 -75
- package/src/constants/index.ts +0 -2
- package/src/constants/misc.ts +0 -36
- package/src/context/Context.ts +0 -14
- package/src/context/identity.ts +0 -58
- package/src/context/index.ts +0 -3
- package/src/context/mainContext.ts +0 -422
- package/src/context/tests/index.spec.ts +0 -255
- package/src/context/types.ts +0 -26
- package/src/db/Replication.ts +0 -94
- package/src/db/couch/DatabaseImpl.ts +0 -511
- package/src/db/couch/connections.ts +0 -89
- package/src/db/couch/index.ts +0 -4
- package/src/db/couch/pouchDB.ts +0 -97
- package/src/db/couch/pouchDump.ts +0 -0
- package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
- package/src/db/couch/utils.ts +0 -55
- package/src/db/db.ts +0 -34
- package/src/db/errors.ts +0 -14
- package/src/db/index.ts +0 -12
- package/src/db/instrumentation.ts +0 -199
- package/src/db/lucene.ts +0 -721
- package/src/db/searchIndexes/index.ts +0 -1
- package/src/db/searchIndexes/searchIndexes.ts +0 -62
- package/src/db/tests/DatabaseImpl.spec.ts +0 -55
- package/src/db/tests/connections.spec.ts +0 -22
- package/src/db/tests/index.spec.ts +0 -32
- package/src/db/tests/lucene.spec.ts +0 -400
- package/src/db/tests/pouch.spec.js +0 -62
- package/src/db/tests/utils.spec.ts +0 -63
- package/src/db/utils.ts +0 -208
- package/src/db/views.ts +0 -245
- package/src/docIds/conversions.ts +0 -60
- package/src/docIds/ids.ts +0 -126
- package/src/docIds/index.ts +0 -2
- package/src/docIds/newid.ts +0 -5
- package/src/docIds/params.ts +0 -189
- package/src/docUpdates/index.ts +0 -24
- package/src/environment.ts +0 -293
- package/src/errors/errors.ts +0 -119
- package/src/errors/index.ts +0 -1
- package/src/events/analytics.ts +0 -6
- package/src/events/asyncEvents/index.ts +0 -2
- package/src/events/asyncEvents/publisher.ts +0 -12
- package/src/events/asyncEvents/queue.ts +0 -22
- package/src/events/backfill.ts +0 -183
- package/src/events/documentId.ts +0 -56
- package/src/events/events.ts +0 -47
- package/src/events/identification.ts +0 -311
- package/src/events/index.ts +0 -15
- package/src/events/processors/AnalyticsProcessor.ts +0 -64
- package/src/events/processors/AuditLogsProcessor.ts +0 -92
- package/src/events/processors/LoggingProcessor.ts +0 -36
- package/src/events/processors/Processors.ts +0 -52
- package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
- package/src/events/processors/index.ts +0 -19
- package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
- package/src/events/processors/posthog/index.ts +0 -3
- package/src/events/processors/posthog/rateLimiting.ts +0 -106
- package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
- package/src/events/processors/types.ts +0 -1
- package/src/events/publishers/account.ts +0 -41
- package/src/events/publishers/ai.ts +0 -21
- package/src/events/publishers/app.ts +0 -168
- package/src/events/publishers/auditLog.ts +0 -26
- package/src/events/publishers/auth.ts +0 -73
- package/src/events/publishers/automation.ts +0 -110
- package/src/events/publishers/backfill.ts +0 -74
- package/src/events/publishers/backup.ts +0 -42
- package/src/events/publishers/datasource.ts +0 -48
- package/src/events/publishers/email.ts +0 -17
- package/src/events/publishers/environmentVariable.ts +0 -38
- package/src/events/publishers/group.ts +0 -99
- package/src/events/publishers/index.ts +0 -25
- package/src/events/publishers/installation.ts +0 -38
- package/src/events/publishers/layout.ts +0 -26
- package/src/events/publishers/license.ts +0 -84
- package/src/events/publishers/org.ts +0 -37
- package/src/events/publishers/plugin.ts +0 -47
- package/src/events/publishers/query.ts +0 -89
- package/src/events/publishers/role.ts +0 -62
- package/src/events/publishers/rows.ts +0 -29
- package/src/events/publishers/screen.ts +0 -36
- package/src/events/publishers/serve.ts +0 -43
- package/src/events/publishers/table.ts +0 -70
- package/src/events/publishers/user.ts +0 -202
- package/src/events/publishers/view.ts +0 -107
- package/src/features/features.ts +0 -277
- package/src/features/index.ts +0 -2
- package/src/features/tests/features.spec.ts +0 -267
- package/src/features/tests/utils.ts +0 -64
- package/src/helpers.ts +0 -9
- package/src/index.ts +0 -59
- package/src/installation.ts +0 -115
- package/src/logging/alerts.ts +0 -26
- package/src/logging/correlation/correlation.ts +0 -15
- package/src/logging/correlation/index.ts +0 -1
- package/src/logging/correlation/middleware.ts +0 -18
- package/src/logging/index.ts +0 -4
- package/src/logging/pino/logger.ts +0 -239
- package/src/logging/pino/middleware.ts +0 -48
- package/src/logging/system.ts +0 -81
- package/src/logging/tests/system.spec.ts +0 -61
- package/src/middleware/adminOnly.ts +0 -9
- package/src/middleware/auditLog.ts +0 -6
- package/src/middleware/authenticated.ts +0 -247
- package/src/middleware/builderOnly.ts +0 -21
- package/src/middleware/builderOrAdmin.ts +0 -21
- package/src/middleware/contentSecurityPolicy.ts +0 -113
- package/src/middleware/csrf.ts +0 -81
- package/src/middleware/errorHandling.ts +0 -43
- package/src/middleware/index.ts +0 -24
- package/src/middleware/internalApi.ts +0 -23
- package/src/middleware/ip.ts +0 -12
- package/src/middleware/joi-validator.ts +0 -58
- package/src/middleware/matchers.ts +0 -39
- package/src/middleware/passport/datasource/google.ts +0 -102
- package/src/middleware/passport/local.ts +0 -54
- package/src/middleware/passport/sso/google.ts +0 -77
- package/src/middleware/passport/sso/oidc.ts +0 -152
- package/src/middleware/passport/sso/sso.ts +0 -138
- package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
- package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
- package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
- package/src/middleware/passport/utils.ts +0 -38
- package/src/middleware/querystringToBody.ts +0 -28
- package/src/middleware/tenancy.ts +0 -36
- package/src/middleware/tests/builder.spec.ts +0 -181
- package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
- package/src/middleware/tests/matchers.spec.ts +0 -100
- package/src/migrations/definitions.ts +0 -40
- package/src/migrations/index.ts +0 -2
- package/src/migrations/migrations.ts +0 -186
- package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
- package/src/migrations/tests/migrations.spec.ts +0 -64
- package/src/objectStore/buckets/app.ts +0 -53
- package/src/objectStore/buckets/global.ts +0 -29
- package/src/objectStore/buckets/index.ts +0 -3
- package/src/objectStore/buckets/plugins.ts +0 -71
- package/src/objectStore/buckets/tests/app.spec.ts +0 -161
- package/src/objectStore/buckets/tests/global.spec.ts +0 -74
- package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
- package/src/objectStore/cloudfront.ts +0 -41
- package/src/objectStore/index.ts +0 -3
- package/src/objectStore/objectStore.ts +0 -585
- package/src/objectStore/utils.ts +0 -113
- package/src/platform/index.ts +0 -3
- package/src/platform/platformDb.ts +0 -6
- package/src/platform/tenants.ts +0 -101
- package/src/platform/tests/tenants.spec.ts +0 -26
- package/src/platform/users.ts +0 -129
- package/src/plugin/index.ts +0 -1
- package/src/plugin/tests/validation.spec.ts +0 -209
- package/src/plugin/utils.ts +0 -175
- package/src/queue/constants.ts +0 -8
- package/src/queue/inMemoryQueue.ts +0 -189
- package/src/queue/index.ts +0 -2
- package/src/queue/listeners.ts +0 -199
- package/src/queue/queue.ts +0 -84
- package/src/redis/index.ts +0 -6
- package/src/redis/init.ts +0 -118
- package/src/redis/redis.ts +0 -358
- package/src/redis/redlockImpl.ts +0 -155
- package/src/redis/tests/redis.spec.ts +0 -207
- package/src/redis/tests/redlockImpl.spec.ts +0 -105
- package/src/redis/utils.ts +0 -128
- package/src/security/auth.ts +0 -24
- package/src/security/encryption.ts +0 -185
- package/src/security/index.ts +0 -1
- package/src/security/permissions.ts +0 -166
- package/src/security/roles.ts +0 -655
- package/src/security/secrets.ts +0 -20
- package/src/security/sessions.ts +0 -123
- package/src/security/tests/auth.spec.ts +0 -45
- package/src/security/tests/encryption.spec.ts +0 -31
- package/src/security/tests/permissions.spec.ts +0 -146
- package/src/security/tests/secrets.spec.ts +0 -35
- package/src/security/tests/sessions.spec.ts +0 -12
- package/src/sql/designDoc.ts +0 -17
- package/src/sql/index.ts +0 -5
- package/src/sql/sql.ts +0 -1854
- package/src/sql/sqlTable.ts +0 -319
- package/src/sql/utils.ts +0 -193
- package/src/tenancy/db.ts +0 -6
- package/src/tenancy/index.ts +0 -2
- package/src/tenancy/tenancy.ts +0 -148
- package/src/tenancy/tests/tenancy.spec.ts +0 -184
- package/src/timers/index.ts +0 -1
- package/src/timers/timers.ts +0 -22
- package/src/users/db.ts +0 -582
- package/src/users/events.ts +0 -176
- package/src/users/index.ts +0 -4
- package/src/users/lookup.ts +0 -99
- package/src/users/test/db.spec.ts +0 -188
- package/src/users/test/utils.spec.ts +0 -67
- package/src/users/users.ts +0 -353
- package/src/users/utils.ts +0 -81
- package/src/utils/Duration.ts +0 -56
- package/src/utils/hashing.ts +0 -15
- package/src/utils/index.ts +0 -4
- package/src/utils/stringUtils.ts +0 -8
- package/src/utils/tests/Duration.spec.ts +0 -19
- package/src/utils/tests/utils.spec.ts +0 -204
- package/src/utils/utils.ts +0 -249
- package/tests/core/logging.ts +0 -34
- package/tests/core/users/users.spec.js +0 -53
- package/tests/core/utilities/index.ts +0 -7
- package/tests/core/utilities/jestUtils.ts +0 -33
- package/tests/core/utilities/mocks/alerts.ts +0 -4
- package/tests/core/utilities/mocks/date.ts +0 -3
- package/tests/core/utilities/mocks/events.ts +0 -132
- package/tests/core/utilities/mocks/index.ts +0 -9
- package/tests/core/utilities/mocks/licenses.ts +0 -119
- package/tests/core/utilities/queue.ts +0 -9
- package/tests/core/utilities/structures/Chance.ts +0 -20
- package/tests/core/utilities/structures/accounts.ts +0 -80
- package/tests/core/utilities/structures/apps.ts +0 -21
- package/tests/core/utilities/structures/common.ts +0 -7
- package/tests/core/utilities/structures/db.ts +0 -12
- package/tests/core/utilities/structures/documents/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
- package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
- package/tests/core/utilities/structures/generator.ts +0 -3
- package/tests/core/utilities/structures/index.ts +0 -15
- package/tests/core/utilities/structures/koa.ts +0 -16
- package/tests/core/utilities/structures/licenses.ts +0 -190
- package/tests/core/utilities/structures/plugins.ts +0 -19
- package/tests/core/utilities/structures/quotas.ts +0 -72
- package/tests/core/utilities/structures/scim.ts +0 -80
- package/tests/core/utilities/structures/sso.ts +0 -118
- package/tests/core/utilities/structures/tenants.ts +0 -5
- package/tests/core/utilities/structures/userGroups.ts +0 -10
- package/tests/core/utilities/structures/users.ts +0 -89
- package/tests/core/utilities/testContainerUtils.ts +0 -165
- package/tests/core/utilities/utils/index.ts +0 -2
- package/tests/core/utilities/utils/queue.ts +0 -27
- package/tests/core/utilities/utils/time.ts +0 -3
- package/tests/extra/DBTestConfiguration.ts +0 -36
- package/tests/extra/index.ts +0 -2
- package/tests/extra/testEnv.ts +0 -95
- package/tests/index.ts +0 -2
- package/tests/jestEnv.ts +0 -10
- package/tests/jestSetup.ts +0 -36
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { User } from "@budibase/types"
|
|
2
|
-
import { generator, structures } from "../../../tests"
|
|
3
|
-
import { DBTestConfiguration } from "../../../tests/extra"
|
|
4
|
-
import { getUsers } from "../user"
|
|
5
|
-
import { getGlobalDB } from "../../context"
|
|
6
|
-
import _ from "lodash"
|
|
7
|
-
|
|
8
|
-
import * as redis from "../../redis/init"
|
|
9
|
-
import { UserDB } from "../../users"
|
|
10
|
-
|
|
11
|
-
const config = new DBTestConfiguration()
|
|
12
|
-
|
|
13
|
-
describe("user cache", () => {
|
|
14
|
-
describe("getUsers", () => {
|
|
15
|
-
const users: User[] = []
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
const userCount = 10
|
|
18
|
-
const userIds = generator.arrayOf(() => generator.guid(), {
|
|
19
|
-
min: userCount,
|
|
20
|
-
max: userCount,
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
await config.doInTenant(async () => {
|
|
24
|
-
const db = getGlobalDB()
|
|
25
|
-
for (const userId of userIds) {
|
|
26
|
-
const user = structures.users.user({ _id: userId })
|
|
27
|
-
await db.put(user)
|
|
28
|
-
users.push(user)
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
beforeEach(async () => {
|
|
34
|
-
jest.clearAllMocks()
|
|
35
|
-
|
|
36
|
-
const redisClient = await redis.getUserClient()
|
|
37
|
-
await redisClient.clear()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it("when no user is in cache, all of them are retrieved from db", async () => {
|
|
41
|
-
const usersToRequest = _.sampleSize(users, 5)
|
|
42
|
-
|
|
43
|
-
const userIdsToRequest = usersToRequest.map(x => x._id!)
|
|
44
|
-
|
|
45
|
-
jest.spyOn(UserDB, "bulkGet")
|
|
46
|
-
|
|
47
|
-
const results = await config.doInTenant(() => getUsers(userIdsToRequest))
|
|
48
|
-
|
|
49
|
-
expect(results.users).toHaveLength(5)
|
|
50
|
-
expect(results).toEqual({
|
|
51
|
-
users: usersToRequest.map(u => ({
|
|
52
|
-
...u,
|
|
53
|
-
budibaseAccess: true,
|
|
54
|
-
_rev: expect.any(String),
|
|
55
|
-
})),
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
expect(UserDB.bulkGet).toHaveBeenCalledTimes(1)
|
|
59
|
-
expect(UserDB.bulkGet).toHaveBeenCalledWith(userIdsToRequest)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it("on a second all, all of them are retrieved from cache", async () => {
|
|
63
|
-
const usersToRequest = _.sampleSize(users, 5)
|
|
64
|
-
|
|
65
|
-
const userIdsToRequest = usersToRequest.map(x => x._id!)
|
|
66
|
-
|
|
67
|
-
jest.spyOn(UserDB, "bulkGet")
|
|
68
|
-
|
|
69
|
-
await config.doInTenant(() => getUsers(userIdsToRequest))
|
|
70
|
-
const resultsFromCache = await config.doInTenant(() =>
|
|
71
|
-
getUsers(userIdsToRequest)
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
expect(resultsFromCache.users).toHaveLength(5)
|
|
75
|
-
expect(resultsFromCache).toEqual({
|
|
76
|
-
users: expect.arrayContaining(
|
|
77
|
-
usersToRequest.map(u => ({
|
|
78
|
-
...u,
|
|
79
|
-
budibaseAccess: true,
|
|
80
|
-
_rev: expect.any(String),
|
|
81
|
-
}))
|
|
82
|
-
),
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
expect(UserDB.bulkGet).toHaveBeenCalledTimes(1)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it("when some users are cached, only the missing ones are retrieved from db", async () => {
|
|
89
|
-
const usersToRequest = _.sampleSize(users, 5)
|
|
90
|
-
|
|
91
|
-
const userIdsToRequest = usersToRequest.map(x => x._id!)
|
|
92
|
-
|
|
93
|
-
jest.spyOn(UserDB, "bulkGet")
|
|
94
|
-
|
|
95
|
-
await config.doInTenant(() =>
|
|
96
|
-
getUsers([userIdsToRequest[0], userIdsToRequest[3]])
|
|
97
|
-
)
|
|
98
|
-
;(UserDB.bulkGet as jest.Mock).mockClear()
|
|
99
|
-
|
|
100
|
-
const results = await config.doInTenant(() => getUsers(userIdsToRequest))
|
|
101
|
-
|
|
102
|
-
expect(results.users).toHaveLength(5)
|
|
103
|
-
expect(results).toEqual({
|
|
104
|
-
users: expect.arrayContaining(
|
|
105
|
-
usersToRequest.map(u => ({
|
|
106
|
-
...u,
|
|
107
|
-
budibaseAccess: true,
|
|
108
|
-
_rev: expect.any(String),
|
|
109
|
-
}))
|
|
110
|
-
),
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
expect(UserDB.bulkGet).toHaveBeenCalledTimes(1)
|
|
114
|
-
expect(UserDB.bulkGet).toHaveBeenCalledWith([
|
|
115
|
-
userIdsToRequest[1],
|
|
116
|
-
userIdsToRequest[2],
|
|
117
|
-
userIdsToRequest[4],
|
|
118
|
-
])
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
it("requesting existing and unexisting ids will return found ones", async () => {
|
|
122
|
-
const usersToRequest = _.sampleSize(users, 3)
|
|
123
|
-
const missingIds = [generator.guid(), generator.guid()]
|
|
124
|
-
|
|
125
|
-
const userIdsToRequest = _.shuffle([
|
|
126
|
-
...missingIds,
|
|
127
|
-
...usersToRequest.map(x => x._id!),
|
|
128
|
-
])
|
|
129
|
-
|
|
130
|
-
const results = await config.doInTenant(() => getUsers(userIdsToRequest))
|
|
131
|
-
|
|
132
|
-
expect(results.users).toHaveLength(3)
|
|
133
|
-
expect(results).toEqual({
|
|
134
|
-
users: expect.arrayContaining(
|
|
135
|
-
usersToRequest.map(u => ({
|
|
136
|
-
...u,
|
|
137
|
-
budibaseAccess: true,
|
|
138
|
-
_rev: expect.any(String),
|
|
139
|
-
}))
|
|
140
|
-
),
|
|
141
|
-
notFoundIds: expect.arrayContaining(missingIds),
|
|
142
|
-
})
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
})
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { DBTestConfiguration } from "../../../tests/extra"
|
|
2
|
-
import { structures } from "../../../tests"
|
|
3
|
-
import { Writethrough } from "../writethrough"
|
|
4
|
-
import { getDB } from "../../db"
|
|
5
|
-
import { Document } from "@budibase/types"
|
|
6
|
-
import tk from "timekeeper"
|
|
7
|
-
|
|
8
|
-
tk.freeze(Date.now())
|
|
9
|
-
|
|
10
|
-
interface ValueDoc extends Document {
|
|
11
|
-
value: any
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const DELAY = 5000
|
|
15
|
-
|
|
16
|
-
describe("writethrough", () => {
|
|
17
|
-
const config = new DBTestConfiguration()
|
|
18
|
-
|
|
19
|
-
const db = getDB(structures.db.id())
|
|
20
|
-
const db2 = getDB(structures.db.id())
|
|
21
|
-
|
|
22
|
-
const writethrough = new Writethrough(db, DELAY)
|
|
23
|
-
const writethrough2 = new Writethrough(db2, DELAY)
|
|
24
|
-
|
|
25
|
-
const docId = structures.uuid()
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
jest.clearAllMocks()
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
describe("put", () => {
|
|
32
|
-
let current: any
|
|
33
|
-
|
|
34
|
-
it("should be able to store, will go to DB", async () => {
|
|
35
|
-
await config.doInTenant(async () => {
|
|
36
|
-
const response = await writethrough.put({
|
|
37
|
-
_id: docId,
|
|
38
|
-
value: 1,
|
|
39
|
-
})
|
|
40
|
-
const output = await db.get<any>(response.id)
|
|
41
|
-
current = output
|
|
42
|
-
expect(output.value).toBe(1)
|
|
43
|
-
})
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it("second put shouldn't update DB", async () => {
|
|
47
|
-
await config.doInTenant(async () => {
|
|
48
|
-
const response = await writethrough.put({ ...current, value: 2 })
|
|
49
|
-
const output = await db.get<any>(response.id)
|
|
50
|
-
expect(current._rev).toBe(output._rev)
|
|
51
|
-
expect(output.value).toBe(1)
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it("should put it again after delay period", async () => {
|
|
56
|
-
await config.doInTenant(async () => {
|
|
57
|
-
tk.freeze(Date.now() + DELAY + 1)
|
|
58
|
-
const response = await writethrough.put({ ...current, value: 3 })
|
|
59
|
-
const output = await db.get<any>(response.id)
|
|
60
|
-
expect(response.rev).not.toBe(current._rev)
|
|
61
|
-
expect(output.value).toBe(3)
|
|
62
|
-
|
|
63
|
-
current = output
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it("should handle parallel DB updates ignoring conflicts", async () => {
|
|
68
|
-
await config.doInTenant(async () => {
|
|
69
|
-
tk.freeze(Date.now() + DELAY + 1)
|
|
70
|
-
const responses = await Promise.all([
|
|
71
|
-
writethrough.put({ ...current, value: 4 }),
|
|
72
|
-
writethrough.put({ ...current, value: 4 }),
|
|
73
|
-
writethrough.put({ ...current, value: 4 }),
|
|
74
|
-
])
|
|
75
|
-
|
|
76
|
-
// with a lock, this will work
|
|
77
|
-
const newRev = responses.map(x => x.rev).find(x => x !== current._rev)
|
|
78
|
-
expect(newRev).toBeDefined()
|
|
79
|
-
expect(responses.map(x => x.rev)).toEqual(
|
|
80
|
-
expect.arrayContaining([current._rev, current._rev, newRev])
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
const output = await db.get<any>(current._id)
|
|
84
|
-
expect(output.value).toBe(4)
|
|
85
|
-
expect(output._rev).toBe(newRev)
|
|
86
|
-
|
|
87
|
-
current = output
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it("should handle updates with documents falling behind", async () => {
|
|
92
|
-
await config.doInTenant(async () => {
|
|
93
|
-
tk.freeze(Date.now() + DELAY + 1)
|
|
94
|
-
|
|
95
|
-
const id = structures.uuid()
|
|
96
|
-
await writethrough.put({ _id: id, value: 1 })
|
|
97
|
-
const doc = await writethrough.get(id)
|
|
98
|
-
|
|
99
|
-
// Updating document
|
|
100
|
-
tk.freeze(Date.now() + DELAY + 1)
|
|
101
|
-
await writethrough.put({ ...doc, value: 2 })
|
|
102
|
-
|
|
103
|
-
// Update with the old rev value
|
|
104
|
-
tk.freeze(Date.now() + DELAY + 1)
|
|
105
|
-
const res = await writethrough.put({
|
|
106
|
-
...doc,
|
|
107
|
-
value: 3,
|
|
108
|
-
})
|
|
109
|
-
expect(res.ok).toBe(true)
|
|
110
|
-
|
|
111
|
-
const output = await db.get<any>(id)
|
|
112
|
-
expect(output.value).toBe(3)
|
|
113
|
-
expect(output._rev).toBe(res.rev)
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
describe("get", () => {
|
|
119
|
-
it("should be able to retrieve", async () => {
|
|
120
|
-
await config.doInTenant(async () => {
|
|
121
|
-
const response = await writethrough.get<ValueDoc>(docId)
|
|
122
|
-
expect(response.value).toBe(4)
|
|
123
|
-
})
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe("same doc, different databases (tenancy)", () => {
|
|
128
|
-
it("should be able to two different databases", async () => {
|
|
129
|
-
await config.doInTenant(async () => {
|
|
130
|
-
const resp1 = await writethrough.put({ _id: "db1", value: "first" })
|
|
131
|
-
const resp2 = await writethrough2.put({ _id: "db1", value: "second" })
|
|
132
|
-
expect(resp1.rev).toBeDefined()
|
|
133
|
-
expect(resp2.rev).toBeDefined()
|
|
134
|
-
expect((await db.get<any>("db1")).value).toBe("first")
|
|
135
|
-
expect((await db2.get<any>("db1")).value).toBe("second")
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
})
|
package/src/cache/user.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import * as redis from "../redis/init"
|
|
2
|
-
import * as tenancy from "../tenancy"
|
|
3
|
-
import * as context from "../context"
|
|
4
|
-
import * as platform from "../platform"
|
|
5
|
-
import env from "../environment"
|
|
6
|
-
import * as accounts from "../accounts"
|
|
7
|
-
import { UserDB } from "../users"
|
|
8
|
-
import { sdk } from "@budibase/shared-core"
|
|
9
|
-
import { User, UserMetadata } from "@budibase/types"
|
|
10
|
-
|
|
11
|
-
const EXPIRY_SECONDS = 3600
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* The default populate user function
|
|
15
|
-
*/
|
|
16
|
-
async function populateFromDB(userId: string, tenantId: string) {
|
|
17
|
-
const db = tenancy.getTenantDB(tenantId)
|
|
18
|
-
const user = await db.get<UserMetadata>(userId)
|
|
19
|
-
user.budibaseAccess = true
|
|
20
|
-
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
21
|
-
const account = await accounts.getAccount(user.email)
|
|
22
|
-
if (account) {
|
|
23
|
-
user.account = account
|
|
24
|
-
user.accountPortalAccess = true
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return user
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function populateUsersFromDB(
|
|
32
|
-
userIds: string[]
|
|
33
|
-
): Promise<{ users: User[]; notFoundIds?: string[] }> {
|
|
34
|
-
const getUsersResponse = await UserDB.bulkGet(userIds)
|
|
35
|
-
|
|
36
|
-
// Handle missed user ids
|
|
37
|
-
const notFoundIds = userIds.filter((uid, i) => !getUsersResponse[i])
|
|
38
|
-
|
|
39
|
-
const users = getUsersResponse.filter(x => x)
|
|
40
|
-
|
|
41
|
-
await Promise.all(
|
|
42
|
-
users.map(async (user: any) => {
|
|
43
|
-
user.budibaseAccess = true
|
|
44
|
-
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
|
|
45
|
-
const account = await accounts.getAccount(user.email)
|
|
46
|
-
if (account) {
|
|
47
|
-
user.account = account
|
|
48
|
-
user.accountPortalAccess = true
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
if (notFoundIds.length) {
|
|
55
|
-
return { users, notFoundIds }
|
|
56
|
-
}
|
|
57
|
-
return { users }
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Get the requested user by id.
|
|
62
|
-
* Use redis cache to first read the user.
|
|
63
|
-
* If not present fallback to loading the user directly and re-caching.
|
|
64
|
-
* @param userId the id of the user to get
|
|
65
|
-
* @param tenantId the tenant of the user to get
|
|
66
|
-
* @param email the email of the user to populate from account if needed
|
|
67
|
-
* @param populateUser function to provide the user for re-caching. default to couch db
|
|
68
|
-
* @returns
|
|
69
|
-
*/
|
|
70
|
-
export async function getUser({
|
|
71
|
-
userId,
|
|
72
|
-
tenantId,
|
|
73
|
-
email,
|
|
74
|
-
populateUser,
|
|
75
|
-
}: {
|
|
76
|
-
userId: string
|
|
77
|
-
email?: string
|
|
78
|
-
tenantId?: string
|
|
79
|
-
populateUser?: (
|
|
80
|
-
userId: string,
|
|
81
|
-
tenantId: string,
|
|
82
|
-
email?: string
|
|
83
|
-
) => Promise<User>
|
|
84
|
-
}) {
|
|
85
|
-
if (!populateUser) {
|
|
86
|
-
populateUser = populateFromDB
|
|
87
|
-
}
|
|
88
|
-
if (!tenantId) {
|
|
89
|
-
try {
|
|
90
|
-
tenantId = context.getTenantId()
|
|
91
|
-
} catch (err) {
|
|
92
|
-
tenantId = await platform.users.lookupTenantId(userId)
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const client = await redis.getUserClient()
|
|
96
|
-
// try cache
|
|
97
|
-
let user: User = await client.get(userId)
|
|
98
|
-
if (!user) {
|
|
99
|
-
user = await populateUser(userId, tenantId, email)
|
|
100
|
-
await client.store(userId, user, EXPIRY_SECONDS)
|
|
101
|
-
}
|
|
102
|
-
if (user && !user.tenantId && tenantId) {
|
|
103
|
-
// make sure the tenant ID is always correct/set
|
|
104
|
-
user.tenantId = tenantId
|
|
105
|
-
}
|
|
106
|
-
// if has groups, could have builder permissions granted by a group
|
|
107
|
-
if (user.userGroups && !sdk.users.isGlobalBuilder(user)) {
|
|
108
|
-
await context.doInTenant(tenantId, async () => {
|
|
109
|
-
const appIds = await UserDB.getGroupBuilderAppIds(user)
|
|
110
|
-
if (appIds.length) {
|
|
111
|
-
const existing = user.builder?.apps || []
|
|
112
|
-
user.builder = {
|
|
113
|
-
apps: [...new Set(existing.concat(appIds))],
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
}
|
|
118
|
-
return user
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Get the requested users by id.
|
|
123
|
-
* Use redis cache to first read the users.
|
|
124
|
-
* If not present fallback to loading the users directly and re-caching.
|
|
125
|
-
* @param userIds the ids of the user to get
|
|
126
|
-
* @param tenantId the tenant of the users to get
|
|
127
|
-
* @returns
|
|
128
|
-
*/
|
|
129
|
-
export async function getUsers(
|
|
130
|
-
userIds: string[]
|
|
131
|
-
): Promise<{ users: User[]; notFoundIds?: string[] }> {
|
|
132
|
-
const client = await redis.getUserClient()
|
|
133
|
-
// try cache
|
|
134
|
-
let usersFromCache = await client.bulkGet<User>(userIds)
|
|
135
|
-
const missingUsersFromCache = userIds.filter(uid => !usersFromCache[uid])
|
|
136
|
-
const users = Object.values(usersFromCache)
|
|
137
|
-
let notFoundIds
|
|
138
|
-
|
|
139
|
-
if (missingUsersFromCache.length) {
|
|
140
|
-
const usersFromDb = await populateUsersFromDB(missingUsersFromCache)
|
|
141
|
-
|
|
142
|
-
notFoundIds = usersFromDb.notFoundIds
|
|
143
|
-
for (const userToCache of usersFromDb.users) {
|
|
144
|
-
await client.store(userToCache._id!, userToCache, EXPIRY_SECONDS)
|
|
145
|
-
}
|
|
146
|
-
users.push(...usersFromDb.users)
|
|
147
|
-
}
|
|
148
|
-
return { users, notFoundIds: notFoundIds }
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export async function invalidateUser(userId: string) {
|
|
152
|
-
const client = await redis.getUserClient()
|
|
153
|
-
await client.delete(userId)
|
|
154
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import BaseCache from "./base"
|
|
2
|
-
import { getWritethroughClient } from "../redis/init"
|
|
3
|
-
import { logWarn } from "../logging"
|
|
4
|
-
import { Database, Document, LockName, LockType } from "@budibase/types"
|
|
5
|
-
import * as locks from "../redis/redlockImpl"
|
|
6
|
-
|
|
7
|
-
const DEFAULT_WRITE_RATE_MS = 10000
|
|
8
|
-
let CACHE: BaseCache | null = null
|
|
9
|
-
|
|
10
|
-
interface CacheItem<T extends Document> {
|
|
11
|
-
doc: T
|
|
12
|
-
lastWrite: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async function getCache() {
|
|
16
|
-
if (!CACHE) {
|
|
17
|
-
const client = await getWritethroughClient()
|
|
18
|
-
CACHE = new BaseCache(client)
|
|
19
|
-
}
|
|
20
|
-
return CACHE
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function makeCacheKey(db: Database, key: string) {
|
|
24
|
-
return db.name + key
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function makeCacheItem<T extends Document>(
|
|
28
|
-
doc: T,
|
|
29
|
-
lastWrite: number | null = null
|
|
30
|
-
): CacheItem<T> {
|
|
31
|
-
return { doc, lastWrite: lastWrite || Date.now() }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function put(
|
|
35
|
-
db: Database,
|
|
36
|
-
doc: Document,
|
|
37
|
-
writeRateMs: number = DEFAULT_WRITE_RATE_MS
|
|
38
|
-
) {
|
|
39
|
-
const cache = await getCache()
|
|
40
|
-
const key = doc._id
|
|
41
|
-
let cacheItem: CacheItem<any> | undefined
|
|
42
|
-
if (key) {
|
|
43
|
-
cacheItem = await cache.get(makeCacheKey(db, key))
|
|
44
|
-
}
|
|
45
|
-
const updateDb = !cacheItem || cacheItem.lastWrite < Date.now() - writeRateMs
|
|
46
|
-
let output = doc
|
|
47
|
-
if (updateDb) {
|
|
48
|
-
const lockResponse = await locks.doWithLock(
|
|
49
|
-
{
|
|
50
|
-
type: LockType.TRY_ONCE,
|
|
51
|
-
name: LockName.PERSIST_WRITETHROUGH,
|
|
52
|
-
resource: key,
|
|
53
|
-
ttl: 15000,
|
|
54
|
-
},
|
|
55
|
-
async () => {
|
|
56
|
-
const writeDb = async (toWrite: any) => {
|
|
57
|
-
// doc should contain the _id and _rev
|
|
58
|
-
const response = await db.put(toWrite, { force: true })
|
|
59
|
-
output._id = response.id
|
|
60
|
-
output._rev = response.rev
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
await writeDb(doc)
|
|
64
|
-
} catch (err: any) {
|
|
65
|
-
if (err.status !== 409) {
|
|
66
|
-
throw err
|
|
67
|
-
} else {
|
|
68
|
-
// Swallow 409s but log them
|
|
69
|
-
logWarn(`Ignoring conflict in write-through cache`)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
if (!lockResponse.executed) {
|
|
76
|
-
logWarn(`Ignoring redlock conflict in write-through cache`)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// if we are updating the DB then need to set the lastWrite to now
|
|
80
|
-
cacheItem = makeCacheItem(output, updateDb ? null : cacheItem?.lastWrite)
|
|
81
|
-
if (output._id) {
|
|
82
|
-
await cache.store(makeCacheKey(db, output._id), cacheItem)
|
|
83
|
-
}
|
|
84
|
-
return { ok: true, id: output._id, rev: output._rev }
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function get<T extends Document>(db: Database, id: string): Promise<T> {
|
|
88
|
-
const cache = await getCache()
|
|
89
|
-
const cacheKey = makeCacheKey(db, id)
|
|
90
|
-
let cacheItem: CacheItem<T> = await cache.get(cacheKey)
|
|
91
|
-
if (!cacheItem) {
|
|
92
|
-
const doc = await db.get<T>(id)
|
|
93
|
-
cacheItem = makeCacheItem(doc)
|
|
94
|
-
await cache.store(cacheKey, cacheItem)
|
|
95
|
-
}
|
|
96
|
-
return cacheItem.doc
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async function remove(db: Database, docOrId: any, rev?: any): Promise<void> {
|
|
100
|
-
const cache = await getCache()
|
|
101
|
-
if (!docOrId) {
|
|
102
|
-
throw new Error("No ID/Rev provided.")
|
|
103
|
-
}
|
|
104
|
-
const id = typeof docOrId === "string" ? docOrId : docOrId._id
|
|
105
|
-
rev = typeof docOrId === "string" ? rev : docOrId._rev
|
|
106
|
-
try {
|
|
107
|
-
await cache.delete(makeCacheKey(db, id))
|
|
108
|
-
} finally {
|
|
109
|
-
await db.remove(id, rev)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export class Writethrough {
|
|
114
|
-
db: Database
|
|
115
|
-
writeRateMs: number
|
|
116
|
-
|
|
117
|
-
constructor(db: Database, writeRateMs: number = DEFAULT_WRITE_RATE_MS) {
|
|
118
|
-
this.db = db
|
|
119
|
-
this.writeRateMs = writeRateMs
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async put(doc: any, writeRateMs: number = this.writeRateMs) {
|
|
123
|
-
return put(this.db, doc, writeRateMs)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async get<T extends Document>(id: string) {
|
|
127
|
-
return get<T>(this.db, id)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async remove(docOrId: any, rev?: any) {
|
|
131
|
-
return remove(this.db, docOrId, rev)
|
|
132
|
-
}
|
|
133
|
-
}
|