chore(server/core/logging): add operation logging to mutations
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
} from '@/modules/core/repositories/tokens'
|
||||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { createPersonalAccessTokenFactory } from '@/modules/core/services/tokens'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
const createPersonalAccessToken = createPersonalAccessTokenFactory({
|
||||
storeApiToken: storeApiTokenFactory({ db }),
|
||||
@@ -44,18 +45,33 @@ const resolvers = {
|
||||
}
|
||||
})
|
||||
|
||||
return await createPersonalAccessToken(
|
||||
context.userId!,
|
||||
args.token.name,
|
||||
args.token.scopes.filter(isValidScope),
|
||||
args.token.lifespan || undefined
|
||||
return await withOperationLogging(
|
||||
async () =>
|
||||
await createPersonalAccessToken(
|
||||
context.userId!,
|
||||
args.token.name,
|
||||
args.token.scopes.filter(isValidScope),
|
||||
args.token.lifespan || undefined
|
||||
),
|
||||
{
|
||||
logger: context.log,
|
||||
operationName: 'createPersonalAccessToken',
|
||||
operationDescription: `Create a new Personal Access Token`
|
||||
}
|
||||
)
|
||||
},
|
||||
async apiTokenRevoke(_parent, args, context) {
|
||||
let id = null
|
||||
if (args.token.toLowerCase().includes('bearer')) id = args.token.split(' ')[1]
|
||||
else id = args.token
|
||||
await revokeToken(id, context.userId!) // let's not revoke other people's tokens
|
||||
await withOperationLogging(
|
||||
async () => await revokeToken(id, context.userId!), // let's not revoke other people's tokens
|
||||
{
|
||||
logger: context.log,
|
||||
operationName: 'revokePersonalAccessToken',
|
||||
operationDescription: `Revoke a Personal Access Token`
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
storeUserServerAppTokenFactory
|
||||
} from '@/modules/core/repositories/tokens'
|
||||
import { createAppTokenFactory } from '@/modules/core/services/tokens'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
const getTokenAppInfo = getTokenAppInfoFactory({ db })
|
||||
const createAppToken = createAppTokenFactory({
|
||||
@@ -50,13 +51,21 @@ export = {
|
||||
})
|
||||
|
||||
const scopes = args.token.scopes.filter(isValidScope)
|
||||
const token = await createAppToken({
|
||||
...args.token,
|
||||
userId: ctx.userId!,
|
||||
appId,
|
||||
lifespan: args.token.lifespan || undefined,
|
||||
scopes
|
||||
})
|
||||
const token = await withOperationLogging(
|
||||
async () =>
|
||||
await createAppToken({
|
||||
...args.token,
|
||||
userId: ctx.userId!,
|
||||
appId,
|
||||
lifespan: args.token.lifespan || undefined,
|
||||
scopes
|
||||
}),
|
||||
{
|
||||
logger: ctx.log,
|
||||
operationName: 'createAppToken',
|
||||
operationDescription: `Create a new App Token`
|
||||
}
|
||||
)
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
throwIfAuthNotOk
|
||||
} from '@/modules/shared/helpers/errorHelper'
|
||||
import { throwIfResourceAccessNotAllowed } from '@/modules/core/helpers/token'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
export = {
|
||||
Query: {},
|
||||
@@ -83,66 +84,101 @@ export = {
|
||||
resourceAccessRules: context.resourceAccessRules
|
||||
})
|
||||
|
||||
const projectId = args.branch.streamId
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
const canCreate = await context.authPolicies.project.model.canCreate({
|
||||
userId: context.userId,
|
||||
projectId: args.branch.streamId
|
||||
projectId
|
||||
})
|
||||
|
||||
if (!canCreate.isOk) {
|
||||
throw mapAuthToServerError(canCreate.error)
|
||||
}
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.branch.streamId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
const getStreamBranchByName = getStreamBranchByNameFactory({ db: projectDB })
|
||||
const createBranchAndNotify = createBranchAndNotifyFactory({
|
||||
getStreamBranchByName,
|
||||
createBranch: createBranchFactory({ db: projectDB }),
|
||||
eventEmit: getEventBus().emit
|
||||
})
|
||||
const { id } = await createBranchAndNotify(args.branch, context.userId!)
|
||||
const { id } = await withOperationLogging(
|
||||
async () => await createBranchAndNotify(args.branch, context.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'createBranch',
|
||||
operationDescription: `Create a new Branch`
|
||||
}
|
||||
)
|
||||
|
||||
return id
|
||||
},
|
||||
|
||||
async branchUpdate(_parent, args, ctx) {
|
||||
const projectId = args.branch.streamId
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.branch.streamId,
|
||||
resourceAccessRules: ctx.resourceAccessRules,
|
||||
resourceType: TokenResourceIdentifierType.Project
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
const canUpdate = await ctx.authPolicies.project.model.canUpdate({
|
||||
userId: ctx.userId,
|
||||
projectId: args.branch.streamId
|
||||
projectId
|
||||
})
|
||||
throwIfAuthNotOk(canUpdate)
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.branch.streamId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
const getBranchById = getBranchByIdFactory({ db: projectDB })
|
||||
const updateBranchAndNotify = updateBranchAndNotifyFactory({
|
||||
getBranchById,
|
||||
updateBranch: updateBranchFactory({ db: projectDB }),
|
||||
eventEmit: getEventBus().emit
|
||||
})
|
||||
const newBranch = await updateBranchAndNotify(args.branch, ctx.userId!)
|
||||
const newBranch = await withOperationLogging(
|
||||
async () => await updateBranchAndNotify(args.branch, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'updateBranch',
|
||||
operationDescription: `Update a Branch`
|
||||
}
|
||||
)
|
||||
return !!newBranch
|
||||
},
|
||||
|
||||
async branchDelete(_parent, args, context) {
|
||||
const projectId = args.branch.streamId
|
||||
const modelId = args.branch.id
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.branch.streamId,
|
||||
resourceAccessRules: context.resourceAccessRules,
|
||||
resourceType: TokenResourceIdentifierType.Project
|
||||
})
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
modelId
|
||||
})
|
||||
|
||||
const canDelete = await context.authPolicies.project.model.canDelete({
|
||||
userId: context.userId,
|
||||
projectId: args.branch.streamId,
|
||||
modelId: args.branch.id
|
||||
projectId,
|
||||
modelId
|
||||
})
|
||||
throwIfAuthNotOk(canDelete)
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.branch.streamId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
const markBranchStreamUpdated = markBranchStreamUpdatedFactory({ db: projectDB })
|
||||
const getStream = getStreamFactory({ db: projectDB })
|
||||
const deleteBranchAndNotify = deleteBranchAndNotifyFactory({
|
||||
@@ -152,7 +188,14 @@ export = {
|
||||
markBranchStreamUpdated,
|
||||
deleteBranchById: deleteBranchByIdFactory({ db: projectDB })
|
||||
})
|
||||
const deleted = await deleteBranchAndNotify(args.branch, context.userId!)
|
||||
const deleted = await withOperationLogging(
|
||||
async () => await deleteBranchAndNotify(args.branch, context.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'deleteBranch',
|
||||
operationDescription: `Delete a Branch`
|
||||
}
|
||||
)
|
||||
return deleted
|
||||
}
|
||||
},
|
||||
|
||||
@@ -82,6 +82,7 @@ import { TokenResourceIdentifierType } from '@/modules/core/domain/tokens/types'
|
||||
import { throwIfAuthNotOk } from '@/modules/shared/helpers/errorHelper'
|
||||
import { getFeatureFlags } from '@/modules/shared/helpers/envHelper'
|
||||
import { getDateFromLimitsFactory } from '@/modules/core/services/versions/limits'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
const { FF_FORCE_PERSONAL_PROJECTS_LIMITS_ENABLED } = getFeatureFlags()
|
||||
|
||||
@@ -361,6 +362,15 @@ export = {
|
||||
throw new RateLimitError(rateLimitResult)
|
||||
}
|
||||
|
||||
const projectId = args.commit.streamId
|
||||
const modelName = args.commit.branchName
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
modelName,
|
||||
branchName: modelName //legacy
|
||||
})
|
||||
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.commit.streamId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
@@ -368,15 +378,15 @@ export = {
|
||||
})
|
||||
const canCreate = await context.authPolicies.project.version.canCreate({
|
||||
userId: context.userId,
|
||||
projectId: args.commit.streamId
|
||||
projectId
|
||||
})
|
||||
throwIfAuthNotOk(canCreate)
|
||||
|
||||
await coreModule.executeHooks('onCreateVersionRequest', {
|
||||
projectId: args.commit.streamId
|
||||
projectId
|
||||
})
|
||||
|
||||
const projectDb = await getProjectDbClient({ projectId: args.commit.streamId })
|
||||
const projectDb = await getProjectDbClient({ projectId })
|
||||
|
||||
const createCommitByBranchId = createCommitByBranchIdFactory({
|
||||
createCommit: createCommitFactory({ db: projectDb }),
|
||||
@@ -395,21 +405,38 @@ export = {
|
||||
getBranchById: getBranchByIdFactory({ db: projectDb })
|
||||
})
|
||||
|
||||
const { id } = await createCommitByBranchName({
|
||||
...args.commit,
|
||||
parents: args.commit.parents?.filter(isNonNullable),
|
||||
authorId: context.userId!
|
||||
})
|
||||
const { id } = await withOperationLogging(
|
||||
async () =>
|
||||
await createCommitByBranchName({
|
||||
...args.commit,
|
||||
parents: args.commit.parents?.filter(isNonNullable),
|
||||
authorId: context.userId!
|
||||
}),
|
||||
{
|
||||
logger,
|
||||
operationName: 'createCommit',
|
||||
operationDescription: `Create a new Commit`
|
||||
}
|
||||
)
|
||||
|
||||
return id
|
||||
},
|
||||
|
||||
async commitUpdate(_parent, args, context) {
|
||||
const projectId = args.commit.streamId
|
||||
const commitId = args.commit.id
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.commit.streamId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
resourceAccessRules: context.resourceAccessRules
|
||||
})
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
commitId
|
||||
})
|
||||
|
||||
const canUpdate = await context.authPolicies.project.version.canUpdate({
|
||||
userId: context.userId,
|
||||
projectId: args.commit.streamId,
|
||||
@@ -430,48 +457,83 @@ export = {
|
||||
markCommitStreamUpdated: markCommitStreamUpdatedFactory({ db: projectDb }),
|
||||
markCommitBranchUpdated: markCommitBranchUpdatedFactory({ db: projectDb })
|
||||
})
|
||||
await updateCommitAndNotify(args.commit, context.userId!)
|
||||
await withOperationLogging(
|
||||
async () => await updateCommitAndNotify(args.commit, context.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'updateCommit',
|
||||
operationDescription: `Update a Commit`
|
||||
}
|
||||
)
|
||||
return true
|
||||
},
|
||||
|
||||
async commitReceive(_parent, args, context) {
|
||||
const projectId = args.input.streamId
|
||||
const versionId = args.input.commitId
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.streamId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
resourceAccessRules: context.resourceAccessRules
|
||||
})
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy,
|
||||
versionId,
|
||||
commitId: versionId //legacy
|
||||
})
|
||||
|
||||
const canReceive = await context.authPolicies.project.version.canReceive({
|
||||
userId: context.userId,
|
||||
projectId: args.input.streamId
|
||||
projectId
|
||||
})
|
||||
throwIfAuthNotOk(canReceive)
|
||||
|
||||
const projectDb = await getProjectDbClient({ projectId: args.input.streamId })
|
||||
await markCommitReceivedAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db: projectDb }),
|
||||
emitEvent: getEventBus().emit
|
||||
})({
|
||||
input: args.input,
|
||||
userId: context.userId!
|
||||
})
|
||||
const projectDb = await getProjectDbClient({ projectId })
|
||||
await withOperationLogging(
|
||||
async () =>
|
||||
await markCommitReceivedAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db: projectDb }),
|
||||
emitEvent: getEventBus().emit
|
||||
})({
|
||||
input: args.input,
|
||||
userId: context.userId!
|
||||
}),
|
||||
{
|
||||
logger,
|
||||
operationName: 'receiveCommit',
|
||||
operationDescription: `Receive a Commit`
|
||||
}
|
||||
)
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
async commitDelete(_parent, args, context) {
|
||||
const projectId = args.commit.streamId
|
||||
const versionId = args.commit.id
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.commit.streamId,
|
||||
resourceId: projectId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
resourceAccessRules: context.resourceAccessRules
|
||||
})
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
versionId,
|
||||
commitId: versionId //legacy
|
||||
})
|
||||
|
||||
const canUpdate = await context.authPolicies.project.version.canUpdate({
|
||||
userId: context.userId,
|
||||
projectId: args.commit.streamId,
|
||||
versionId: args.commit.id
|
||||
projectId,
|
||||
versionId
|
||||
})
|
||||
throwIfAuthNotOk(canUpdate)
|
||||
|
||||
const projectDb = await getProjectDbClient({ projectId: args.commit.streamId })
|
||||
const projectDb = await getProjectDbClient({ projectId })
|
||||
const deleteCommitAndNotify = deleteCommitAndNotifyFactory({
|
||||
getCommit: getCommitFactory({ db: projectDb }),
|
||||
markCommitStreamUpdated: markCommitStreamUpdatedFactory({ db: projectDb }),
|
||||
@@ -479,22 +541,33 @@ export = {
|
||||
deleteCommit: deleteCommitFactory({ db: projectDb }),
|
||||
emitEvent: getEventBus().emit
|
||||
})
|
||||
const deleted = await deleteCommitAndNotify(
|
||||
args.commit.id,
|
||||
args.commit.streamId,
|
||||
context.userId!
|
||||
const deleted = await withOperationLogging(
|
||||
async () =>
|
||||
await deleteCommitAndNotify(args.commit.id, projectId, context.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'deleteCommit',
|
||||
operationDescription: 'Delete a Commit'
|
||||
}
|
||||
)
|
||||
return deleted
|
||||
},
|
||||
|
||||
// Not used by connectors
|
||||
async commitsMove(_, args, ctx) {
|
||||
const projectId = args.input.streamId
|
||||
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.streamId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
resourceAccessRules: ctx.resourceAccessRules
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
const canUpdateAll = await Promise.all(
|
||||
args.input.commitIds.map(async (versionId) =>
|
||||
ctx.authPolicies.project.version.canUpdate({
|
||||
@@ -517,23 +590,36 @@ export = {
|
||||
moveCommitsToBranch: moveCommitsToBranchFactory({ db: projectDb }),
|
||||
emitEvent: getEventBus().emit
|
||||
})
|
||||
await batchMoveCommits(args.input, ctx.userId!)
|
||||
await withOperationLogging(
|
||||
async () => await batchMoveCommits(args.input, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'moveCommits',
|
||||
operationDescription: 'Move one or more commits'
|
||||
}
|
||||
)
|
||||
return true
|
||||
},
|
||||
|
||||
// Not used by connectors
|
||||
async commitsDelete(_, args, ctx) {
|
||||
const projectId = args.input.streamId
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.streamId,
|
||||
resourceId: projectId,
|
||||
resourceType: TokenResourceIdentifierType.Project,
|
||||
resourceAccessRules: ctx.resourceAccessRules
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
const canUpdateAll = await Promise.all(
|
||||
args.input.commitIds.map(async (versionId) =>
|
||||
ctx.authPolicies.project.version.canUpdate({
|
||||
userId: ctx.userId,
|
||||
projectId: args.input.streamId,
|
||||
projectId,
|
||||
versionId
|
||||
})
|
||||
)
|
||||
@@ -542,14 +628,21 @@ export = {
|
||||
throwIfAuthNotOk(result)
|
||||
})
|
||||
|
||||
const projectDb = await getProjectDbClient({ projectId: args.input.streamId })
|
||||
const projectDb = await getProjectDbClient({ projectId })
|
||||
const batchDeleteCommits = batchDeleteCommitsFactory({
|
||||
getCommits: getCommitsFactory({ db: projectDb }),
|
||||
getStreams,
|
||||
deleteCommits: deleteCommitsFactory({ db: projectDb }),
|
||||
emitEvent: getEventBus().emit
|
||||
})
|
||||
await batchDeleteCommits(args.input, ctx.userId!)
|
||||
await withOperationLogging(
|
||||
async () => await batchDeleteCommits(args.input, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'deleteCommits',
|
||||
operationDescription: 'Delete one or more commits'
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
},
|
||||
|
||||
@@ -59,6 +59,7 @@ import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||
import { throwIfAuthNotOk } from '@/modules/shared/helpers/errorHelper'
|
||||
import { throwIfResourceAccessNotAllowed } from '@/modules/core/helpers/token'
|
||||
import { TokenResourceIdentifierType } from '@/modules/core/domain/tokens/types'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
export = {
|
||||
User: {
|
||||
@@ -297,19 +298,25 @@ export = {
|
||||
},
|
||||
ModelMutations: {
|
||||
async create(_parent, args, ctx) {
|
||||
const projectId = args.input.projectId
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.projectId,
|
||||
resourceId: projectId,
|
||||
resourceAccessRules: ctx.resourceAccessRules,
|
||||
resourceType: TokenResourceIdentifierType.Project
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
const canCreate = await ctx.authPolicies.project.model.canCreate({
|
||||
userId: ctx.userId,
|
||||
projectId: args.input.projectId
|
||||
projectId
|
||||
})
|
||||
throwIfAuthNotOk(canCreate)
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.input.projectId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
|
||||
// Sanitize model name by trimming spaces around slashes
|
||||
const sanitizedInput = {
|
||||
@@ -326,44 +333,76 @@ export = {
|
||||
createBranch: createBranchFactory({ db: projectDB }),
|
||||
eventEmit: getEventBus().emit
|
||||
})
|
||||
return await createBranchAndNotify(sanitizedInput, ctx.userId!)
|
||||
return await withOperationLogging(
|
||||
async () => await createBranchAndNotify(sanitizedInput, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'createModel',
|
||||
operationDescription: `Create a new Model`
|
||||
}
|
||||
)
|
||||
},
|
||||
async update(_parent, args, ctx) {
|
||||
const projectId = args.input.projectId
|
||||
const modelId = args.input.id
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.projectId,
|
||||
resourceId: projectId,
|
||||
resourceAccessRules: ctx.resourceAccessRules,
|
||||
resourceType: TokenResourceIdentifierType.Project
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
modelId,
|
||||
branchId: modelId //legacy
|
||||
})
|
||||
|
||||
const canUpdate = await ctx.authPolicies.project.model.canUpdate({
|
||||
userId: ctx.userId,
|
||||
projectId: args.input.projectId
|
||||
projectId
|
||||
})
|
||||
throwIfAuthNotOk(canUpdate)
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.input.projectId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
const updateBranchAndNotify = updateBranchAndNotifyFactory({
|
||||
getBranchById: getBranchByIdFactory({ db: projectDB }),
|
||||
updateBranch: updateBranchFactory({ db: projectDB }),
|
||||
eventEmit: getEventBus().emit
|
||||
})
|
||||
return await updateBranchAndNotify(args.input, ctx.userId!)
|
||||
return await withOperationLogging(
|
||||
async () => await updateBranchAndNotify(args.input, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'updateModel',
|
||||
operationDescription: `Update a Model`
|
||||
}
|
||||
)
|
||||
},
|
||||
async delete(_parent, args, ctx) {
|
||||
const projectId = args.input.projectId
|
||||
const modelId = args.input.id
|
||||
throwIfResourceAccessNotAllowed({
|
||||
resourceId: args.input.projectId,
|
||||
resourceAccessRules: ctx.resourceAccessRules,
|
||||
resourceType: TokenResourceIdentifierType.Project
|
||||
})
|
||||
|
||||
const logger = ctx.log.child({
|
||||
projectId,
|
||||
streamId: projectId, //legacy
|
||||
modelId,
|
||||
branchId: modelId //legacy
|
||||
})
|
||||
|
||||
const canDelete = await ctx.authPolicies.project.model.canDelete({
|
||||
userId: ctx.userId,
|
||||
projectId: args.input.projectId,
|
||||
modelId: args.input.id
|
||||
projectId,
|
||||
modelId
|
||||
})
|
||||
throwIfAuthNotOk(canDelete)
|
||||
|
||||
const projectDB = await getProjectDbClient({ projectId: args.input.projectId })
|
||||
const projectDB = await getProjectDbClient({ projectId })
|
||||
const markBranchStreamUpdated = markBranchStreamUpdatedFactory({ db: projectDB })
|
||||
const getStream = getStreamFactory({ db })
|
||||
const deleteBranchAndNotify = deleteBranchAndNotifyFactory({
|
||||
@@ -373,7 +412,14 @@ export = {
|
||||
markBranchStreamUpdated,
|
||||
deleteBranchById: deleteBranchByIdFactory({ db: projectDB })
|
||||
})
|
||||
return await deleteBranchAndNotify(args.input, ctx.userId!)
|
||||
return await withOperationLogging(
|
||||
async () => await deleteBranchAndNotify(args.input, ctx.userId!),
|
||||
{
|
||||
logger,
|
||||
operationName: 'deleteModel',
|
||||
operationDescription: `Delete a Model`
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
Subscription: {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { createObjectsFactory } from '@/modules/core/services/objects/management'
|
||||
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
|
||||
import coreModule from '@/modules/core'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
type GetObjectChildrenQueryParams = Parameters<
|
||||
ReturnType<typeof getObjectChildrenQueryFactory>
|
||||
@@ -93,6 +94,8 @@ export = {
|
||||
},
|
||||
Mutation: {
|
||||
async objectCreate(_parent, args, context) {
|
||||
const projectId = args.objectInput.streamId
|
||||
|
||||
await authorizeResolver(
|
||||
context.userId,
|
||||
args.objectInput.streamId,
|
||||
@@ -100,20 +103,33 @@ export = {
|
||||
context.resourceAccessRules
|
||||
)
|
||||
|
||||
const logger = context.log.child({
|
||||
projectId,
|
||||
streamId: projectId //legacy
|
||||
})
|
||||
|
||||
await coreModule.executeHooks?.('onCreateObjectRequest', {
|
||||
projectId: args.objectInput.streamId
|
||||
projectId
|
||||
})
|
||||
|
||||
const projectDB = await getProjectDbClient({
|
||||
projectId: args.objectInput.streamId
|
||||
projectId
|
||||
})
|
||||
const createObjects = createObjectsFactory({
|
||||
storeObjectsIfNotFoundFactory: storeObjectsIfNotFoundFactory({ db: projectDB })
|
||||
})
|
||||
const ids = await createObjects({
|
||||
streamId: args.objectInput.streamId,
|
||||
objects: args.objectInput.objects.filter(isNonNullable)
|
||||
})
|
||||
const ids = await withOperationLogging(
|
||||
async () =>
|
||||
await createObjects({
|
||||
streamId: projectId,
|
||||
objects: args.objectInput.objects.filter(isNonNullable)
|
||||
}),
|
||||
{
|
||||
logger,
|
||||
operationName: 'objectCreate',
|
||||
operationDescription: `Create one or more new objects`
|
||||
}
|
||||
)
|
||||
return ids
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,14 @@ export const logErrorThenThrow = (err: unknown, logger: Logger) => {
|
||||
throw err
|
||||
}
|
||||
|
||||
/**
|
||||
* @description withOperationLogging is intended to be used for adding observability to high-level 'business' operations
|
||||
* (e.g. creating a new object, sending an email, etc). It will log the start and end of the operation, as well as any errors that occur.
|
||||
* It is likely to only be called directly within mutation Graphql resolvers and POST/PUT/DELETE REST endpoints.
|
||||
* @param operation
|
||||
* @param params
|
||||
* @returns Returns the result of the operation
|
||||
*/
|
||||
export const withOperationLogging = async <T>(
|
||||
operation: () => T,
|
||||
params: {
|
||||
|
||||
Reference in New Issue
Block a user