Merge pull request #12587 from Budibase/instrument-formula-processing
Instrument formula processing in DataDog.
This commit is contained in:
commit
2dd07b9768
|
@ -12,103 +12,112 @@ import { getCachedSelf } from "../utilities/global"
|
|||
import env from "../environment"
|
||||
import { isWebhookEndpoint } from "./utils"
|
||||
import { UserCtx, ContextUser } from "@budibase/types"
|
||||
import tracer from "dd-trace"
|
||||
|
||||
export default async (ctx: UserCtx, next: any) => {
|
||||
// try to get the appID from the request
|
||||
let requestAppId = await utils.getAppIdFromCtx(ctx)
|
||||
if (!requestAppId) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// deny access to application preview
|
||||
if (!env.isTest()) {
|
||||
if (
|
||||
isDevAppID(requestAppId) &&
|
||||
!isWebhookEndpoint(ctx) &&
|
||||
!users.isBuilder(ctx.user, requestAppId)
|
||||
) {
|
||||
return ctx.redirect("/")
|
||||
return tracer.trace("currentapp middleware", {}, async span => {
|
||||
// try to get the appID from the request
|
||||
let requestAppId = await utils.getAppIdFromCtx(ctx)
|
||||
if (!requestAppId) {
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
let appId: string | undefined,
|
||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
if (!ctx.user?._id) {
|
||||
// not logged in, try to set a cookie for public apps
|
||||
appId = requestAppId
|
||||
} else if (requestAppId != null) {
|
||||
// Different App ID means cookie needs reset, or if the same public user has logged in
|
||||
const globalUser = await getCachedSelf(ctx, requestAppId)
|
||||
appId = requestAppId
|
||||
// retrieving global user gets the right role
|
||||
roleId = globalUser.roleId || roleId
|
||||
if (requestAppId) {
|
||||
span?.addTags({ app_id: requestAppId })
|
||||
}
|
||||
|
||||
// Allow builders to specify their role via a header
|
||||
const isBuilder = users.isBuilder(globalUser, appId)
|
||||
const isDevApp = appId && isDevAppID(appId)
|
||||
const roleHeader =
|
||||
ctx.request &&
|
||||
(ctx.request.headers[constants.Header.PREVIEW_ROLE] as string)
|
||||
if (isBuilder && isDevApp && roleHeader) {
|
||||
// Ensure the role is valid by ensuring a definition exists
|
||||
try {
|
||||
if (roleHeader) {
|
||||
await roles.getRole(roleHeader)
|
||||
roleId = roleHeader
|
||||
// deny access to application preview
|
||||
if (!env.isTest()) {
|
||||
if (
|
||||
isDevAppID(requestAppId) &&
|
||||
!isWebhookEndpoint(ctx) &&
|
||||
!users.isBuilder(ctx.user, requestAppId)
|
||||
) {
|
||||
return ctx.redirect("/")
|
||||
}
|
||||
}
|
||||
|
||||
// Delete admin and builder flags so that the specified role is honoured
|
||||
ctx.user = users.removePortalUserPermissions(ctx.user) as ContextUser
|
||||
let appId: string | undefined,
|
||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
if (!ctx.user?._id) {
|
||||
// not logged in, try to set a cookie for public apps
|
||||
appId = requestAppId
|
||||
} else if (requestAppId != null) {
|
||||
// Different App ID means cookie needs reset, or if the same public user has logged in
|
||||
const globalUser = await getCachedSelf(ctx, requestAppId)
|
||||
appId = requestAppId
|
||||
// retrieving global user gets the right role
|
||||
roleId = globalUser.roleId || roleId
|
||||
|
||||
// Allow builders to specify their role via a header
|
||||
const isBuilder = users.isBuilder(globalUser, appId)
|
||||
const isDevApp = appId && isDevAppID(appId)
|
||||
const roleHeader =
|
||||
ctx.request &&
|
||||
(ctx.request.headers[constants.Header.PREVIEW_ROLE] as string)
|
||||
if (isBuilder && isDevApp && roleHeader) {
|
||||
// Ensure the role is valid by ensuring a definition exists
|
||||
try {
|
||||
if (roleHeader) {
|
||||
await roles.getRole(roleHeader)
|
||||
roleId = roleHeader
|
||||
|
||||
// Delete admin and builder flags so that the specified role is honoured
|
||||
ctx.user = users.removePortalUserPermissions(
|
||||
ctx.user
|
||||
) as ContextUser
|
||||
}
|
||||
} catch (error) {
|
||||
// Swallow error and do nothing
|
||||
}
|
||||
} catch (error) {
|
||||
// Swallow error and do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nothing more to do
|
||||
if (!appId) {
|
||||
return next()
|
||||
}
|
||||
// nothing more to do
|
||||
if (!appId) {
|
||||
return next()
|
||||
}
|
||||
|
||||
const userId = ctx.user ? generateUserMetadataID(ctx.user._id!) : undefined
|
||||
const userId = ctx.user ? generateUserMetadataID(ctx.user._id!) : undefined
|
||||
|
||||
// if the user is not in the right tenant then make sure to wipe their cookie
|
||||
// also cleanse any information about them that has been allocated
|
||||
// this avoids apps making calls to say the worker which are cross tenant,
|
||||
// we simply remove the authentication
|
||||
if (
|
||||
env.MULTI_TENANCY &&
|
||||
userId &&
|
||||
requestAppId &&
|
||||
!tenancy.isUserInAppTenant(requestAppId, ctx.user)
|
||||
) {
|
||||
// clear out the user
|
||||
ctx.user = users.cleanseUserObject(ctx.user) as ContextUser
|
||||
ctx.isAuthenticated = false
|
||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
// remove the cookie, so future calls are public
|
||||
await auth.platformLogout({
|
||||
ctx,
|
||||
userId,
|
||||
})
|
||||
}
|
||||
|
||||
return context.doInAppContext(appId, async () => {
|
||||
ctx.appId = appId
|
||||
if (roleId) {
|
||||
ctx.roleId = roleId
|
||||
const globalId = ctx.user ? ctx.user._id : undefined
|
||||
ctx.user = {
|
||||
...ctx.user!,
|
||||
// override userID with metadata one
|
||||
_id: userId,
|
||||
// if the user is not in the right tenant then make sure to wipe their cookie
|
||||
// also cleanse any information about them that has been allocated
|
||||
// this avoids apps making calls to say the worker which are cross tenant,
|
||||
// we simply remove the authentication
|
||||
if (
|
||||
env.MULTI_TENANCY &&
|
||||
userId &&
|
||||
requestAppId &&
|
||||
!tenancy.isUserInAppTenant(requestAppId, ctx.user)
|
||||
) {
|
||||
// clear out the user
|
||||
ctx.user = users.cleanseUserObject(ctx.user) as ContextUser
|
||||
ctx.isAuthenticated = false
|
||||
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
|
||||
// remove the cookie, so future calls are public
|
||||
await auth.platformLogout({
|
||||
ctx,
|
||||
userId,
|
||||
globalId,
|
||||
roleId,
|
||||
role: await roles.getRole(roleId, { defaultPublic: true }),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return next()
|
||||
return context.doInAppContext(appId, async () => {
|
||||
ctx.appId = appId
|
||||
if (roleId) {
|
||||
ctx.roleId = roleId
|
||||
const globalId = ctx.user ? ctx.user._id : undefined
|
||||
ctx.user = {
|
||||
...ctx.user!,
|
||||
// override userID with metadata one
|
||||
_id: userId,
|
||||
userId,
|
||||
globalId,
|
||||
roleId,
|
||||
role: await roles.getRole(roleId, { defaultPublic: true }),
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
Row,
|
||||
Table,
|
||||
} from "@budibase/types"
|
||||
import tracer from "dd-trace"
|
||||
|
||||
interface FormulaOpts {
|
||||
dynamic?: boolean
|
||||
|
@ -50,33 +51,41 @@ export function processFormulas<T extends Row | Row[]>(
|
|||
inputRows: T,
|
||||
{ dynamic, contextRows }: FormulaOpts = { dynamic: true }
|
||||
): T {
|
||||
const rows = Array.isArray(inputRows) ? inputRows : [inputRows]
|
||||
if (rows)
|
||||
for (let [column, schema] of Object.entries(table.schema)) {
|
||||
if (schema.type !== FieldTypes.FORMULA) {
|
||||
continue
|
||||
}
|
||||
return tracer.trace("processFormulas", {}, span => {
|
||||
span?.addTags({ table_id: table._id })
|
||||
const rows = Array.isArray(inputRows) ? inputRows : [inputRows]
|
||||
if (rows) {
|
||||
for (let [column, schema] of Object.entries(table.schema)) {
|
||||
if (schema.type !== FieldTypes.FORMULA) {
|
||||
continue
|
||||
}
|
||||
|
||||
const isStatic = schema.formulaType === FormulaTypes.STATIC
|
||||
const isStatic = schema.formulaType === FormulaTypes.STATIC
|
||||
|
||||
if (
|
||||
schema.formula == null ||
|
||||
(dynamic && isStatic) ||
|
||||
(!dynamic && !isStatic)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
// iterate through rows and process formula
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i]
|
||||
let context = contextRows ? contextRows[i] : row
|
||||
rows[i] = {
|
||||
...row,
|
||||
[column]: processStringSync(schema.formula, context),
|
||||
if (
|
||||
schema.formula == null ||
|
||||
(dynamic && isStatic) ||
|
||||
(!dynamic && !isStatic)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
// iterate through rows and process formula
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i]
|
||||
let context = contextRows ? contextRows[i] : row
|
||||
let formula = schema.formula
|
||||
rows[i] = {
|
||||
...row,
|
||||
[column]: tracer.trace("processStringSync", {}, span => {
|
||||
span?.addTags({ column })
|
||||
return processStringSync(formula, context)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Array.isArray(inputRows) ? rows : rows[0]
|
||||
return Array.isArray(inputRows) ? rows : rows[0]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue