@budibase/backend-core 3.2.4 → 3.2.6

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.
Files changed (272) hide show
  1. package/dist/index.js.map +1 -1
  2. package/dist/index.js.meta.json +1 -1
  3. package/dist/package.json +11 -4
  4. package/dist/plugins.js.meta.json +1 -1
  5. package/package.json +11 -4
  6. package/src/accounts/accounts.ts +0 -82
  7. package/src/accounts/api.ts +0 -59
  8. package/src/accounts/index.ts +0 -1
  9. package/src/auth/auth.ts +0 -210
  10. package/src/auth/index.ts +0 -1
  11. package/src/auth/tests/auth.spec.ts +0 -14
  12. package/src/blacklist/blacklist.ts +0 -54
  13. package/src/blacklist/index.ts +0 -1
  14. package/src/blacklist/tests/blacklist.spec.ts +0 -46
  15. package/src/cache/appMetadata.ts +0 -88
  16. package/src/cache/base/index.ts +0 -150
  17. package/src/cache/docWritethrough.ts +0 -105
  18. package/src/cache/generic.ts +0 -33
  19. package/src/cache/index.ts +0 -8
  20. package/src/cache/invite.ts +0 -86
  21. package/src/cache/passwordReset.ts +0 -49
  22. package/src/cache/tests/docWritethrough.spec.ts +0 -296
  23. package/src/cache/tests/user.spec.ts +0 -145
  24. package/src/cache/tests/writethrough.spec.ts +0 -139
  25. package/src/cache/user.ts +0 -154
  26. package/src/cache/writethrough.ts +0 -133
  27. package/src/configs/configs.ts +0 -263
  28. package/src/configs/index.ts +0 -1
  29. package/src/configs/tests/configs.spec.ts +0 -184
  30. package/src/constants/db.ts +0 -75
  31. package/src/constants/index.ts +0 -2
  32. package/src/constants/misc.ts +0 -36
  33. package/src/context/Context.ts +0 -14
  34. package/src/context/identity.ts +0 -58
  35. package/src/context/index.ts +0 -3
  36. package/src/context/mainContext.ts +0 -422
  37. package/src/context/tests/index.spec.ts +0 -255
  38. package/src/context/types.ts +0 -26
  39. package/src/db/Replication.ts +0 -94
  40. package/src/db/couch/DatabaseImpl.ts +0 -511
  41. package/src/db/couch/connections.ts +0 -89
  42. package/src/db/couch/index.ts +0 -4
  43. package/src/db/couch/pouchDB.ts +0 -97
  44. package/src/db/couch/pouchDump.ts +0 -0
  45. package/src/db/couch/tests/DatabaseImpl.spec.ts +0 -118
  46. package/src/db/couch/utils.ts +0 -55
  47. package/src/db/db.ts +0 -34
  48. package/src/db/errors.ts +0 -14
  49. package/src/db/index.ts +0 -12
  50. package/src/db/instrumentation.ts +0 -199
  51. package/src/db/lucene.ts +0 -721
  52. package/src/db/searchIndexes/index.ts +0 -1
  53. package/src/db/searchIndexes/searchIndexes.ts +0 -62
  54. package/src/db/tests/DatabaseImpl.spec.ts +0 -55
  55. package/src/db/tests/connections.spec.ts +0 -22
  56. package/src/db/tests/index.spec.ts +0 -32
  57. package/src/db/tests/lucene.spec.ts +0 -400
  58. package/src/db/tests/pouch.spec.js +0 -62
  59. package/src/db/tests/utils.spec.ts +0 -63
  60. package/src/db/utils.ts +0 -208
  61. package/src/db/views.ts +0 -245
  62. package/src/docIds/conversions.ts +0 -60
  63. package/src/docIds/ids.ts +0 -126
  64. package/src/docIds/index.ts +0 -2
  65. package/src/docIds/newid.ts +0 -5
  66. package/src/docIds/params.ts +0 -189
  67. package/src/docUpdates/index.ts +0 -24
  68. package/src/environment.ts +0 -293
  69. package/src/errors/errors.ts +0 -119
  70. package/src/errors/index.ts +0 -1
  71. package/src/events/analytics.ts +0 -6
  72. package/src/events/asyncEvents/index.ts +0 -2
  73. package/src/events/asyncEvents/publisher.ts +0 -12
  74. package/src/events/asyncEvents/queue.ts +0 -22
  75. package/src/events/backfill.ts +0 -183
  76. package/src/events/documentId.ts +0 -56
  77. package/src/events/events.ts +0 -47
  78. package/src/events/identification.ts +0 -311
  79. package/src/events/index.ts +0 -15
  80. package/src/events/processors/AnalyticsProcessor.ts +0 -64
  81. package/src/events/processors/AuditLogsProcessor.ts +0 -92
  82. package/src/events/processors/LoggingProcessor.ts +0 -36
  83. package/src/events/processors/Processors.ts +0 -52
  84. package/src/events/processors/async/DocumentUpdateProcessor.ts +0 -38
  85. package/src/events/processors/index.ts +0 -19
  86. package/src/events/processors/posthog/PosthogProcessor.ts +0 -118
  87. package/src/events/processors/posthog/index.ts +0 -3
  88. package/src/events/processors/posthog/rateLimiting.ts +0 -106
  89. package/src/events/processors/posthog/tests/PosthogProcessor.spec.ts +0 -164
  90. package/src/events/processors/types.ts +0 -1
  91. package/src/events/publishers/account.ts +0 -41
  92. package/src/events/publishers/ai.ts +0 -21
  93. package/src/events/publishers/app.ts +0 -168
  94. package/src/events/publishers/auditLog.ts +0 -26
  95. package/src/events/publishers/auth.ts +0 -73
  96. package/src/events/publishers/automation.ts +0 -110
  97. package/src/events/publishers/backfill.ts +0 -74
  98. package/src/events/publishers/backup.ts +0 -42
  99. package/src/events/publishers/datasource.ts +0 -48
  100. package/src/events/publishers/email.ts +0 -17
  101. package/src/events/publishers/environmentVariable.ts +0 -38
  102. package/src/events/publishers/group.ts +0 -99
  103. package/src/events/publishers/index.ts +0 -25
  104. package/src/events/publishers/installation.ts +0 -38
  105. package/src/events/publishers/layout.ts +0 -26
  106. package/src/events/publishers/license.ts +0 -84
  107. package/src/events/publishers/org.ts +0 -37
  108. package/src/events/publishers/plugin.ts +0 -47
  109. package/src/events/publishers/query.ts +0 -89
  110. package/src/events/publishers/role.ts +0 -62
  111. package/src/events/publishers/rows.ts +0 -29
  112. package/src/events/publishers/screen.ts +0 -36
  113. package/src/events/publishers/serve.ts +0 -43
  114. package/src/events/publishers/table.ts +0 -70
  115. package/src/events/publishers/user.ts +0 -202
  116. package/src/events/publishers/view.ts +0 -107
  117. package/src/features/features.ts +0 -277
  118. package/src/features/index.ts +0 -2
  119. package/src/features/tests/features.spec.ts +0 -267
  120. package/src/features/tests/utils.ts +0 -64
  121. package/src/helpers.ts +0 -9
  122. package/src/index.ts +0 -59
  123. package/src/installation.ts +0 -115
  124. package/src/logging/alerts.ts +0 -26
  125. package/src/logging/correlation/correlation.ts +0 -15
  126. package/src/logging/correlation/index.ts +0 -1
  127. package/src/logging/correlation/middleware.ts +0 -18
  128. package/src/logging/index.ts +0 -4
  129. package/src/logging/pino/logger.ts +0 -239
  130. package/src/logging/pino/middleware.ts +0 -48
  131. package/src/logging/system.ts +0 -81
  132. package/src/logging/tests/system.spec.ts +0 -61
  133. package/src/middleware/adminOnly.ts +0 -9
  134. package/src/middleware/auditLog.ts +0 -6
  135. package/src/middleware/authenticated.ts +0 -247
  136. package/src/middleware/builderOnly.ts +0 -21
  137. package/src/middleware/builderOrAdmin.ts +0 -21
  138. package/src/middleware/contentSecurityPolicy.ts +0 -113
  139. package/src/middleware/csrf.ts +0 -81
  140. package/src/middleware/errorHandling.ts +0 -43
  141. package/src/middleware/index.ts +0 -24
  142. package/src/middleware/internalApi.ts +0 -23
  143. package/src/middleware/ip.ts +0 -12
  144. package/src/middleware/joi-validator.ts +0 -58
  145. package/src/middleware/matchers.ts +0 -39
  146. package/src/middleware/passport/datasource/google.ts +0 -102
  147. package/src/middleware/passport/local.ts +0 -54
  148. package/src/middleware/passport/sso/google.ts +0 -77
  149. package/src/middleware/passport/sso/oidc.ts +0 -152
  150. package/src/middleware/passport/sso/sso.ts +0 -138
  151. package/src/middleware/passport/sso/tests/google.spec.ts +0 -68
  152. package/src/middleware/passport/sso/tests/oidc.spec.ts +0 -144
  153. package/src/middleware/passport/sso/tests/sso.spec.ts +0 -197
  154. package/src/middleware/passport/utils.ts +0 -38
  155. package/src/middleware/querystringToBody.ts +0 -28
  156. package/src/middleware/tenancy.ts +0 -36
  157. package/src/middleware/tests/builder.spec.ts +0 -181
  158. package/src/middleware/tests/contentSecurityPolicy.spec.ts +0 -75
  159. package/src/middleware/tests/matchers.spec.ts +0 -100
  160. package/src/migrations/definitions.ts +0 -40
  161. package/src/migrations/index.ts +0 -2
  162. package/src/migrations/migrations.ts +0 -186
  163. package/src/migrations/tests/__snapshots__/migrations.spec.ts.snap +0 -11
  164. package/src/migrations/tests/migrations.spec.ts +0 -64
  165. package/src/objectStore/buckets/app.ts +0 -53
  166. package/src/objectStore/buckets/global.ts +0 -29
  167. package/src/objectStore/buckets/index.ts +0 -3
  168. package/src/objectStore/buckets/plugins.ts +0 -71
  169. package/src/objectStore/buckets/tests/app.spec.ts +0 -161
  170. package/src/objectStore/buckets/tests/global.spec.ts +0 -74
  171. package/src/objectStore/buckets/tests/plugins.spec.ts +0 -111
  172. package/src/objectStore/cloudfront.ts +0 -41
  173. package/src/objectStore/index.ts +0 -3
  174. package/src/objectStore/objectStore.ts +0 -585
  175. package/src/objectStore/utils.ts +0 -113
  176. package/src/platform/index.ts +0 -3
  177. package/src/platform/platformDb.ts +0 -6
  178. package/src/platform/tenants.ts +0 -101
  179. package/src/platform/tests/tenants.spec.ts +0 -26
  180. package/src/platform/users.ts +0 -129
  181. package/src/plugin/index.ts +0 -1
  182. package/src/plugin/tests/validation.spec.ts +0 -209
  183. package/src/plugin/utils.ts +0 -175
  184. package/src/queue/constants.ts +0 -8
  185. package/src/queue/inMemoryQueue.ts +0 -189
  186. package/src/queue/index.ts +0 -2
  187. package/src/queue/listeners.ts +0 -199
  188. package/src/queue/queue.ts +0 -84
  189. package/src/redis/index.ts +0 -6
  190. package/src/redis/init.ts +0 -118
  191. package/src/redis/redis.ts +0 -358
  192. package/src/redis/redlockImpl.ts +0 -155
  193. package/src/redis/tests/redis.spec.ts +0 -207
  194. package/src/redis/tests/redlockImpl.spec.ts +0 -105
  195. package/src/redis/utils.ts +0 -128
  196. package/src/security/auth.ts +0 -24
  197. package/src/security/encryption.ts +0 -185
  198. package/src/security/index.ts +0 -1
  199. package/src/security/permissions.ts +0 -166
  200. package/src/security/roles.ts +0 -655
  201. package/src/security/secrets.ts +0 -20
  202. package/src/security/sessions.ts +0 -123
  203. package/src/security/tests/auth.spec.ts +0 -45
  204. package/src/security/tests/encryption.spec.ts +0 -31
  205. package/src/security/tests/permissions.spec.ts +0 -146
  206. package/src/security/tests/secrets.spec.ts +0 -35
  207. package/src/security/tests/sessions.spec.ts +0 -12
  208. package/src/sql/designDoc.ts +0 -17
  209. package/src/sql/index.ts +0 -5
  210. package/src/sql/sql.ts +0 -1854
  211. package/src/sql/sqlTable.ts +0 -319
  212. package/src/sql/utils.ts +0 -193
  213. package/src/tenancy/db.ts +0 -6
  214. package/src/tenancy/index.ts +0 -2
  215. package/src/tenancy/tenancy.ts +0 -148
  216. package/src/tenancy/tests/tenancy.spec.ts +0 -184
  217. package/src/timers/index.ts +0 -1
  218. package/src/timers/timers.ts +0 -22
  219. package/src/users/db.ts +0 -582
  220. package/src/users/events.ts +0 -176
  221. package/src/users/index.ts +0 -4
  222. package/src/users/lookup.ts +0 -99
  223. package/src/users/test/db.spec.ts +0 -188
  224. package/src/users/test/utils.spec.ts +0 -67
  225. package/src/users/users.ts +0 -353
  226. package/src/users/utils.ts +0 -81
  227. package/src/utils/Duration.ts +0 -56
  228. package/src/utils/hashing.ts +0 -15
  229. package/src/utils/index.ts +0 -4
  230. package/src/utils/stringUtils.ts +0 -8
  231. package/src/utils/tests/Duration.spec.ts +0 -19
  232. package/src/utils/tests/utils.spec.ts +0 -204
  233. package/src/utils/utils.ts +0 -249
  234. package/tests/core/logging.ts +0 -34
  235. package/tests/core/users/users.spec.js +0 -53
  236. package/tests/core/utilities/index.ts +0 -7
  237. package/tests/core/utilities/jestUtils.ts +0 -33
  238. package/tests/core/utilities/mocks/alerts.ts +0 -4
  239. package/tests/core/utilities/mocks/date.ts +0 -3
  240. package/tests/core/utilities/mocks/events.ts +0 -132
  241. package/tests/core/utilities/mocks/index.ts +0 -9
  242. package/tests/core/utilities/mocks/licenses.ts +0 -119
  243. package/tests/core/utilities/queue.ts +0 -9
  244. package/tests/core/utilities/structures/Chance.ts +0 -20
  245. package/tests/core/utilities/structures/accounts.ts +0 -80
  246. package/tests/core/utilities/structures/apps.ts +0 -21
  247. package/tests/core/utilities/structures/common.ts +0 -7
  248. package/tests/core/utilities/structures/db.ts +0 -12
  249. package/tests/core/utilities/structures/documents/index.ts +0 -1
  250. package/tests/core/utilities/structures/documents/platform/index.ts +0 -1
  251. package/tests/core/utilities/structures/documents/platform/installation.ts +0 -12
  252. package/tests/core/utilities/structures/generator.ts +0 -3
  253. package/tests/core/utilities/structures/index.ts +0 -15
  254. package/tests/core/utilities/structures/koa.ts +0 -16
  255. package/tests/core/utilities/structures/licenses.ts +0 -190
  256. package/tests/core/utilities/structures/plugins.ts +0 -19
  257. package/tests/core/utilities/structures/quotas.ts +0 -72
  258. package/tests/core/utilities/structures/scim.ts +0 -80
  259. package/tests/core/utilities/structures/sso.ts +0 -118
  260. package/tests/core/utilities/structures/tenants.ts +0 -5
  261. package/tests/core/utilities/structures/userGroups.ts +0 -10
  262. package/tests/core/utilities/structures/users.ts +0 -89
  263. package/tests/core/utilities/testContainerUtils.ts +0 -165
  264. package/tests/core/utilities/utils/index.ts +0 -2
  265. package/tests/core/utilities/utils/queue.ts +0 -27
  266. package/tests/core/utilities/utils/time.ts +0 -3
  267. package/tests/extra/DBTestConfiguration.ts +0 -36
  268. package/tests/extra/index.ts +0 -2
  269. package/tests/extra/testEnv.ts +0 -95
  270. package/tests/index.ts +0 -2
  271. package/tests/jestEnv.ts +0 -10
  272. package/tests/jestSetup.ts +0 -36
package/src/users/db.ts DELETED
@@ -1,582 +0,0 @@
1
- import env from "../environment"
2
- import * as eventHelpers from "./events"
3
- import * as accountSdk from "../accounts"
4
- import * as cache from "../cache"
5
- import { getGlobalDB, getIdentity, getTenantId } from "../context"
6
- import * as dbUtils from "../db"
7
- import { EmailUnavailableError, HTTPError } from "../errors"
8
- import * as platform from "../platform"
9
- import * as sessions from "../security/sessions"
10
- import * as usersCore from "./users"
11
- import {
12
- Account,
13
- BulkUserCreated,
14
- BulkUserDeleted,
15
- isSSOAccount,
16
- isSSOUser,
17
- SaveUserOpts,
18
- User,
19
- UserGroup,
20
- UserIdentifier,
21
- UserStatus,
22
- PlatformUserBySsoId,
23
- PlatformUserById,
24
- AnyDocument,
25
- } from "@budibase/types"
26
- import {
27
- getAccountHolderFromUsers,
28
- isAdmin,
29
- isCreator,
30
- validateUniqueUser,
31
- } from "./utils"
32
- import {
33
- getFirstPlatformUser,
34
- getPlatformUsers,
35
- searchExistingEmails,
36
- } from "./lookup"
37
- import { hash } from "../utils"
38
- import { validatePassword } from "../security"
39
-
40
- type QuotaUpdateFn = (
41
- change: number,
42
- creatorsChange: number,
43
- cb?: () => Promise<any>
44
- ) => Promise<any>
45
- type GroupUpdateFn = (groupId: string, userIds: string[]) => Promise<any>
46
- type FeatureFn = () => Promise<Boolean>
47
- type GroupGetFn = (ids: string[]) => Promise<UserGroup[]>
48
- type GroupBuildersFn = (user: User) => Promise<string[]>
49
- type QuotaFns = { addUsers: QuotaUpdateFn; removeUsers: QuotaUpdateFn }
50
- type GroupFns = {
51
- addUsers: GroupUpdateFn
52
- getBulk: GroupGetFn
53
- getGroupBuilderAppIds: GroupBuildersFn
54
- }
55
- type CreateAdminUserOpts = {
56
- password?: string
57
- ssoId?: string
58
- hashPassword?: boolean
59
- requirePassword?: boolean
60
- skipPasswordValidation?: boolean
61
- firstName?: string
62
- lastName?: string
63
- }
64
- type FeatureFns = { isSSOEnforced: FeatureFn; isAppBuildersEnabled: FeatureFn }
65
-
66
- const bulkDeleteProcessing = async (dbUser: User) => {
67
- const userId = dbUser._id as string
68
- await platform.users.removeUser(dbUser)
69
- await eventHelpers.handleDeleteEvents(dbUser)
70
- await cache.user.invalidateUser(userId)
71
- await sessions.invalidateSessions(userId, { reason: "bulk-deletion" })
72
- }
73
-
74
- export class UserDB {
75
- static quotas: QuotaFns
76
- static groups: GroupFns
77
- static features: FeatureFns
78
-
79
- static init(quotaFns: QuotaFns, groupFns: GroupFns, featureFns: FeatureFns) {
80
- UserDB.quotas = quotaFns
81
- UserDB.groups = groupFns
82
- UserDB.features = featureFns
83
- }
84
-
85
- static async isPreventPasswordActions(user: User, account?: Account) {
86
- // when in maintenance mode we allow sso users with the admin role
87
- // to perform any password action - this prevents lockout
88
- if (env.ENABLE_SSO_MAINTENANCE_MODE && isAdmin(user)) {
89
- return false
90
- }
91
-
92
- // SSO is enforced for all users
93
- if (await UserDB.features.isSSOEnforced()) {
94
- return true
95
- }
96
-
97
- // Check local sso
98
- if (isSSOUser(user)) {
99
- return true
100
- }
101
-
102
- // Check account sso
103
- if (!account) {
104
- account = await accountSdk.getAccountByTenantId(getTenantId())
105
- }
106
- return !!(account && account.email === user.email && isSSOAccount(account))
107
- }
108
-
109
- static async buildUser(
110
- user: User,
111
- opts: SaveUserOpts = {
112
- hashPassword: true,
113
- requirePassword: true,
114
- },
115
- tenantId: string,
116
- dbUser?: any,
117
- account?: Account
118
- ): Promise<User> {
119
- let { password, _id } = user
120
-
121
- // don't require a password if the db user doesn't already have one
122
- if (dbUser && !dbUser.password) {
123
- opts.requirePassword = false
124
- }
125
-
126
- let hashedPassword
127
- if (password) {
128
- if (await UserDB.isPreventPasswordActions(user, account)) {
129
- throw new HTTPError("Password change is disabled for this user", 400)
130
- }
131
-
132
- if (!opts.skipPasswordValidation) {
133
- const passwordValidation = validatePassword(password)
134
- if (!passwordValidation.valid) {
135
- throw new HTTPError(passwordValidation.error, 400)
136
- }
137
- }
138
-
139
- hashedPassword = opts.hashPassword ? await hash(password) : password
140
- } else if (dbUser) {
141
- hashedPassword = dbUser.password
142
- }
143
-
144
- // passwords are never required if sso is enforced
145
- const requirePasswords =
146
- opts.requirePassword && !(await UserDB.features.isSSOEnforced())
147
- if (!hashedPassword && requirePasswords) {
148
- throw "Password must be specified."
149
- }
150
-
151
- _id = _id || dbUtils.generateGlobalUserID()
152
-
153
- const fullUser = {
154
- createdAt: Date.now(),
155
- ...dbUser,
156
- ...user,
157
- _id,
158
- password: hashedPassword,
159
- tenantId,
160
- }
161
- // make sure the roles object is always present
162
- if (!fullUser.roles) {
163
- fullUser.roles = {}
164
- }
165
- // add the active status to a user if it's not provided
166
- if (fullUser.status == null) {
167
- fullUser.status = UserStatus.ACTIVE
168
- }
169
-
170
- return fullUser
171
- }
172
-
173
- static async allUsers() {
174
- const db = getGlobalDB()
175
- const response = await db.allDocs<User>(
176
- dbUtils.getGlobalUserParams(null, {
177
- include_docs: true,
178
- })
179
- )
180
- return response.rows.map(row => row.doc!)
181
- }
182
-
183
- static async countUsersByApp(appId: string) {
184
- let response: any = await usersCore.searchGlobalUsersByApp(appId, {})
185
- return {
186
- userCount: response.length,
187
- }
188
- }
189
-
190
- static async getUsersByAppAccess(opts: { appId?: string; limit?: number }) {
191
- let response: User[] = await usersCore.searchGlobalUsersByAppAccess(
192
- opts.appId,
193
- { limit: opts.limit || 50 }
194
- )
195
- return response
196
- }
197
-
198
- static async getUserByEmail(email: string) {
199
- return usersCore.getGlobalUserByEmail(email)
200
- }
201
-
202
- /**
203
- * Gets a user by ID from the global database, based on the current tenancy.
204
- */
205
- static async getUser(userId: string) {
206
- const user = await usersCore.getById(userId)
207
- if (user) {
208
- delete user.password
209
- }
210
- return user
211
- }
212
-
213
- static async bulkGet(userIds: string[]) {
214
- return await usersCore.bulkGetGlobalUsersById(userIds)
215
- }
216
-
217
- static async bulkUpdate(users: User[]) {
218
- return await usersCore.bulkUpdateGlobalUsers(users)
219
- }
220
-
221
- static async save(user: User, opts: SaveUserOpts = {}): Promise<User> {
222
- // default booleans to true
223
- if (opts.hashPassword == null) {
224
- opts.hashPassword = true
225
- }
226
- if (opts.requirePassword == null) {
227
- opts.requirePassword = true
228
- }
229
- const tenantId = getTenantId()
230
- const db = getGlobalDB()
231
-
232
- const { email, _id, userGroups = [], roles } = user
233
-
234
- if (!email && !_id) {
235
- throw new Error("_id or email is required")
236
- }
237
-
238
- let dbUser: User | undefined
239
- if (_id) {
240
- // try to get existing user from db
241
- try {
242
- dbUser = await usersCore.getById(_id)
243
- if (email && dbUser.email !== email && !opts.allowChangingEmail) {
244
- throw new Error("Email address cannot be changed")
245
- }
246
- } catch (e: any) {
247
- if (e.status === 404) {
248
- // do nothing, save this new user with the id specified - required for SSO auth
249
- } else {
250
- throw e
251
- }
252
- }
253
- }
254
-
255
- if (!dbUser && email) {
256
- // no id was specified - load from email instead
257
- dbUser = await usersCore.getGlobalUserByEmail(email)
258
- if (dbUser && dbUser._id !== _id) {
259
- throw new EmailUnavailableError(email)
260
- }
261
- }
262
-
263
- const change = dbUser ? 0 : 1 // no change if there is existing user
264
- const creatorsChange =
265
- (await isCreator(dbUser)) !== (await isCreator(user)) ? 1 : 0
266
- return UserDB.quotas.addUsers(change, creatorsChange, async () => {
267
- await validateUniqueUser(email, tenantId)
268
-
269
- let builtUser = await UserDB.buildUser(user, opts, tenantId, dbUser)
270
- // don't allow a user to update its own roles/perms
271
- if (opts.currentUserId && opts.currentUserId === dbUser?._id) {
272
- builtUser = usersCore.cleanseUserObject(builtUser, dbUser) as User
273
- }
274
-
275
- if (!dbUser && roles?.length) {
276
- builtUser.roles = { ...roles }
277
- }
278
-
279
- // make sure we set the _id field for a new user
280
- // Also if this is a new user, associate groups with them
281
- const groupPromises = []
282
- if (!_id) {
283
- if (userGroups.length > 0) {
284
- for (let groupId of userGroups) {
285
- groupPromises.push(
286
- UserDB.groups.addUsers(groupId, [builtUser._id!])
287
- )
288
- }
289
- }
290
- }
291
-
292
- try {
293
- // save the user to db
294
- let response = await db.put(builtUser)
295
- builtUser._rev = response.rev
296
-
297
- await eventHelpers.handleSaveEvents(builtUser, dbUser)
298
- if (dbUser && builtUser.email !== dbUser.email) {
299
- // Remove the plaform email reference if the email changed
300
- await platform.users.removeUser({ email: dbUser.email } as User)
301
- }
302
-
303
- await platform.users.addUser(
304
- tenantId,
305
- builtUser._id!,
306
- builtUser.email,
307
- builtUser.ssoId
308
- )
309
- await cache.user.invalidateUser(response.id)
310
-
311
- await Promise.all(groupPromises)
312
-
313
- // finally returned the saved user from the db
314
- return db.get(builtUser._id!)
315
- } catch (err: any) {
316
- if (err.status === 409) {
317
- throw "User exists already"
318
- } else {
319
- throw err
320
- }
321
- }
322
- })
323
- }
324
-
325
- static async bulkCreate(
326
- newUsersRequested: User[],
327
- groups?: string[]
328
- ): Promise<BulkUserCreated> {
329
- const tenantId = getTenantId()
330
-
331
- let usersToSave: any[] = []
332
- let newUsers: any[] = []
333
- let newCreators: any[] = []
334
-
335
- const emails = newUsersRequested.map((user: User) => user.email)
336
- const existingEmails = await searchExistingEmails(emails)
337
- const unsuccessful: { email: string; reason: string }[] = []
338
-
339
- for (const newUser of newUsersRequested) {
340
- if (
341
- newUsers.find(
342
- (x: User) => x.email.toLowerCase() === newUser.email.toLowerCase()
343
- ) ||
344
- existingEmails.includes(newUser.email.toLowerCase())
345
- ) {
346
- unsuccessful.push({
347
- email: newUser.email,
348
- reason: `Unavailable`,
349
- })
350
- continue
351
- }
352
- newUser.userGroups = groups || []
353
- newUsers.push(newUser)
354
- if (await isCreator(newUser)) {
355
- newCreators.push(newUser)
356
- }
357
- }
358
-
359
- const account = await accountSdk.getAccountByTenantId(tenantId)
360
- return UserDB.quotas.addUsers(
361
- newUsers.length,
362
- newCreators.length,
363
- async () => {
364
- // create the promises array that will be called by bulkDocs
365
- newUsers.forEach((user: any) => {
366
- usersToSave.push(
367
- UserDB.buildUser(
368
- user,
369
- {
370
- hashPassword: true,
371
- requirePassword: user.requirePassword,
372
- },
373
- tenantId,
374
- undefined, // no dbUser
375
- account
376
- )
377
- )
378
- })
379
-
380
- const usersToBulkSave = await Promise.all(usersToSave)
381
- await usersCore.bulkUpdateGlobalUsers(usersToBulkSave)
382
-
383
- // Post-processing of bulk added users, e.g. events and cache operations
384
- for (const user of usersToBulkSave) {
385
- // TODO: Refactor to bulk insert users into the info db
386
- // instead of relying on looping tenant creation
387
- await platform.users.addUser(tenantId, user._id, user.email)
388
- await eventHelpers.handleSaveEvents(user, undefined)
389
- }
390
-
391
- const saved = usersToBulkSave.map(user => {
392
- return {
393
- _id: user._id,
394
- email: user.email,
395
- }
396
- })
397
-
398
- // now update the groups
399
- if (Array.isArray(saved) && groups) {
400
- const groupPromises = []
401
- const createdUserIds = saved.map(user => user._id)
402
- for (let groupId of groups) {
403
- groupPromises.push(UserDB.groups.addUsers(groupId, createdUserIds))
404
- }
405
- await Promise.all(groupPromises)
406
- }
407
-
408
- return {
409
- successful: saved,
410
- unsuccessful,
411
- }
412
- }
413
- )
414
- }
415
-
416
- static async bulkDelete(
417
- users: Array<UserIdentifier>
418
- ): Promise<BulkUserDeleted> {
419
- const db = getGlobalDB()
420
-
421
- const response: BulkUserDeleted = {
422
- successful: [],
423
- unsuccessful: [],
424
- }
425
-
426
- // remove the account holder from the delete request if present
427
- const accountHolder = await getAccountHolderFromUsers(users)
428
- if (accountHolder) {
429
- users = users.filter(u => u.userId !== accountHolder.userId)
430
- // mark user as unsuccessful
431
- response.unsuccessful.push({
432
- _id: accountHolder.userId,
433
- email: accountHolder.email,
434
- reason: "Account holder cannot be deleted",
435
- })
436
- }
437
-
438
- // Get users and delete
439
- const allDocsResponse = await db.allDocs<User>({
440
- include_docs: true,
441
- keys: users.map(u => u.userId),
442
- })
443
- const usersToDelete = allDocsResponse.rows.map(user => {
444
- return user.doc!
445
- })
446
-
447
- // Delete from DB
448
- const toDelete = usersToDelete.map(user => ({
449
- ...user,
450
- _deleted: true,
451
- }))
452
- const dbResponse = await usersCore.bulkUpdateGlobalUsers(toDelete)
453
-
454
- const creatorsEval = await Promise.all(usersToDelete.map(isCreator))
455
- const creatorsToDeleteCount = creatorsEval.filter(
456
- creator => !!creator
457
- ).length
458
-
459
- const ssoUsersToDelete: AnyDocument[] = []
460
- for (let user of usersToDelete) {
461
- const platformUser = (await getFirstPlatformUser(
462
- user._id!
463
- )) as PlatformUserById
464
- const ssoId = platformUser.ssoId
465
- if (ssoId) {
466
- // Need to get the _rev of the SSO user doc to delete it. The view also returns docs that have the ssoId property, so we need to ignore those.
467
- const ssoUsers = (await getPlatformUsers(
468
- ssoId
469
- )) as PlatformUserBySsoId[]
470
- ssoUsers
471
- .filter(user => user.ssoId == null)
472
- .forEach(user => {
473
- ssoUsersToDelete.push({
474
- ...user,
475
- _deleted: true,
476
- })
477
- })
478
- }
479
- await bulkDeleteProcessing(user)
480
- }
481
-
482
- // Delete any associated SSO user docs
483
- await platform.getPlatformDB().bulkDocs(ssoUsersToDelete)
484
-
485
- await UserDB.quotas.removeUsers(toDelete.length, creatorsToDeleteCount)
486
-
487
- // Build Response
488
- // index users by id
489
- const userIndex: { [key: string]: User } = {}
490
- usersToDelete.reduce((prev, current) => {
491
- prev[current._id!] = current
492
- return prev
493
- }, userIndex)
494
-
495
- // add the successful and unsuccessful users to response
496
- dbResponse.forEach(item => {
497
- const email = userIndex[item.id].email
498
- if (item.ok) {
499
- response.successful.push({ _id: item.id, email })
500
- } else {
501
- response.unsuccessful.push({
502
- _id: item.id,
503
- email,
504
- reason: "Database error",
505
- })
506
- }
507
- })
508
-
509
- return response
510
- }
511
-
512
- static async destroy(id: string) {
513
- const db = getGlobalDB()
514
- const dbUser = (await db.get(id)) as User
515
- const userId = dbUser._id as string
516
-
517
- if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
518
- // root account holder can't be deleted from inside budibase
519
- const email = dbUser.email
520
- const account = await accountSdk.getAccount(email)
521
- if (account) {
522
- if (dbUser.userId === getIdentity()!._id) {
523
- throw new HTTPError('Please visit "Account" to delete this user', 400)
524
- } else {
525
- throw new HTTPError("Account holder cannot be deleted", 400)
526
- }
527
- }
528
- }
529
-
530
- await platform.users.removeUser(dbUser)
531
-
532
- await db.remove(userId, dbUser._rev!)
533
-
534
- const creatorsToDelete = (await isCreator(dbUser)) ? 1 : 0
535
- await UserDB.quotas.removeUsers(1, creatorsToDelete)
536
- await eventHelpers.handleDeleteEvents(dbUser)
537
- await cache.user.invalidateUser(userId)
538
- await sessions.invalidateSessions(userId, { reason: "deletion" })
539
- }
540
-
541
- static async createAdminUser(
542
- email: string,
543
- tenantId: string,
544
- opts?: CreateAdminUserOpts
545
- ) {
546
- const password = opts?.password
547
- const user: User = {
548
- email: email,
549
- password,
550
- createdAt: Date.now(),
551
- roles: {},
552
- builder: {
553
- global: true,
554
- },
555
- admin: {
556
- global: true,
557
- },
558
- tenantId,
559
- firstName: opts?.firstName,
560
- lastName: opts?.lastName,
561
- }
562
- if (opts?.ssoId) {
563
- user.ssoId = opts.ssoId
564
- }
565
- // always bust checklist beforehand, if an error occurs but can proceed, don't get
566
- // stuck in a cycle
567
- await cache.bustCache(cache.CacheKey.CHECKLIST)
568
- return await UserDB.save(user, {
569
- hashPassword: opts?.hashPassword,
570
- requirePassword: opts?.requirePassword,
571
- skipPasswordValidation: opts?.skipPasswordValidation,
572
- })
573
- }
574
-
575
- static async getGroups(groupIds: string[]) {
576
- return await this.groups.getBulk(groupIds)
577
- }
578
-
579
- static async getGroupBuilderAppIds(user: User) {
580
- return await this.groups.getGroupBuilderAppIds(user)
581
- }
582
- }