2023-10-07 04:31:48 +13:00
|
|
|
import { cache, db as dbCore } from "@budibase/backend-core"
|
2023-09-15 21:21:10 +12:00
|
|
|
import { utils } from "@budibase/shared-core"
|
2024-04-23 03:27:26 +12:00
|
|
|
import {
|
|
|
|
FieldType,
|
|
|
|
FieldSubtype,
|
|
|
|
DocumentType,
|
|
|
|
SEPARATOR,
|
|
|
|
} from "@budibase/types"
|
2023-09-15 22:07:25 +12:00
|
|
|
import { InvalidBBRefError } from "./errors"
|
2023-09-15 20:33:36 +12:00
|
|
|
|
2023-10-07 04:31:48 +13:00
|
|
|
const ROW_PREFIX = DocumentType.ROW + SEPARATOR
|
|
|
|
|
2024-04-23 06:58:35 +12:00
|
|
|
export function processInputBBReferences<T = FieldType.BB_REFERENCE_SINGLE>(
|
|
|
|
value: string,
|
|
|
|
type: T
|
|
|
|
): Promise<string | null>
|
|
|
|
export function processInputBBReferences<
|
2024-04-23 03:27:26 +12:00
|
|
|
T = FieldType.BB_REFERENCE,
|
|
|
|
TS = FieldSubtype.USER
|
|
|
|
>(
|
2023-09-15 22:07:25 +12:00
|
|
|
value: string | string[] | { _id: string } | { _id: string }[],
|
2024-04-23 03:27:26 +12:00
|
|
|
type: T,
|
|
|
|
subtype: TS
|
|
|
|
): Promise<string | null>
|
2024-04-23 06:58:35 +12:00
|
|
|
export function processInputBBReferences<
|
2024-04-23 03:27:26 +12:00
|
|
|
T = FieldType.BB_REFERENCE,
|
|
|
|
TS = FieldSubtype.USERS
|
|
|
|
>(
|
|
|
|
value: string | string[] | { _id: string } | { _id: string }[],
|
|
|
|
type: T,
|
|
|
|
subtype: TS
|
|
|
|
): Promise<string[] | null>
|
|
|
|
|
|
|
|
export async function processInputBBReferences<
|
|
|
|
T extends FieldType.BB_REFERENCE | FieldType.BB_REFERENCE_SINGLE,
|
|
|
|
TS extends FieldSubtype.USER | FieldSubtype.USERS
|
|
|
|
>(
|
|
|
|
value: string | string[] | { _id: string } | { _id: string }[],
|
|
|
|
type: T,
|
|
|
|
subtype?: TS
|
2023-10-05 03:50:05 +13:00
|
|
|
): Promise<string | string[] | null> {
|
2024-04-24 22:04:43 +12:00
|
|
|
switch (type) {
|
|
|
|
case FieldType.BB_REFERENCE:
|
|
|
|
let referenceIds: string[] = []
|
2023-09-20 21:07:32 +12:00
|
|
|
|
2024-04-24 22:04:43 +12:00
|
|
|
if (Array.isArray(value)) {
|
|
|
|
referenceIds.push(
|
|
|
|
...value.map(idOrDoc =>
|
|
|
|
typeof idOrDoc === "string" ? idOrDoc : idOrDoc._id
|
|
|
|
)
|
|
|
|
)
|
|
|
|
} else if (typeof value !== "string") {
|
|
|
|
referenceIds.push(value._id)
|
|
|
|
} else {
|
|
|
|
referenceIds.push(
|
|
|
|
...value
|
|
|
|
.split(",")
|
|
|
|
.filter(x => x)
|
|
|
|
.map((id: string) => id.trim())
|
|
|
|
)
|
|
|
|
}
|
2023-09-15 21:21:10 +12:00
|
|
|
|
2024-04-24 22:04:43 +12:00
|
|
|
// make sure all reference IDs are correct global user IDs
|
|
|
|
// they may be user metadata references (start with row prefix)
|
|
|
|
// and these need to be converted to global IDs
|
|
|
|
referenceIds = referenceIds.map(id => {
|
|
|
|
if (id?.startsWith(ROW_PREFIX)) {
|
|
|
|
return dbCore.getGlobalIDFromUserMetadataID(id)
|
|
|
|
} else {
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
})
|
2023-10-07 04:31:48 +13:00
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
switch (subtype) {
|
|
|
|
case undefined:
|
|
|
|
throw "Subtype must be defined"
|
|
|
|
case FieldSubtype.USER:
|
2024-04-23 06:58:35 +12:00
|
|
|
case FieldSubtype.USERS: {
|
2024-04-23 03:27:26 +12:00
|
|
|
const { notFoundIds } = await cache.user.getUsers(referenceIds)
|
|
|
|
|
|
|
|
if (notFoundIds?.length) {
|
|
|
|
throw new InvalidBBRefError(notFoundIds[0], FieldSubtype.USER)
|
|
|
|
}
|
|
|
|
|
2024-04-25 23:20:00 +12:00
|
|
|
if (!referenceIds?.length) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
if (subtype === FieldSubtype.USERS) {
|
|
|
|
return referenceIds
|
|
|
|
}
|
2023-09-20 20:05:52 +12:00
|
|
|
|
2024-04-25 23:20:00 +12:00
|
|
|
return referenceIds.join(",")
|
2024-04-23 06:58:35 +12:00
|
|
|
}
|
2024-04-23 03:27:26 +12:00
|
|
|
default:
|
|
|
|
throw utils.unreachable(subtype)
|
2023-09-15 21:21:10 +12:00
|
|
|
}
|
2023-10-05 03:50:05 +13:00
|
|
|
|
2024-04-23 06:58:35 +12:00
|
|
|
case FieldType.BB_REFERENCE_SINGLE: {
|
2024-04-24 22:04:43 +12:00
|
|
|
if (value && Array.isArray(value)) {
|
|
|
|
throw "BB_REFERENCE_SINGLE cannot be an array"
|
|
|
|
}
|
|
|
|
|
|
|
|
const id = typeof value === "string" ? value : value._id
|
|
|
|
|
|
|
|
const user = await cache.user.getUser(id)
|
2024-04-23 03:27:26 +12:00
|
|
|
|
|
|
|
if (!user) {
|
2024-04-24 22:04:43 +12:00
|
|
|
throw new InvalidBBRefError(id, FieldSubtype.USER)
|
2023-10-05 03:50:05 +13:00
|
|
|
}
|
|
|
|
|
2024-04-25 23:38:31 +12:00
|
|
|
return user._id!
|
2024-04-23 06:58:35 +12:00
|
|
|
}
|
2024-04-23 03:27:26 +12:00
|
|
|
|
2023-09-15 21:21:10 +12:00
|
|
|
default:
|
2024-04-23 03:27:26 +12:00
|
|
|
throw utils.unreachable(type)
|
2023-09-15 21:21:10 +12:00
|
|
|
}
|
|
|
|
}
|
2023-09-15 23:31:22 +12:00
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
interface UserReferenceInfo {
|
|
|
|
_id: string
|
|
|
|
primaryDisplay: string
|
|
|
|
email: string
|
|
|
|
firstName: string
|
|
|
|
lastName: string
|
|
|
|
}
|
|
|
|
|
2024-04-23 06:58:35 +12:00
|
|
|
export function processOutputBBReferences<T = FieldType.BB_REFERENCE_SINGLE>(
|
|
|
|
value: string,
|
|
|
|
type: T
|
|
|
|
): Promise<UserReferenceInfo>
|
|
|
|
export function processOutputBBReferences<
|
2024-04-23 03:27:26 +12:00
|
|
|
T = FieldType.BB_REFERENCE,
|
|
|
|
TS = FieldSubtype.USER
|
|
|
|
>(value: string, type: T, subtype: TS): Promise<UserReferenceInfo[]>
|
2024-04-23 06:58:35 +12:00
|
|
|
export function processOutputBBReferences<
|
2024-04-23 03:27:26 +12:00
|
|
|
T = FieldType.BB_REFERENCE,
|
|
|
|
TS = FieldSubtype.USERS
|
|
|
|
>(value: string[], type: T, subtype: TS): Promise<UserReferenceInfo[]>
|
|
|
|
|
2023-09-15 23:31:22 +12:00
|
|
|
export async function processOutputBBReferences(
|
2023-10-05 03:50:05 +13:00
|
|
|
value: string | string[],
|
2024-04-23 03:27:26 +12:00
|
|
|
type: FieldType.BB_REFERENCE | FieldType.BB_REFERENCE_SINGLE,
|
|
|
|
subtype?: FieldSubtype.USER | FieldSubtype.USERS
|
2023-09-15 23:31:22 +12:00
|
|
|
) {
|
2023-10-05 03:50:05 +13:00
|
|
|
if (value === null || value === undefined) {
|
2023-09-19 23:17:07 +12:00
|
|
|
// Already processed or nothing to process
|
2023-09-30 03:39:18 +13:00
|
|
|
return value || undefined
|
2023-09-15 23:47:08 +12:00
|
|
|
}
|
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
switch (type) {
|
|
|
|
case FieldType.BB_REFERENCE:
|
|
|
|
const ids =
|
|
|
|
typeof value === "string" ? value.split(",").filter(id => !!id) : value
|
|
|
|
|
|
|
|
switch (subtype) {
|
|
|
|
case undefined:
|
|
|
|
throw "Subtype must be defined"
|
|
|
|
case FieldSubtype.USER:
|
2024-04-23 06:58:35 +12:00
|
|
|
case FieldSubtype.USERS: {
|
2024-04-23 03:27:26 +12:00
|
|
|
const { users } = await cache.user.getUsers(ids)
|
|
|
|
if (!users.length) {
|
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
|
|
|
|
return users.map(u => ({
|
|
|
|
_id: u._id,
|
|
|
|
primaryDisplay: u.email,
|
|
|
|
email: u.email,
|
|
|
|
firstName: u.firstName,
|
|
|
|
lastName: u.lastName,
|
|
|
|
}))
|
2024-04-23 06:58:35 +12:00
|
|
|
}
|
2024-04-23 03:27:26 +12:00
|
|
|
default:
|
|
|
|
throw utils.unreachable(subtype)
|
|
|
|
}
|
2023-09-19 23:17:07 +12:00
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
case FieldType.BB_REFERENCE_SINGLE:
|
|
|
|
const user = await cache.user.getUser(value as string)
|
|
|
|
if (!user) {
|
2023-09-20 21:07:32 +12:00
|
|
|
return undefined
|
|
|
|
}
|
|
|
|
|
2024-04-23 03:27:26 +12:00
|
|
|
return {
|
|
|
|
_id: user._id,
|
|
|
|
primaryDisplay: user.email,
|
|
|
|
email: user.email,
|
|
|
|
firstName: user.firstName,
|
|
|
|
lastName: user.lastName,
|
|
|
|
}
|
|
|
|
|
2023-09-15 23:31:22 +12:00
|
|
|
default:
|
2024-04-23 03:27:26 +12:00
|
|
|
throw utils.unreachable(type)
|
2023-09-15 23:31:22 +12:00
|
|
|
}
|
|
|
|
}
|