From 53ebb4a81601371ca314ae1d7042da2e9487bb9d Mon Sep 17 00:00:00 2001 From: Anand Chowdhary Date: Sat, 7 Nov 2020 16:33:32 +0530 Subject: [PATCH] :sparkles: Trigger webhooks on audit log --- src/interceptors/audit-log.interceptor.ts | 3 ++ src/modules/webhooks/webhooks.service.ts | 57 +++++++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/interceptors/audit-log.interceptor.ts b/src/interceptors/audit-log.interceptor.ts index e9997cd74..c1ddb321d 100644 --- a/src/interceptors/audit-log.interceptor.ts +++ b/src/interceptors/audit-log.interceptor.ts @@ -13,6 +13,7 @@ import { STAART_AUDIT_LOG_DATA } from 'src/modules/audit-logs/audit-log.constant import { UserRequest } from 'src/modules/auth/auth.interface'; import { GeolocationService } from 'src/modules/geolocation/geolocation.service'; import { PrismaService } from 'src/modules/prisma/prisma.service'; +import { WebhooksService } from 'src/modules/webhooks/webhooks.service'; import { UAParser } from 'ua-parser-js'; @Injectable() @@ -23,6 +24,7 @@ export class AuditLogger implements NestInterceptor { private readonly reflector: Reflector, private prisma: PrismaService, private geolocationService: GeolocationService, + private webhooksService: WebhooksService, ) {} intercept(context: ExecutionContext, next: CallHandler): Observable { @@ -64,6 +66,7 @@ export class AuditLogger implements NestInterceptor { }`.trim() || undefined, }, }); + this.webhooksService.triggerWebhook(groupId, event); } } })() diff --git a/src/modules/webhooks/webhooks.service.ts b/src/modules/webhooks/webhooks.service.ts index 08964e4f7..53aae1b57 100644 --- a/src/modules/webhooks/webhooks.service.ts +++ b/src/modules/webhooks/webhooks.service.ts @@ -2,6 +2,7 @@ import { HttpException, HttpStatus, Injectable, + Logger, UnauthorizedException, } from '@nestjs/common'; import { @@ -12,16 +13,18 @@ import { webhooksWhereInput, webhooksWhereUniqueInput, } from '@prisma/client'; +import got from 'got'; +import PQueue from 'p-queue'; +import pRetry from 'p-retry'; import { Expose } from '../prisma/prisma.interface'; import { PrismaService } from '../prisma/prisma.service'; -import { StripeService } from '../stripe/stripe.service'; @Injectable() export class WebhooksService { - constructor( - private prisma: PrismaService, - private stripeService: StripeService, - ) {} + private readonly logger = new Logger(WebhooksService.name); + private queue = new PQueue({ concurrency: 1 }); + + constructor(private prisma: PrismaService) {} async createWebhook( groupId: number, @@ -116,4 +119,48 @@ export class WebhooksService { const scopes: Record = {}; return scopes; } + + triggerWebhook(groupId: number, event: string) { + this.prisma.webhooks + .findMany({ + where: { group: { id: groupId }, isActive: true, event }, + }) + .then((webhooks) => { + webhooks.forEach((webhook) => + this.queue + .add(() => + pRetry(() => this.callWebhook(webhook, event), { + retries: 3, + onFailedAttempt: (error) => { + this.logger.error( + `Triggering webhoook failed, retrying (${error.retriesLeft} attempts left)`, + error.name, + ); + if (error.retriesLeft === 0) + this.prisma.webhooks + .update({ + where: { id: webhook.id }, + data: { isActive: false }, + }) + .then(() => {}) + .catch(() => {}); + }, + }), + ) + .then(() => {}) + .catch(() => {}), + ); + }) + .catch((error) => this.logger.error('Unable to get webhooks', error)); + } + + private async callWebhook(webhook: webhooks, event: string) { + if (webhook.contentType === 'application/json') + await got(webhook.url, { method: 'POST', json: { event } }); + else await got(webhook.url, { method: 'POST', body: event }); + await this.prisma.webhooks.update({ + where: { id: webhook.id }, + data: { lastFiredAt: new Date() }, + }); + } }