dev-mailbox.ts 4.0 KB

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