RHeactorJS/template-mailer-aws-lambda

View on GitHub
operations/send.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict'

const Joi = require('joi')
const _merge = require('lodash/merge')
const _template = require('lodash/template')
const _forEach = require('lodash/forEach')
const Promise = require('bluebird')
const showdown = require('showdown')
const converter = new showdown.Converter({
  simplifiedAutoLink: true,
  strikethrough: true,
  tables: true
})

const formatContent = (data) => {
  if (!(typeof data === 'object')) {
    return data
  }
  if (data['@markdown']) {
    return {
      '@text': data['@markdown'],
      '@html': converter.makeHtml(data['@markdown'])
    }
  }
  _forEach(data, (value, key) => {
    data[key] = formatContent(value)
  })
  return data
}

const send = (ses, transportRepo, templateRepo, transport, template, body) => {
  const schema = Joi.object().keys({
    transport: Joi.string().required().regex(/^[a-z0-9]+(?!-+$)[a-z0-9-]*$/).lowercase(),
    template: Joi.string().required().regex(/^[a-z0-9]+(?!-+$)[a-z0-9-]*$/).lowercase(),
    to: Joi.string().email().required(),
    name: Joi.string().required().trim()
  })
  const data = _merge({}, {transport, template}, body)
  let v = Joi.validate(data, schema, {allowUnknown: true})
  if (v.error) {
    throw new Error('Validation failed: ' + v.error)
  }
  return Promise
    .join(
      transportRepo.fetch(v.value.transport),
      templateRepo.fetch(v.value.template)
    )
    .spread((transport, template) => {
      if (!transport || !template) {
        throw new Error('Transport or Template not found')
      }
      // Try to apply template
      let from, to, bcc, subject, html, text
      let templateData = v.value
      return Promise
        .try(() => {
          return Promise
            .try(() => {
              subject = _template(template.subject)(templateData)
              templateData.subject = subject
              templateData = formatContent(templateData)
              templateData._ = require('lodash')
              html = _template(template.html)(templateData)
              if (template.text) {
                text = _template(template.text)(templateData)
              }
            })
            .catch((err) => {
              console.error(err)
              throw new Error('Failed to render template: "' + v.value.template + '" with data "' + templateData + '"')
            })
        })
        .then(() => {
          from = '"' + transport.name + '" <' + transport.email + '>'
          to = '"' + v.value.name + '" <' + v.value.to + '>'
          bcc = transport.bcc
          const params = {
            Destination: {
              ToAddresses: [to]
            },
            Source: from,
            Message: {
              Body: {
                Html: {
                  Data: html,
                  Charset: 'UTF-8'
                }
              },
              Subject: {
                Data: subject,
                Charset: 'UTF-8'
              }
            }
          }
          if (bcc) {
            params.Destination.BccAddresses = [bcc]
          }
          if (text) {
            params.Message.Body.Text = {
              Data: text,
              Charset: 'UTF-8'
            }
          }
          return Promise.promisify(ses.sendEmail, {context: ses})(params)
        })
        .then(function () {
          console.log('Successfully send mail to "' + to + '" template: "' + v.value.template + '" via "' + v.value.transport + '"')
        })
        .catch((err) => {
          console.error('Failed to send mail to "' + to + '" template: "' + v.value.template + '" via "' + v.value.transport + '"', err)
          throw err
        })
    })
}

module.exports = {
  send
}