dev-mailbox.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { LanguageCode } from '@vendure/common/lib/generated-types';
  2. import { Channel, RequestContext } from '@vendure/core';
  3. import express from 'express';
  4. import fs from 'fs-extra';
  5. import http from 'http';
  6. import path from 'path';
  7. import { EmailEventHandler } from './event-handler';
  8. import { EmailPluginDevModeOptions, EventWithContext } from './types';
  9. /**
  10. * An email inbox application that serves the contents of the dev mode `outputPath` directory.
  11. */
  12. export class DevMailbox {
  13. private handleMockEventFn: (
  14. handler: EmailEventHandler<string, any>,
  15. event: EventWithContext,
  16. ) => void | undefined;
  17. serve(options: EmailPluginDevModeOptions) {
  18. const { outputPath, handlers } = options;
  19. const server = express.Router();
  20. server.get('/', (req, res) => {
  21. res.sendFile(path.join(__dirname, '../../dev-mailbox.html'));
  22. });
  23. server.get('/list', async (req, res) => {
  24. const list = await fs.readdir(outputPath);
  25. const contents = await this.getEmailList(outputPath);
  26. res.send(contents);
  27. });
  28. server.get('/types', async (req, res) => {
  29. res.send(handlers.map(h => h.type));
  30. });
  31. server.get('/generate/:type/:languageCode', async (req, res) => {
  32. const { type, languageCode } = req.params;
  33. if (this.handleMockEventFn) {
  34. const handler = handlers.find(h => h.type === type);
  35. if (!handler || !handler.mockEvent) {
  36. res.statusCode = 404;
  37. res.send({ success: false, error: `No mock event registered for type "${type}"` });
  38. return;
  39. }
  40. try {
  41. await this.handleMockEventFn(handler, {
  42. ...handler.mockEvent,
  43. ctx: this.createRequestContext(languageCode as LanguageCode),
  44. });
  45. res.send({ success: true });
  46. } catch (e) {
  47. res.statusCode = 500;
  48. res.send({ success: false, error: e.message });
  49. }
  50. return;
  51. } else {
  52. res.send({ success: false, error: `Mock email generation not set up.` });
  53. }
  54. });
  55. server.get('/item/:id', async (req, res) => {
  56. const fileName = req.params.id;
  57. const content = await this.getEmail(outputPath, fileName);
  58. res.send(content);
  59. });
  60. return server;
  61. }
  62. handleMockEvent(handler: (handler: EmailEventHandler<string, any>, event: EventWithContext) => void) {
  63. this.handleMockEventFn = handler;
  64. }
  65. private async getEmailList(outputPath: string) {
  66. const list = await fs.readdir(outputPath);
  67. const contents: any[] = [];
  68. for (const fileName of list) {
  69. const json = await fs.readFile(path.join(outputPath, fileName), 'utf-8');
  70. const content = JSON.parse(json);
  71. contents.push({
  72. fileName,
  73. date: content.date,
  74. subject: content.subject,
  75. recipient: content.recipient,
  76. });
  77. }
  78. contents.sort((a, b) => {
  79. return +new Date(b.date) - +new Date(a.date);
  80. });
  81. return contents;
  82. }
  83. private async getEmail(outputPath: string, fileName: string) {
  84. const safeSuffix = path.normalize(fileName).replace(/^(\.\.(\/|\\|$))+/, '');
  85. const safeFilePath = path.join(outputPath, safeSuffix);
  86. const json = await fs.readFile(safeFilePath, 'utf-8');
  87. const content = JSON.parse(json);
  88. return content;
  89. }
  90. private createRequestContext(languageCode: LanguageCode): RequestContext {
  91. return new RequestContext({
  92. languageCode,
  93. apiType: 'admin',
  94. session: {} as any,
  95. isAuthorized: false,
  96. authorizedAsOwnerOnly: true,
  97. channel: new Channel(),
  98. });
  99. }
  100. }