From 407d232aff37f831aca55b0760bcdcaecf40cde2 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Tue, 16 Apr 2019 09:38:56 +0200 Subject: [PATCH] feat(email-plugin): Introduce globalTemplateVars option --- packages/email-plugin/src/event-listener.ts | 42 +++++++++++++----- packages/email-plugin/src/plugin.spec.ts | 49 +++++++++++++++++++-- packages/email-plugin/src/plugin.ts | 2 +- packages/email-plugin/src/types.ts | 7 +++ 4 files changed, 85 insertions(+), 15 deletions(-) diff --git a/packages/email-plugin/src/event-listener.ts b/packages/email-plugin/src/event-listener.ts index a73cd3c16c..d46f6e5220 100644 --- a/packages/email-plugin/src/event-listener.ts +++ b/packages/email-plugin/src/event-listener.ts @@ -37,6 +37,11 @@ export interface EmailTemplateConfig { subject: string; } +export type SetTemplateVarsFn = ( + event: Event, + globals: { [key: string]: any }, +) => { [key: string]: any }; + /** * @description * An EmailEventListener is used to listen for events and set up a {@link EmailEventHandler} which @@ -100,7 +105,7 @@ export class EmailEventListener { */ export class EmailEventHandler { private setRecipientFn: (event: Event) => string; - private setTemplateVarsFn: (event: Event) => { [key: string]: any; }; + private setTemplateVarsFn: SetTemplateVarsFn; private filterFns: Array<(event: Event) => boolean> = []; private configurations: EmailTemplateConfig[] = []; private defaultSubject: string; @@ -140,7 +145,7 @@ export class EmailEventHandler { [key: string]: any; }): EmailEventHandler { + setTemplateVars(templateVarsFn: SetTemplateVarsFn): EmailEventHandler { this.setTemplateVarsFn = templateVarsFn; return this; } @@ -169,23 +174,30 @@ export class EmailEventHandler { - return (c.channelCode === channelCode || c.channelCode === 'default') && c.languageCode === languageCode; + return ( + (c.channelCode === channelCode || c.channelCode === 'default') && + c.languageCode === languageCode + ); }); if (exactMatch) { return exactMatch; } - const channelMatch = this.configurations.find(c => c.channelCode === channelCode && c.languageCode === 'default'); + const channelMatch = this.configurations.find( + c => c.channelCode === channelCode && c.languageCode === 'default', + ); if (channelMatch) { return channelMatch; } diff --git a/packages/email-plugin/src/plugin.spec.ts b/packages/email-plugin/src/plugin.spec.ts index 3cd7d0f273..caee9d1388 100644 --- a/packages/email-plugin/src/plugin.spec.ts +++ b/packages/email-plugin/src/plugin.spec.ts @@ -7,22 +7,24 @@ import path from 'path'; import { orderConfirmationHandler } from './default-email-handlers'; import { EmailEventHandler, EmailEventListener } from './event-listener'; import { EmailPlugin } from './plugin'; +import { EmailPluginOptions } from './types'; describe('EmailPlugin', () => { let plugin: EmailPlugin; let eventBus: EventBus; let onSend: jest.Mock; - async function initPluginWithHandlers(handlers: Array>, templatePath?: string) { + async function initPluginWithHandlers(handlers: Array>, options?: Partial) { eventBus = new EventBus(); onSend = jest.fn(); plugin = new EmailPlugin({ - templatePath: templatePath || path.join(__dirname, '../test-templates'), + templatePath: path.join(__dirname, '../test-templates'), transport: { type: 'testing', onSend, }, handlers, + ...options, }); const inject = (token: any): any => { @@ -114,6 +116,47 @@ describe('EmailPlugin', () => { await pause(); expect(onSend.mock.calls[0][0].body).toContain('this is the test var'); }); + + it('interpolates globalTemplateVars', async () => { + const handler = new EmailEventListener('test') + .on(MockEvent) + .setRecipient(() => 'test@test.com') + .setSubject('Hello {{ globalVar }}'); + + await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } }); + + eventBus.publish(new MockEvent(ctx, true)); + await pause(); + expect(onSend.mock.calls[0][0].subject).toBe('Hello baz'); + }); + + it('globalTemplateVars available in setTemplateVars method', async () => { + const handler = new EmailEventListener('test') + .on(MockEvent) + .setRecipient(() => 'test@test.com') + .setSubject('Hello {{ testVar }}') + .setTemplateVars((event, globals) => ({ testVar: globals.globalVar + ' quux' })); + + await initPluginWithHandlers([handler], { globalTemplateVars: { globalVar: 'baz' } }); + + eventBus.publish(new MockEvent(ctx, true)); + await pause(); + expect(onSend.mock.calls[0][0].subject).toBe('Hello baz quux'); + }); + + it('setTemplateVars overrides globals', async () => { + const handler = new EmailEventListener('test') + .on(MockEvent) + .setRecipient(() => 'test@test.com') + .setSubject('Hello {{ name }}') + .setTemplateVars((event, globals) => ({ name: 'quux' })); + + await initPluginWithHandlers([handler], { globalTemplateVars: { name: 'baz' } }); + + eventBus.publish(new MockEvent(ctx, true)); + await pause(); + expect(onSend.mock.calls[0][0].subject).toBe('Hello quux'); + }); }); describe('multiple configs', () => { @@ -152,7 +195,7 @@ describe('EmailPlugin', () => { describe('orderConfirmationHandler', () => { beforeEach(async () => { - await initPluginWithHandlers([orderConfirmationHandler], path.join(__dirname, '../templates')); + await initPluginWithHandlers([orderConfirmationHandler], { templatePath: path.join(__dirname, '../templates') }); }); const ctx = { diff --git a/packages/email-plugin/src/plugin.ts b/packages/email-plugin/src/plugin.ts index 9ea0709a70..9dd3b5b3fa 100644 --- a/packages/email-plugin/src/plugin.ts +++ b/packages/email-plugin/src/plugin.ts @@ -191,7 +191,7 @@ export class EmailPlugin implements VendurePlugin { private async handleEvent(handler: EmailEventHandler, event: EventWithContext) { const { type } = handler; - const result = handler.handle(event); + const result = handler.handle(event, this.options.globalTemplateVars); if (!result) { return; } diff --git a/packages/email-plugin/src/types.ts b/packages/email-plugin/src/types.ts index caedec590d..0ca0ca383f 100644 --- a/packages/email-plugin/src/types.ts +++ b/packages/email-plugin/src/types.ts @@ -40,6 +40,13 @@ export interface EmailPluginOptions { * emails, and how those emails are generated. */ handlers: EmailEventHandler[]; + /** + * @description + * An object containing variables which are made available to all templates. For example, + * the storefront URL could be defined here and then used in the "email address verification" + * email. + */ + globalTemplateVars?: { [key: string]: any; }; } /**