import _get from 'lodash.get' ; import { EventEmitter } from 'events' ; import { getHandlebarsVariables } from '../content/content.engine' ; import { EmailHandler } from '../handler/email.handler' ; import { SmsHandler } from '../handler/sms.handler' ; import { INotifireConfig } from '../notifire.interface' ; import { ProviderStore } from '../provider/provider.store' ; import { ChannelTypeEnum , IMessage , ITemplate , ITriggerPayload , } from '../template/template.interface' ; import { TemplateStore } from '../template/template.store' ; import { ThemeStore } from '../theme/theme.store' ; import { DirectHandler } from '../handler/direct.handler' ; export class TriggerEngine { constructor ( private templateStore , private providerStore , private themeStore , private config , private eventEmitter ) { } async trigger ( eventId , data ) { const template = await this . templateStore . getTemplateById ( eventId ) ; if ( ! template ) { throw new Error ( `Template on event: ${ eventId } was not found in the template store` ) ; } const activeMessages = await this . templateStore . getActiveMessages ( template , data ) ; for ( const message of activeMessages ) { await this . processTemplateMessage ( template , message , data ) ; } } async processTemplateMessage ( template , message , data ) { const provider = await this . providerStore . getProviderByChannel ( message . channel ) ; if ( ! provider ) { throw new Error ( `Provider for ${ message . channel } channel was not found` ) ; } const missingVariables = this . getMissingVariables ( message , data ) ; if ( missingVariables . length && this . config . variableProtection ) { throw new Error ( `Missing variables passed. ${ missingVariables . toString ( ) }` ) ; } await this . validate ( message , data ) ; this . eventEmitter . emit ( 'pre:send' , { id : template . id , channel : message . channel , message , triggerPayload : data , } ) ; let theme = await this . themeStore . getDefaultTheme ( ) ; if ( data . $theme_id ) { theme = await this . themeStore . getThemeById ( data ?. $theme_id ) ; } else if ( template . themeId ) { theme = await this . themeStore . getThemeById ( template . themeId ) ; } if ( provider . channelType === ChannelTypeEnum . EMAIL ) { const emailHandler = new EmailHandler ( message , provider , theme ) ; await emailHandler . send ( data ) ; } else if ( provider . channelType === ChannelTypeEnum . SMS ) { const smsHandler = new SmsHandler ( message , provider ) ; await smsHandler . send ( data ) ; } else if ( provider . channelType === ChannelTypeEnum . DIRECT ) { const directHandler = new DirectHandler ( message , provider ) ; await directHandler . send ( data ) ; } this . eventEmitter . emit ( 'post:send' , { id : template . id , channel : message . channel , message , triggerPayload : data , } ) ; } private getMissingVariables ( message , data ) { const variables = this . extractMessageVariables ( message , data ) ; const missingVariables = [ ] ; for ( const variable of variables ) { if ( ! _get ( data , variable ) ) { missingVariables . push ( variable ) ; } } return missingVariables ; } private extractMessageVariables ( message , data ) { const mergedResults = [ ] ; if ( message . template && typeof message . template === 'string' ) { mergedResults . push ( ... getHandlebarsVariables ( message . template ) ) ; } if ( message . subject ) { if ( typeof message . subject === 'string' ) { mergedResults . push ( ... getHandlebarsVariables ( message . subject ) ) ; } else if ( typeof message . subject === 'function' ) { mergedResults . push ( ... getHandlebarsVariables ( message . subject ( data ) ) ) ; } else { throw new Error ( "Subject must be either of 'string' or 'function' type" ) ; } } const deduplicatedResults = [ ... new Set ( mergedResults ) ] ; return deduplicatedResults ; } private async validate ( message , data ) { if ( ! message . validator ) { return ; } const valid = await message . validator ?. validate ( data ) ; if ( ! valid ) { throw new Error ( `Payload for ${ message . channel } is invalid` ) ; } } }