Skip to content

Commit

Permalink
Gro 738 refactor code that returns the account holder from user (#14872)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* Remove tests

* Remove TenantInfo

* Remove unused export

* Remove TenantInfo type

* Remove unused export

* Remove unused routes

* Add getAccountHolder front-end endpoint

* Add endpoint to no tenancy list

* Get account holder via appId

* lint

* Update pro ref

* Use account email instead of budibaseUserId (#14876)

* Update account-portal ref

* Update account portal ref

* Correct import order

* Simplify boolean

* type fix

* Rename endpoint to accountholder

* Update account-portal ref

* Refactor

* Refactor to not use appId

* Update type

* appId not needed

* Unused import
  • Loading branch information
melohagan authored Oct 28, 2024
1 parent b2f3e4f commit 7dcdce2
Show file tree
Hide file tree
Showing 25 changed files with 126 additions and 256 deletions.
2 changes: 1 addition & 1 deletion packages/account-portal
13 changes: 7 additions & 6 deletions packages/backend-core/src/events/identification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ const identifyUser = async (
if (isSSOUser(user)) {
providerType = user.providerType
}
const accountHolder = account?.budibaseUserId === user._id || false
const verified =
account && account?.budibaseUserId === user._id ? account.verified : false
const accountHolder = await users.getExistingAccounts([user.email])
const isAccountHolder = accountHolder.length > 0
const verified = !!account && isAccountHolder && account.verified
const installationId = await getInstallationId()
const hosting = account ? account.hosting : getHostingFromEnv()
const environment = getDeploymentEnvironment()
Expand All @@ -185,7 +185,7 @@ const identifyUser = async (
installationId,
tenantId,
verified,
accountHolder,
accountHolder: isAccountHolder,
providerType,
builder,
admin,
Expand All @@ -207,9 +207,10 @@ const identifyAccount = async (account: Account) => {
const environment = getDeploymentEnvironment()

if (isCloudAccount(account)) {
if (account.budibaseUserId) {
const user = await users.getGlobalUserByEmail(account.email)
if (user?._id) {
// use the budibase user as the id if set
id = account.budibaseUserId
id = user._id
}
}

Expand Down
23 changes: 0 additions & 23 deletions packages/backend-core/src/tenancy/db.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,6 @@
import { getDB } from "../db/db"
import { getGlobalDBName } from "../context"
import { TenantInfo } from "@budibase/types"

export function getTenantDB(tenantId: string) {
return getDB(getGlobalDBName(tenantId))
}

export async function saveTenantInfo(tenantInfo: TenantInfo) {
const db = getTenantDB(tenantInfo.tenantId)
// save the tenant info to db
return db.put({
_id: "tenant_info",
...tenantInfo,
})
}

export async function getTenantInfo(
tenantId: string
): Promise<TenantInfo | undefined> {
try {
const db = getTenantDB(tenantId)
const tenantInfo = (await db.get("tenant_info")) as TenantInfo
delete tenantInfo.owner.password
return tenantInfo
} catch {
return undefined
}
}
21 changes: 12 additions & 9 deletions packages/backend-core/src/users/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ import {
isSSOUser,
SaveUserOpts,
User,
UserStatus,
UserGroup,
UserIdentifier,
UserStatus,
PlatformUserBySsoId,
PlatformUserById,
AnyDocument,
} from "@budibase/types"
import {
getAccountHolderFromUserIds,
getAccountHolderFromUsers,
isAdmin,
isCreator,
validateUniqueUser,
Expand Down Expand Up @@ -412,7 +413,9 @@ export class UserDB {
)
}

static async bulkDelete(userIds: string[]): Promise<BulkUserDeleted> {
static async bulkDelete(
users: Array<UserIdentifier>
): Promise<BulkUserDeleted> {
const db = getGlobalDB()

const response: BulkUserDeleted = {
Expand All @@ -421,21 +424,21 @@ export class UserDB {
}

// remove the account holder from the delete request if present
const account = await getAccountHolderFromUserIds(userIds)
if (account) {
userIds = userIds.filter(u => u !== account.budibaseUserId)
const accountHolder = await getAccountHolderFromUsers(users)
if (accountHolder) {
users = users.filter(u => u.userId !== accountHolder.userId)
// mark user as unsuccessful
response.unsuccessful.push({
_id: account.budibaseUserId,
email: account.email,
_id: accountHolder.userId,
email: accountHolder.email,
reason: "Account holder cannot be deleted",
})
}

// Get users and delete
const allDocsResponse = await db.allDocs<User>({
include_docs: true,
keys: userIds,
keys: users.map(u => u.userId),
})
const usersToDelete = allDocsResponse.rows.map(user => {
return user.doc!
Expand Down
11 changes: 11 additions & 0 deletions packages/backend-core/src/users/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ export async function getAllUserIds() {
return response.rows.map(row => row.id)
}

export async function getAllUsers(): Promise<User[]> {
const db = getGlobalDB()
const startKey = `${DocumentType.USER}${SEPARATOR}`
const response = await db.allDocs({
startkey: startKey,
endkey: `${startKey}${UNICODE_MAX}`,
include_docs: true,
})
return response.rows.map(row => row.doc) as User[]
}

export async function bulkUpdateGlobalUsers(users: User[]) {
const db = getGlobalDB()
return (await db.bulkDocs(users)) as BulkDocsResponse
Expand Down
30 changes: 12 additions & 18 deletions packages/backend-core/src/users/utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { CloudAccount, ContextUser, User, UserGroup } from "@budibase/types"
import { ContextUser, User, UserGroup, UserIdentifier } from "@budibase/types"
import * as accountSdk from "../accounts"
import env from "../environment"
import { getFirstPlatformUser } from "./lookup"
import { getExistingAccounts, getFirstPlatformUser } from "./lookup"
import { EmailUnavailableError } from "../errors"
import { getTenantId } from "../context"
import { sdk } from "@budibase/shared-core"
import { getAccountByTenantId } from "../accounts"
import { BUILTIN_ROLE_IDS } from "../security/roles"
import * as context from "../context"

Expand Down Expand Up @@ -67,21 +65,17 @@ export async function validateUniqueUser(email: string, tenantId: string) {
}

/**
* For the given user id's, return the account holder if it is in the ids.
* For a list of users, return the account holder if there is an email match.
*/
export async function getAccountHolderFromUserIds(
userIds: string[]
): Promise<CloudAccount | undefined> {
export async function getAccountHolderFromUsers(
users: Array<UserIdentifier>
): Promise<UserIdentifier | undefined> {
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
const tenantId = getTenantId()
const account = await getAccountByTenantId(tenantId)
if (!account) {
throw new Error(`Account not found for tenantId=${tenantId}`)
}

const budibaseUserId = account.budibaseUserId
if (userIds.includes(budibaseUserId)) {
return account
}
const accountMetadata = await getExistingAccounts(
users.map(user => user.email)
)
return users.find(user =>
accountMetadata.map(metadata => metadata.email).includes(user.email)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@
if (!user?._id) {
$goto("./")
}
tenantOwner = await users.tenantOwner($auth.tenantId)
tenantOwner = await users.getAccountHolder()
}
async function toggleFlags(detail) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,12 @@
}
if (ids.length > 0) {
await users.bulkDelete(ids)
await users.bulkDelete(
selectedRows.map(user => ({
userId: user._id,
email: user.email,
}))
)
}
if (selectedInvites.length > 0) {
Expand Down Expand Up @@ -319,7 +324,7 @@
groupsLoaded = true
pendingInvites = await users.getInvites()
invitesLoaded = true
tenantOwner = await users.tenantOwner($auth.tenantId)
tenantOwner = await users.getAccountHolder()
tenantOwnerLoaded = true
} catch (error) {
notifications.error("Error fetching user group data")
Expand Down
11 changes: 5 additions & 6 deletions packages/builder/src/stores/portal/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ export function createUsersStore() {
return await API.getUserCountByApp({ appId })
}

async function bulkDelete(userIds) {
return API.deleteUsers(userIds)
async function bulkDelete(users) {
return API.deleteUsers(users)
}

async function save(user) {
Expand All @@ -128,9 +128,8 @@ export function createUsersStore() {
return await API.removeAppBuilder({ userId, appId })
}

async function getTenantOwner(tenantId) {
const tenantInfo = await API.getTenantInfo({ tenantId })
return tenantInfo?.owner
async function getAccountHolder() {
return await API.getAccountHolder()
}

const getUserRole = user => {
Expand Down Expand Up @@ -176,7 +175,7 @@ export function createUsersStore() {
save: refreshUsage(save),
bulkDelete: refreshUsage(bulkDelete),
delete: refreshUsage(del),
tenantOwner: getTenantOwner,
getAccountHolder,
}
}

Expand Down
10 changes: 5 additions & 5 deletions packages/frontend-core/src/api/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,14 @@ export const buildUserEndpoints = API => ({

/**
* Deletes multiple users
* @param userIds the ID of the user to delete
* @param users the ID/email pair of the user to delete
*/
deleteUsers: async userIds => {
deleteUsers: async users => {
const res = await API.post({
url: `/api/global/users/bulk`,
body: {
delete: {
userIds,
users,
},
},
})
Expand Down Expand Up @@ -296,9 +296,9 @@ export const buildUserEndpoints = API => ({
})
},

getTenantInfo: async ({ tenantId }) => {
getAccountHolder: async () => {
return await API.get({
url: `/api/global/tenant/${tenantId}`,
url: `/api/global/users/accountholder`,
})
},
})
5 changes: 4 additions & 1 deletion packages/types/src/api/web/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export interface UserDetails {

export interface BulkUserRequest {
delete?: {
userIds: string[]
users: Array<{
userId: string
email: string
}>
}
create?: {
roles?: any[]
Expand Down
1 change: 0 additions & 1 deletion packages/types/src/documents/global/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ export * from "./schedule"
export * from "./templates"
export * from "./environmentVariables"
export * from "./auditLogs"
export * from "./tenantInfo"
15 changes: 0 additions & 15 deletions packages/types/src/documents/global/tenantInfo.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/types/src/documents/global/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ export function isSSOUser(user: User): user is SSOUser {

// USER

export interface UserIdentifier {
userId: string
email: string
}

export interface User extends Document {
tenantId: string
email: string
Expand Down
14 changes: 0 additions & 14 deletions packages/worker/src/api/controllers/global/tenant.ts

This file was deleted.

Loading

0 comments on commit 7dcdce2

Please sign in to comment.