Add new UnsavedUser type and update controllers

This commit is contained in:
Andrew Kingston 2025-01-08 15:54:09 +00:00
parent 52916f11a8
commit 6bd4cb47c2
No known key found for this signature in database
4 changed files with 38 additions and 31 deletions

View File

@ -9,9 +9,18 @@ import {
SearchUsersResponse,
UpdateInviteRequest,
User,
UserIdentifier,
UnsavedUser,
} from "@budibase/types"
import { BudiStore } from "../BudiStore"
interface UserInfo {
email: string
password: string
forceResetPassword?: boolean
role: keyof typeof Constants.BudibaseRoles
}
type UserState = SearchUsersResponse & SearchUsersRequest
class UserStore extends BudiStore<UserState> {
@ -116,9 +125,9 @@ class UserStore extends BudiStore<UserState> {
return await API.getUserCountByApp(appId)
}
async create(data: any) {
let mappedUsers: Omit<User, "tenantId">[] = data.users.map((user: any) => {
const body: Omit<User, "tenantId"> = {
async create(data: { users: UserInfo[]; groups: any[] }) {
let mappedUsers: UnsavedUser[] = data.users.map((user: any) => {
const body: UnsavedUser = {
email: user.email,
password: user.password,
roles: {},
@ -128,17 +137,17 @@ class UserStore extends BudiStore<UserState> {
}
switch (user.role) {
case "appUser":
case Constants.BudibaseRoles.AppUser:
body.builder = { global: false }
body.admin = { global: false }
break
case "developer":
case Constants.BudibaseRoles.Developer:
body.builder = { global: true }
break
case "creator":
case Constants.BudibaseRoles.Creator:
body.builder = { creator: true, global: false }
break
case "admin":
case Constants.BudibaseRoles.Admin:
body.admin = { global: true }
body.builder = { global: true }
break
@ -157,12 +166,7 @@ class UserStore extends BudiStore<UserState> {
await API.deleteUser(id)
}
async bulkDelete(
users: Array<{
userId: string
email: string
}>
) {
async bulkDelete(users: UserIdentifier[]) {
return API.deleteUsers(users)
}
@ -199,9 +203,8 @@ class UserStore extends BudiStore<UserState> {
}
}
foo = this.refreshUsage(this.create)
bar = this.refreshUsage(this.save)
// Wrapper function to refresh quota usage after an operation,
// persisting argument and return types
refreshUsage<T extends any[], U>(fn: (...args: T) => Promise<U>) {
return async function (...args: T) {
const response = await fn(...args)

View File

@ -21,11 +21,12 @@ import {
SaveUserResponse,
SearchUsersRequest,
SearchUsersResponse,
UnsavedUser,
UpdateInviteRequest,
UpdateInviteResponse,
UpdateSelfMetadataRequest,
UpdateSelfMetadataResponse,
User,
UserIdentifier,
} from "@budibase/types"
import { BaseAPIClient } from "./types"
@ -38,14 +39,9 @@ export interface UserEndpoints {
createAdminUser: (
user: CreateAdminUserRequest
) => Promise<CreateAdminUserResponse>
saveUser: (user: User) => Promise<SaveUserResponse>
saveUser: (user: UnsavedUser) => Promise<SaveUserResponse>
deleteUser: (userId: string) => Promise<DeleteUserResponse>
deleteUsers: (
users: Array<{
userId: string
email: string
}>
) => Promise<BulkUserDeleted | undefined>
deleteUsers: (users: UserIdentifier[]) => Promise<BulkUserDeleted | undefined>
onboardUsers: (data: InviteUsersRequest) => Promise<InviteUsersResponse>
getUserInvite: (code: string) => Promise<CheckInviteResponse>
getUserInvites: () => Promise<GetUserInvitesResponse>
@ -60,7 +56,7 @@ export interface UserEndpoints {
getAccountHolder: () => Promise<LookupAccountHolderResponse>
searchUsers: (data: SearchUsersRequest) => Promise<SearchUsersResponse>
createUsers: (
users: Omit<User, "tenantId">[],
users: UnsavedUser[],
groups: any[]
) => Promise<BulkUserCreated | undefined>
updateUserInvite: (

View File

@ -22,6 +22,8 @@ export interface UserDetails {
password?: string
}
export type UnsavedUser = Omit<User, "tenantId">
export interface BulkUserRequest {
delete?: {
users: Array<{
@ -31,7 +33,7 @@ export interface BulkUserRequest {
}
create?: {
roles?: any[]
users: User[]
users: UnsavedUser[]
groups: any[]
}
}

View File

@ -33,6 +33,7 @@ import {
SaveUserResponse,
SearchUsersRequest,
SearchUsersResponse,
UnsavedUser,
UpdateInviteRequest,
UpdateInviteResponse,
User,
@ -49,6 +50,7 @@ import {
tenancy,
db,
locks,
context,
} from "@budibase/backend-core"
import { checkAnyUserExists } from "../../../utilities/users"
import { isEmailConfigured } from "../../../utilities/email"
@ -66,10 +68,11 @@ const generatePassword = (length: number) => {
.slice(0, length)
}
export const save = async (ctx: UserCtx<User, SaveUserResponse>) => {
export const save = async (ctx: UserCtx<UnsavedUser, SaveUserResponse>) => {
try {
const currentUserId = ctx.user?._id
const requestUser = ctx.request.body
const tenantId = context.getTenantId()
const requestUser: User = { ...ctx.request.body, tenantId }
// Do not allow the account holder role to be changed
const accountMetadata = await users.getExistingAccounts([requestUser.email])
@ -149,7 +152,12 @@ export const bulkUpdate = async (
let created, deleted
try {
if (input.create) {
created = await bulkCreate(input.create.users, input.create.groups)
const tenantId = context.getTenantId()
const users: User[] = input.create.users.map(user => ({
...user,
tenantId,
}))
created = await bulkCreate(users, input.create.groups)
}
if (input.delete) {
deleted = await bulkDelete(input.delete.users, currentUserId)
@ -441,7 +449,6 @@ export const checkInvite = async (ctx: UserCtx<void, CheckInviteResponse>) => {
} catch (e) {
console.warn("Error getting invite from code", e)
ctx.throw(400, "There was a problem with the invite")
return
}
ctx.body = {
email: invite.email,
@ -472,7 +479,6 @@ export const updateInvite = async (
invite = await cache.invite.getCode(code)
} catch (e) {
ctx.throw(400, "There was a problem with the invite")
return
}
let updated = {