Adapt authoring tool UI documentation

v1.0.0-rc.4

adapt-authoring-mailer/lib/MailerModule.js

  1. import { AbstractModule } from 'adapt-authoring-core'
  2. import AbstractMailTransport from './AbstractMailTransport.js'
  3. import FilesystemTransport from './transports/FilesystemTransport.js'
  4. import SmtpTransport from './transports/SmtpTransport.js'
  5. /**
  6. * Mailer Module
  7. * @memberof mailer
  8. * @extends {AbstractModule}
  9. */
  10. class MailerModule extends AbstractModule {
  11. /** @override */
  12. async init () {
  13. /**
  14. * Reference to the isEnabled config value
  15. * @type {Boolean}
  16. */
  17. this.isEnabled = this.getConfig('isEnabled')
  18. /**
  19. * Reference to the connectionUrl config value
  20. * @type {String}
  21. */
  22. this.connectionUrl = this.getConfig('connectionUrl')
  23. /**
  24. * Registered mail transports
  25. * @type {Object}
  26. */
  27. this.transports = {}
  28. // note we still enable the API route if mailer is disabled to allow for testing
  29. const [auth, server] = await this.app.waitForModule('auth', 'server')
  30. const router = server.api.createChildRouter('mailer')
  31. router.addRoute({
  32. route: '/test',
  33. internal: true,
  34. handlers: { post: this.testEmailHandler.bind(this) },
  35. meta: {
  36. post: {
  37. summary: 'Send test email',
  38. responses: { 200: {} }
  39. }
  40. }
  41. })
  42. auth.unsecureRoute(`${router.path}/test`, 'post')
  43. if (this.isEnabled) {
  44. // add the standard transport
  45. this.registerTransport(FilesystemTransport)
  46. this.registerTransport(SmtpTransport)
  47. this.app.onReady().then(() => this.initTransports())
  48. }
  49. }
  50. registerTransport (TransportClass) {
  51. let t
  52. try {
  53. t = new TransportClass()
  54. this.transports[t.name] = t
  55. } catch (e) {
  56. this.log('error', `Failed to create transport, ${e}`)
  57. }
  58. if (!(t instanceof AbstractMailTransport)) {
  59. this.log('error', 'Failed to create transport, not an instance of AbstractMailTransport')
  60. }
  61. if (!t.name) {
  62. this.log('error', 'Failed to create transport, does not define a name')
  63. }
  64. }
  65. getTransport () {
  66. const transportName = this.getConfig('transport')
  67. if (!this.transports[transportName]) {
  68. throw new Error(`No transport with name ${transportName}`)
  69. }
  70. return this.transports[transportName]
  71. }
  72. async initTransports () {
  73. const transport = this.getTransport()
  74. try {
  75. await transport.test()
  76. this.log('info', `${transport.name} connection verified successfully`)
  77. } catch (e) {
  78. this.log('warn', `${transport.name} connection test failed, ${e}`)
  79. }
  80. }
  81. /**
  82. * Sends an email
  83. * @param {MailData} data The message data
  84. * @return {Promise}
  85. */
  86. async send (data, options = {}) {
  87. if (!this.isEnabled) {
  88. if (options.strict) throw this.app.errors.MAIL_NOT_ENABLED
  89. else return this.log('warn', 'could not send email, SMTP is not enabled')
  90. }
  91. if (!data.from) {
  92. data.from = this.getConfig('defaultSenderAddress')
  93. }
  94. try {
  95. const jsonschema = await this.app.waitForModule('jsonschema')
  96. const schema = await jsonschema.getSchema('maildata')
  97. await schema.validate(data)
  98. await this.getTransport().send(data)
  99. this.log('info', 'email sent successfully')
  100. } catch (e) {
  101. throw this.app.errors.MAIL_SEND_FAILED.setData({ email: data.to, error: e })
  102. }
  103. }
  104. /**
  105. * Sends a test email. Can only be called from localhost
  106. * @param {external:ExpressRequest} req The client request object
  107. * @param {external:ExpressResponse} res The server response object
  108. * @param {Function} next The callback function
  109. */
  110. async testEmailHandler (req, res, next) {
  111. if (!this.isEnabled) {
  112. throw this.app.errors.MAIL_NOT_ENABLED
  113. }
  114. const appUrl = (await this.app.waitForModule('server')).getConfig('url')
  115. try {
  116. await this.send({
  117. to: req.body.email,
  118. subject: 'Adapt authoring tool: email test',
  119. text: `Hello world!\n\nThis is a test email from ${appUrl}.\n\nRegards,\nTeam Adapt.`
  120. }, { strict: true })
  121. res.status(200).end()
  122. } catch (e) {
  123. return next(e)
  124. }
  125. }
  126. }
  127. export default MailerModule