From c723335ebc33e32c04ea11e8f8f703934bc6deeb Mon Sep 17 00:00:00 2001 From: houssenedao Date: Thu, 23 Dec 2021 00:01:45 +0000 Subject: [PATCH] feat(): create exception and change dependances requirement --- lib/bootstrap/index.ts | 3 +- lib/bootstrap/webhook-channel.message.ts | 91 +++++++++++++++++++ lib/bootstrap/webhook.channel.ts | 65 +++++++++++-- lib/constants/index.ts | 1 + lib/constants/webhook-channel.constant.ts | 2 + lib/exceptions/index.ts | 1 + lib/exceptions/webhook-channel.exception.ts | 15 +++ lib/index.ts | 2 +- lib/interfaces/index.ts | 2 + .../webhook-channel-module.interface.ts | 57 ++++++++++++ lib/interfaces/webhook-channel.interface.ts | 15 +++ 11 files changed, 245 insertions(+), 9 deletions(-) create mode 100644 lib/bootstrap/webhook-channel.message.ts create mode 100644 lib/constants/index.ts create mode 100644 lib/constants/webhook-channel.constant.ts create mode 100644 lib/exceptions/index.ts create mode 100644 lib/exceptions/webhook-channel.exception.ts create mode 100644 lib/interfaces/index.ts create mode 100644 lib/interfaces/webhook-channel-module.interface.ts create mode 100644 lib/interfaces/webhook-channel.interface.ts diff --git a/lib/bootstrap/index.ts b/lib/bootstrap/index.ts index ee94847..053efe7 100644 --- a/lib/bootstrap/index.ts +++ b/lib/bootstrap/index.ts @@ -1,3 +1,2 @@ export * from './webhook.channel'; -export * from './webhook.interface'; -export * from './webhook.message'; +export * from './webhook-channel.message'; diff --git a/lib/bootstrap/webhook-channel.message.ts b/lib/bootstrap/webhook-channel.message.ts new file mode 100644 index 0000000..6033f77 --- /dev/null +++ b/lib/bootstrap/webhook-channel.message.ts @@ -0,0 +1,91 @@ +import { WebhookChannelException } from '../exceptions'; + +/** + * Webhook message + * @class WebhookChannelMessage + */ +export class WebhookChannelMessage { + /** + * @public + * @property {string} channelId + */ + private url: string; + + /** + * @public + * @property {any} header + */ + private header: any; + + /** + * @public + * @property {any} body + */ + private body: any; + + /** + * @constructor + * @param {string} body + */ + constructor(body: any) { + this.body = body; + } + + /** + * Get url. + */ + get getUrl() { + return this.url; + } + + /** + * Set the message url. + * @param {string} url + * @return this + */ + setUrl(url: string): WebhookChannelMessage { + if (!url) { + throw new WebhookChannelException('URL is not empty'); + } + + this.url = url; + + return this; + } + + /** + * Get header + */ + get getHeader() { + return this.header; + } + + /** + * Set the message header. + * @param {any} header + * @return this + */ + setHeader(header: any): WebhookChannelMessage { + this.header = header; + + return this; + } + + /** + * Get body + */ + get getBody() { + return this.body; + } + + /** + * Set the message body. + * @param {any} body + * @return this + */ + setBody(body: any): WebhookChannelMessage { + this.body = body; + + return this; + } +} diff --git a/lib/bootstrap/webhook.channel.ts b/lib/bootstrap/webhook.channel.ts index ed0ec2b..d5e9d25 100644 --- a/lib/bootstrap/webhook.channel.ts +++ b/lib/bootstrap/webhook.channel.ts @@ -1,16 +1,34 @@ -import { Injectable, InternalServerErrorException } from '@nestjs/common'; +import { Inject, Injectable, Optional } from '@nestjs/common'; import { HttpService } from '@nestjs/axios'; import { INestjsNotificationChannel } from '@sinuos/nestjs-notification'; import { AxiosResponse } from 'axios'; -import { IWebhookChannel } from './webhook.interface'; +import { IWebhookChannel, WebhookChannelModuleOptions } from '../interfaces'; +import { WebhookChannelException } from '../exceptions'; +import { WEBHOOK_CHANNEL_OPTIONS } from '../constants'; @Injectable() export class WebhookChannel implements INestjsNotificationChannel { + /** + * @readonly + * @private + */ + private readonly url: string; + /** * @constructor + * @param options * @param {HttpService} http */ - constructor(private readonly http: HttpService) {} + constructor( + private readonly http: HttpService, + @Optional() + @Inject(WEBHOOK_CHANNEL_OPTIONS) + options: WebhookChannelModuleOptions, + ) { + if (options?.url) { + this.url = options.url; + } + } /** * Send notify @@ -21,28 +39,63 @@ export class WebhookChannel implements INestjsNotificationChannel { public async send( notification: IWebhookChannel, ): Promise> { + // validator + this.validator(notification); + + // get message content const message = WebhookChannel.getData(notification); + // url + const url = message.getUrl; + + // make http request. const response = await this.http.request({ method: 'POST', - url: message.getUrl, + url, data: message.getBody, headers: message.getHeader, }); + // return response return response.toPromise(); } + /** + * Validator. + * @method + * @param {IWebhookChannel} notification + * @private + */ + private validator(notification: IWebhookChannel) { + const message = WebhookChannel.getData(notification); + + /** Account sid is empty */ + if (!this.url && !message.getUrl) { + throw new WebhookChannelException('URL is required'); + } + } + + /** + * Get data. + * @method + * @param {IWebhookChannel} notification + * @private + */ + private static getData(notification: IWebhookChannel) { + return WebhookChannel.getChannelData(notification); + } + /** * Get the data for the notification. * @param notification */ - private static getData(notification: IWebhookChannel) { + private static getChannelData(notification: IWebhookChannel) { if (typeof notification.toWebhook === 'function') { return notification.toWebhook(); } - throw new InternalServerErrorException( + // throw exception + throw new WebhookChannelException( 'Notification is missing toWebhook method.', ); } diff --git a/lib/constants/index.ts b/lib/constants/index.ts new file mode 100644 index 0000000..2d6efeb --- /dev/null +++ b/lib/constants/index.ts @@ -0,0 +1 @@ +export * from './webhook-channel.constant'; diff --git a/lib/constants/webhook-channel.constant.ts b/lib/constants/webhook-channel.constant.ts new file mode 100644 index 0000000..30a1c20 --- /dev/null +++ b/lib/constants/webhook-channel.constant.ts @@ -0,0 +1,2 @@ +export const WEBHOOK_CHANNEL_HTTP = 'WEBHOOK_CHANNEL_HTTP'; +export const WEBHOOK_CHANNEL_OPTIONS = 'WEBHOOK_CHANNEL_OPTIONS'; diff --git a/lib/exceptions/index.ts b/lib/exceptions/index.ts new file mode 100644 index 0000000..2a6dce4 --- /dev/null +++ b/lib/exceptions/index.ts @@ -0,0 +1 @@ +export * from './webhook-channel.exception'; diff --git a/lib/exceptions/webhook-channel.exception.ts b/lib/exceptions/webhook-channel.exception.ts new file mode 100644 index 0000000..f10641b --- /dev/null +++ b/lib/exceptions/webhook-channel.exception.ts @@ -0,0 +1,15 @@ +/** + * @class WebhookChannelException + * @extends Error + */ +export class WebhookChannelException extends Error { + /** + * @constructor + * @param message + */ + constructor(message: string) { + super(message); + + this.name = 'WebhookChannelException'; + } +} diff --git a/lib/index.ts b/lib/index.ts index cd3df21..9e4c415 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,3 +1,3 @@ export * from './bootstrap'; -export * from './webhook-channel.service'; +export * from './interfaces'; export * from './webhook-channel.module'; diff --git a/lib/interfaces/index.ts b/lib/interfaces/index.ts new file mode 100644 index 0000000..3d04229 --- /dev/null +++ b/lib/interfaces/index.ts @@ -0,0 +1,2 @@ +export * from './webhook-channel.interface'; +export * from './webhook-channel-module.interface'; diff --git a/lib/interfaces/webhook-channel-module.interface.ts b/lib/interfaces/webhook-channel-module.interface.ts new file mode 100644 index 0000000..262ce90 --- /dev/null +++ b/lib/interfaces/webhook-channel-module.interface.ts @@ -0,0 +1,57 @@ +import { ModuleMetadata, Provider, Type } from '@nestjs/common'; + +/** + * @interface WebhookChannelModuleOptionsFactory + * @property createWebhookChannelOptions() + */ +export interface WebhookChannelModuleOptionsFactory { + createWebhookChannelOptions(): + | Promise + | WebhookChannelModuleOptions; +} + +/** + * @interface WebhookChannelModuleAsyncOptions + * @extends {Pick} + * @property useExisting + * @property useClass + * @property useFactory + * @property inject + * @property extraProviders + */ +export interface WebhookChannelModuleAsyncOptions + extends Pick { + useExisting?: Type; + useClass?: Type; + useFactory?: ( + ...args: any[] + ) => Promise | WebhookChannelModuleOptions; + inject?: any[]; + extraProviders?: Provider[]; +} + +/** + * HTTP client. + * @interface WebhookHttpClient + */ +export interface WebhookHttpClient { + maxRedirects?: number; + timeout?: number; +} + +/** + * @interface WebhookChannelConfig + */ +export interface WebhookChannelConfig { + url?: string; +} + +/** + * @interface WebhookChannelModuleOptions + * @property {string} twilioAccountSid + * @property {string} twilioAuthToken + * @property {string} endpoint + */ +export interface WebhookChannelModuleOptions + extends WebhookHttpClient, + WebhookChannelConfig {} diff --git a/lib/interfaces/webhook-channel.interface.ts b/lib/interfaces/webhook-channel.interface.ts new file mode 100644 index 0000000..5c30b2c --- /dev/null +++ b/lib/interfaces/webhook-channel.interface.ts @@ -0,0 +1,15 @@ +import { NestJsNotification } from '@sinuos/nestjs-notification'; + +/** + * Webhook channel model + * @interface IWebhookChannel + * @extends NestJsNotification + */ +export interface IWebhookChannel extends NestJsNotification { + /** + * Get the Http representation of the notification. + * @property + * @returns {any} http payload data + */ + toWebhook?(): any; +}