From 6d0ce30a445bcf548ceadceebf71f78286af3df8 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 25 May 2022 22:20:13 +0800 Subject: [PATCH] Add setWebhook resolver --- packages/api/src/entity/webhook.ts | 12 +-- packages/api/src/generated/graphql.ts | 2 + packages/api/src/generated/schema.graphql | 2 + .../api/src/resolvers/function_resolvers.ts | 4 + packages/api/src/resolvers/webhooks/index.ts | 79 +++++++++++++++++++ packages/api/src/schema.ts | 2 + 6 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 packages/api/src/resolvers/webhooks/index.ts diff --git a/packages/api/src/entity/webhook.ts b/packages/api/src/entity/webhook.ts index 98d6efbf2..0af802e60 100644 --- a/packages/api/src/entity/webhook.ts +++ b/packages/api/src/entity/webhook.ts @@ -21,21 +21,21 @@ export class Webhook { @Column('text') url!: string - @Column('text[]') + @Column('text', { array: true }) eventTypes!: string[] @Column('text', { default: 'POST' }) - method?: string + method!: string @Column('text', { default: 'application/json' }) - contentType?: string + contentType!: string @Column('boolean', { default: true }) - enabled?: boolean + enabled!: boolean @CreateDateColumn({ default: () => 'CURRENT_TIMESTAMP' }) - createdAt?: Date + createdAt!: Date @UpdateDateColumn({ default: () => 'CURRENT_TIMESTAMP' }) - updatedAt?: Date + updatedAt!: Date } diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 615ae0e64..592927875 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1625,6 +1625,7 @@ export type SetWebhookError = { export enum SetWebhookErrorCode { AlreadyExists = 'ALREADY_EXISTS', BadRequest = 'BAD_REQUEST', + NotFound = 'NOT_FOUND', Unauthorized = 'UNAUTHORIZED' } @@ -1632,6 +1633,7 @@ export type SetWebhookInput = { contentType?: InputMaybe; enabled?: InputMaybe; eventTypes: Array; + id?: InputMaybe; method?: InputMaybe; url: Scalars['String']; }; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index de6019e8b..b0d25e7e8 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1193,6 +1193,7 @@ type SetWebhookError { enum SetWebhookErrorCode { ALREADY_EXISTS BAD_REQUEST + NOT_FOUND UNAUTHORIZED } @@ -1200,6 +1201,7 @@ input SetWebhookInput { contentType: String enabled: Boolean eventTypes: [WebhookEvent!]! + id: ID method: String url: String! } diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 67baa03f9..7c50351c5 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -71,6 +71,7 @@ import { updateHighlightResolver, updateLabelResolver, updateLinkShareInfoResolver, + updatePageResolver, updateReminderResolver, updateSharedCommentResolver, updateUserProfileResolver, @@ -87,6 +88,7 @@ import { } from '../utils/uploads' import { getPageByParam } from '../elastic/pages' import { generateApiKeyResolver } from './api_key' +import { setWebhookResolver } from './webhooks' /* eslint-disable @typescript-eslint/naming-convention */ type ResultResolveType = { @@ -151,6 +153,7 @@ export const functionResolvers = { updatePage: updatePageResolver, subscribe: subscribeResolver, addPopularRead: addPopularReadResolver, + setWebhook: setWebhookResolver, }, Query: { me: getMeUserResolver, @@ -563,4 +566,5 @@ export const functionResolvers = { ...resultResolveTypeResolver('UpdatePage'), ...resultResolveTypeResolver('Subscribe'), ...resultResolveTypeResolver('AddPopularRead'), + ...resultResolveTypeResolver('SetWebhook'), } diff --git a/packages/api/src/resolvers/webhooks/index.ts b/packages/api/src/resolvers/webhooks/index.ts new file mode 100644 index 000000000..00eb1802d --- /dev/null +++ b/packages/api/src/resolvers/webhooks/index.ts @@ -0,0 +1,79 @@ +import { authorized } from '../../utils/helpers' +import { + MutationSetWebhookArgs, + SetWebhookError, + SetWebhookErrorCode, + SetWebhookSuccess, + WebhookEvent, +} from '../../generated/graphql' +import { getRepository } from '../../entity/utils' +import { User } from '../../entity/user' +import { Webhook } from '../../entity/webhook' + +export const setWebhookResolver = authorized< + SetWebhookSuccess, + SetWebhookError, + MutationSetWebhookArgs +>(async (_, { input }, { claims: { uid }, log }) => { + log.info('setWebhookResolver') + + try { + const user = await getRepository(User).findOneBy({ id: uid }) + if (!user) { + return { + errorCodes: [SetWebhookErrorCode.Unauthorized], + } + } + + const webhookToAdd = { + url: input.url, + eventTypes: input.eventTypes as string[], + method: input.method || 'POST', + contentType: input.contentType || 'application/json', + enabled: input.enabled === null ? true : input.enabled, + } + + let webhook: Webhook | null + + if (input.id) { + // Update + webhook = await getRepository(Webhook).findOneBy({ id: input.id }) + if (!webhook) { + return { + errorCodes: [SetWebhookErrorCode.NotFound], + } + } + if (webhook.user.id !== uid) { + return { + errorCodes: [SetWebhookErrorCode.Unauthorized], + } + } + await getRepository(Webhook).update(webhook.id, webhookToAdd) + } else { + // Create + webhook = await getRepository(Webhook).save({ + user, + ...webhookToAdd, + }) + + if (!webhook) { + return { + errorCodes: [SetWebhookErrorCode.AlreadyExists], + } + } + } + + return { + webhook: { + ...webhook, + eventTypes: webhook.eventTypes as WebhookEvent[], + }, + } + } catch (error) { + log.error(error) + + return { + errorCodes: [SetWebhookErrorCode.BadRequest], + } + } +}) diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index ece4cc8ad..ab21dc2fe 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1572,6 +1572,7 @@ const schema = gql` } input SetWebhookInput { + id: ID url: String! eventTypes: [WebhookEvent!]! contentType: String @@ -1616,6 +1617,7 @@ const schema = gql` UNAUTHORIZED BAD_REQUEST ALREADY_EXISTS + NOT_FOUND } # Mutations