Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x |
import { LocalConfigParsed } from './types/mongoDbTypes'
import { hookInterpreterExpose } from '../0_hooks/hookInterpreterExpose'
import { mongoFilterHookInterpreter } from './hooks/mongoFilterHookInterpreter'
import { mongoSanitizeFilter } from './services/mongoSanitizeFilter'
import { unPopulate } from './services/populateService'
import { applyMaskIncludingOnPopulatedFieldsRecursive } from './services/maskService'
import event from '../../event'
import { getId } from 'topkat-utils'
import { getProjectDatabaseModels } from '../../helpers/getProjectModelsAndDaos'
export async function mongoBeforeRequest(
ctx: Ctx,
localConfig: LocalConfigParsed,
): Promise<void> {
localConfig.ressourceId = getId(localConfig.inputFields) || getId(localConfig?.filter)
const { modelName, method, dbName, dbId, ressourceId } = localConfig
const hasFields = localConfig.inputFields && Object.keys(localConfig.inputFields).length
const errExtraInfos = { modelName, dbName, dbId, method }
await hookInterpreterExpose(ctx, dbId, dbName, method, modelName) // may throw
await mongoSanitizeFilter(ctx, localConfig)
// APPLY SECURITY FILTERS
await mongoFilterHookInterpreter(ctx, localConfig)
// EMIT "BEFORE" EVENTS
// they are applied after security so that every changes that are made by an event is made as a system eventhough the ctx used is a normal one
if (!ctx.simulateRequest && !localConfig.disableEmittingEvents) {
const eventName = `${modelName}.${method}.before` // user.create.before
// all that mess to keep type safe on ctx, ctx has different type depending on the method (getOne, update...)
if (method === 'create') {
await event.emit(
`${modelName}.create.before`,
ctx.clone({ ...localConfig, method, inputFields: localConfig.inputFields, createdId: localConfig.inputFields._id })
)
} else if (method === 'update') {
if (!localConfig.ressourceId && event.registeredEvents[eventName] && event.registeredEvents[eventName].length) {
throw ctx.error.serverError(`An event is registered on this request. When updating all, please use 'disableEmittingEvents' in request config, so that you make sure event emitting is bypassed. Actually updating all is not compatible with event emitting, because you wont get the id of the updated field`)
}
await event.emit(
`${modelName}.update.before`,
ctx.clone({ ...localConfig, method, updatedId: ressourceId, inputFields: localConfig.inputFields })
)
} else if (method === 'getOne') {
await event.emit(
`${modelName}.getOne.before`,
ctx.clone({ ...localConfig, method })
)
} else if (method === 'getAll') {
await event.emit(
`${modelName}.getAll.before`,
ctx.clone({ ...localConfig, method })
)
} else if (method === 'delete') {
await event.emit(
`${modelName}.delete.before`,
ctx.clone({ ...localConfig, method, deletedId: ressourceId })
)
} else throw ctx.error.serverError('notExistingMethod', { method })
}
if (hasFields) {
await unPopulate(dbName, modelName, localConfig.inputFields)
// MASK UNAUTHORIZED DATA IN BODY
localConfig.inputFields = await applyMaskIncludingOnPopulatedFieldsRecursive(ctx, method, dbName, modelName, localConfig.inputFields, false)
// CHECK TYPES AND FORMAT DATA
const dbs = await getProjectDatabaseModels()
const validator = dbs[dbName][modelName]
localConfig.inputFields = await validator.formatAndValidate(localConfig.inputFields, {
user: ctx.getUserMinimal(),
method,
dbName,
dbId,
modelName,
errorExtraInfos: errExtraInfos
})
}
if (method === 'update' && hasFields) delete localConfig.inputFields._id // this is here so in an event we can still rely on fields._id if needed, the best way is to use ctx.ressourceId
} |