Files
speckle-server/packages/server/modules/webhooks/graph/resolvers/webhooks.ts
T
Kristaps Fabians Geikins bde148f286 chore(server): migrating fully to ESM (#5042)
* wip

* some extra fixes

* stuff kinda works?

* need to figure out mocks

* need to figure out mocks

* fix db listener

* gqlgen fix

* minor gqlgen watch adjustment

* lint fixes

* delete old codegen file

* converting migrations to ESM

* getModuleDIrectory

* vitest sort of works

* added back ts-vitest

* resolve gql double load

* fixing test timeout configs

* TSC lint fix

* fix automate tests

* moar debugging

* debugging

* more debugging

* codegen update

* server works

* yargs migrated

* chore(server): getting rid of global mocks for Server ESM (#5046)

* got rid of email mock

* got rid of comment mocks

* got rid of multi region mocks

* got rid of stripe mock

* admin override mock updated

* removed final mock

* fixing import.meta.resolve calls

* another import.meta.resolve fix

* added requested test

* nyc ESM fix

* removed unneeded deps + linting

* yarn lock forgot to commit

* tryna fix flakyness

* email capture util fix

* sendEmail fix

* fix TSX check

* sender transporter fix + CR comments

* merge main fix

* test fixx

* circleci fix

* gqlgen bigint fix

* error formatter fix

* more error formatting improvements

* esmloader added to Dockerfile

* more dockerfile fixes

* bg jobs fix
2025-07-14 10:26:19 +03:00

206 lines
6.1 KiB
TypeScript

import { Resolvers } from '@/modules/core/graph/generated/graphql'
import { authorizeResolver } from '@/modules/shared'
import {
createWebhookFactory,
deleteWebhookFactory,
updateWebhookFactory
} from '@/modules/webhooks/services/webhooks'
import { Authz, Roles } from '@speckle/shared'
import {
countWebhooksByStreamIdFactory,
createWebhookConfigFactory,
deleteWebhookConfigFactory,
getLastWebhookEventsFactory,
getStreamWebhooksFactory,
getWebhookByIdFactory,
getWebhookEventsCountFactory,
updateWebhookConfigFactory
} from '@/modules/webhooks/repositories/webhooks'
import { ForbiddenError } from '@/modules/shared/errors'
import {
TokenResourceIdentifier,
TokenResourceIdentifierType
} from '@/modules/core/domain/tokens/types'
import { getProjectDbClient } from '@/modules/multiregion/utils/dbSelector'
import { throwIfResourceAccessNotAllowed } from '@/modules/core/helpers/token'
import { throwIfAuthNotOk } from '@/modules/shared/helpers/errorHelper'
import { withOperationLogging } from '@/observability/domain/businessLogging'
const streamWebhooksResolver = async (
parent: { id: string },
args: { id?: string },
context: {
resourceAccessRules?: TokenResourceIdentifier[] | null
userId: string
authPolicies: Authz.AuthPolicies
}
) => {
throwIfResourceAccessNotAllowed({
resourceId: parent.id,
resourceType: TokenResourceIdentifierType.Project,
resourceAccessRules: context.resourceAccessRules
})
const canReadWebhooks = await context.authPolicies.project.canReadWebhooks({
projectId: parent.id,
userId: context.userId
})
throwIfAuthNotOk(canReadWebhooks)
const projectDb = await getProjectDbClient({ projectId: parent.id })
if (args.id) {
const wh = await getWebhookByIdFactory({ db: projectDb })({ id: args.id })
const items = wh ? [wh] : []
return { items, totalCount: items.length }
}
const items = await getStreamWebhooksFactory({ db: projectDb })({
streamId: parent.id
})
return { items, totalCount: items.length }
}
export default {
Webhook: {
projectId: (parent) => parent.streamId,
hasSecret: (parent) => !!parent.secret?.length,
history: async (parent, args) => {
const projectDb = await getProjectDbClient({ projectId: parent.streamId })
const items = await getLastWebhookEventsFactory({ db: projectDb })({
webhookId: parent.id,
limit: args.limit
})
const totalCount = await getWebhookEventsCountFactory({ db: projectDb })({
webhookId: parent.id
})
return { items, totalCount }
}
},
Stream: {
webhooks: streamWebhooksResolver
},
Project: {
webhooks: streamWebhooksResolver
},
Mutation: {
webhookCreate: async (_parent, args, context) => {
const projectId = args.webhook.streamId
await authorizeResolver(
context.userId,
projectId,
Roles.Stream.Owner,
context.resourceAccessRules
)
const logger = context.log.child({
projectId,
streamId: projectId //legacy
})
const projectDb = await getProjectDbClient({ projectId })
const createWebhook = createWebhookFactory({
createWebhookConfig: createWebhookConfigFactory({ db: projectDb }),
countWebhooksByStreamId: countWebhooksByStreamIdFactory({ db: projectDb })
})
const id = await withOperationLogging(
async () =>
await createWebhook({
streamId: projectId,
url: args.webhook.url,
description: args.webhook.description,
secret: args.webhook.secret,
enabled: args.webhook.enabled !== false,
triggers: args.webhook.triggers
}),
{
logger,
operationName: 'webhookCreate',
operationDescription: 'Create a new webhook'
}
)
return id
},
webhookUpdate: async (_parent, args, context) => {
const projectId = args.webhook.streamId
const webhookId = args.webhook.id
await authorizeResolver(
context.userId,
projectId,
Roles.Stream.Owner,
context.resourceAccessRules
)
const logger = context.log.child({
projectId,
streamId: projectId, //legacy
webhookId
})
const projectDb = await getProjectDbClient({ projectId })
const wh = await getWebhookByIdFactory({ db: projectDb })({ id: args.webhook.id })
if (args.webhook.streamId !== wh?.streamId)
throw new ForbiddenError(
'The webhook id and stream id do not match. Please check your inputs.'
)
const updateWebhook = updateWebhookFactory({
updateWebhookConfig: updateWebhookConfigFactory({ db: projectDb })
})
const updated = await withOperationLogging(
async () =>
await updateWebhook({
id: args.webhook.id,
url: args.webhook.url,
description: args.webhook.description,
secret: args.webhook.secret,
enabled: args.webhook.enabled !== false,
triggers: args.webhook.triggers
}),
{
logger,
operationName: 'webhookUpdate',
operationDescription: 'Update an existing webhook'
}
)
return updated
},
webhookDelete: async (_parent, args, context) => {
const projectId = args.webhook.streamId
const webhookId = args.webhook.id
await authorizeResolver(
context.userId,
projectId,
Roles.Stream.Owner,
context.resourceAccessRules
)
const logger = context.log.child({
projectId,
streamId: projectId, //legacy
webhookId
})
const projectDb = await getProjectDbClient({ projectId })
const deleteWebhook = deleteWebhookFactory({
deleteWebhookConfig: deleteWebhookConfigFactory({ db: projectDb }),
getWebhookById: getWebhookByIdFactory({ db: projectDb })
})
return await withOperationLogging(async () => await deleteWebhook(args.webhook), {
logger,
operationName: 'webhookDelete',
operationDescription: 'Delete an existing webhook'
})
}
}
} as Resolvers