refactor(nodemailer): Refactored koa nodemailer

This commit is contained in:
Daniel Gonzalez
2021-03-30 20:36:33 -04:00
parent c7c27ca746
commit a98f64fc70
3 changed files with 338 additions and 17952 deletions
+59 -17870
View File
File diff suppressed because it is too large Load Diff
+65 -82
View File
@@ -34,15 +34,6 @@ class NodeMailer {
return transporter return transporter
} }
// Validate email
async validateEmail (email) {
// eslint-disable-next-line no-useless-escape
if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
return true
}
return false
}
// Handles the sending of data via email. // Handles the sending of data via email.
async sendEmail (data) { async sendEmail (data) {
try { try {
@@ -50,10 +41,6 @@ class NodeMailer {
if (!data.email || typeof data.email !== 'string') { if (!data.email || typeof data.email !== 'string') {
throw new Error("Property 'email' must be a string!") throw new Error("Property 'email' must be a string!")
} }
const isEmail = await _this.validateEmail(data.email)
if (!isEmail) {
throw new Error("Property 'email' must be email format!")
}
if (!data.to || !Array.isArray(data.to)) { if (!data.to || !Array.isArray(data.to)) {
throw new Error("Property 'to' must be a array!") throw new Error("Property 'to' must be a array!")
@@ -62,66 +49,28 @@ class NodeMailer {
await _this.validateEmailArray(data.to) await _this.validateEmailArray(data.to)
if (!data.formMessage || typeof data.formMessage !== 'string') { if (!data.formMessage || typeof data.formMessage !== 'string') {
throw new Error("Property 'message' must be a string!") throw new Error("Property 'formMessage' must be a string!")
} }
if (!data.subject || typeof data.subject !== 'string') { if (!data.subject || typeof data.subject !== 'string') {
throw new Error("Property 'subject' must be a string!") throw new Error("Property 'subject' must be a string!")
} }
if (!data.payloadTitle || typeof data.payloadTitle !== 'string') { // Use the provided html or use a default html generated from the input data
throw new Error("Property 'payloadTitle' must be a string!")
const html = data.htmlData || _this.getHtmlFromObject(data)
const sendObj = {
// from: `${data.email}`, // sender address
from: data.email,
to: data.to, // list of receivers
// subject: `Pearson ${subject}`, // Subject line
subject: data.subject,
// html: '<b>This is a test email</b>' // html body
html
} }
const msg = data.formMessage.replace(/(\r\n|\n|\r)/g, '<br />')
const now = new Date()
const subject = data.subject
const to = data.to
// const emailUser = data.email // email from the user who initiated the sharing email
const payload = data.payloadTitle
const bodyJson = data
delete bodyJson.to
delete bodyJson.subject
delete bodyJson.formMessage
// Prototyping email output.
bodyJson.email = 'noreply@launchpadip.net'
delete bodyJson.email
delete bodyJson.emailList
delete bodyJson.payloadTitle
bodyJson.message = msg
// Html body
let htmlData = ''
// maps the object and converts it into html format
Object.keys(bodyJson).forEach(function (key) {
htmlData += `${key}: ${bodyJson[key]}<br/>`
})
// This paragraph just be added to the message for
// emails that are not password reset ones
const paragraphTag = 'This is a test email'
const htmlMsg = `<h3>${subject}:</h3>
${payload === 'Email reset' ? '' : paragraphTag}
<p>
time: ${now.toLocaleString()}<br/>
${htmlData}
</p>`
// send mail with defined transport object // send mail with defined transport object
const info = await _this.transporter.sendMail({ const info = await _this.transporter.sendMail(sendObj)
// from: `${data.email}`, // sender address
from: 'noreply@launchpadip.net',
to: `${to}`, // list of receivers
// subject: `Pearson ${subject}`, // Subject line
subject: subject,
// html: '<b>This is a test email</b>' // html body
html: htmlMsg
})
console.log('Message sent: %s', info.messageId) console.log('Message sent: %s', info.messageId)
return info return info
} catch (err) { } catch (err) {
@@ -140,30 +89,64 @@ class NodeMailer {
throw new Error("Property 'emailList' cant be empty!") throw new Error("Property 'emailList' cant be empty!")
} }
// Iterates the array and validates each email format
const isValid = await new Promise(resolve => {
emailList.map(async (value, i) => {
const isEmail = await _this.validateEmail(value)
if (!isEmail) {
resolve(false)
}
if (i >= emailList.length - 1) {
resolve(true)
}
})
})
if (!isValid) {
throw new Error('Array must contain emails format!')
}
return true return true
} catch (err) { } catch (err) {
wlogger.error('Error in lib/nodemailer.js/validateEmailArray()') wlogger.error('Error in lib/nodemailer.js/validateEmailArray()')
throw err throw err
} }
} }
// get the email html from object
getHtmlFromObject (objectData) {
try {
if (!objectData || typeof objectData !== 'object') {
throw new Error("Property 'objectData' must be a object!")
}
if (!objectData.subject) {
throw new Error("Property 'subject' must be a string!")
}
if (!objectData.formMessage) {
throw new Error("Property 'formMessage' must be a string!")
}
const obj = {}
Object.assign(obj, objectData)
// neccesary data
const msg = obj.formMessage.replace(/(\r\n|\n|\r)/g, '<br />')
const now = new Date()
const subject = obj.subject
// Delete unneccesary data if it exist
delete obj.to
delete obj.subject
delete obj.from
delete obj.emailList
delete obj.formMessage
const bodyJson = obj
bodyJson.message = msg
// Html body
let htmlBody = ''
// maps the object and converts it into html format
Object.keys(bodyJson).forEach(function (key) {
htmlBody += `${key}: ${bodyJson[key]}<br/>`
})
const defaultHtmlData = `<h3>${subject}:</h3>
<p>
time: ${now.toLocaleString()}<br/>
${htmlBody}
</p>`
return defaultHtmlData
} catch (error) {
wlogger.error('Error in lib/nodemailer.js/getHtmlFromObject()')
throw error
}
}
} }
module.exports = NodeMailer module.exports = NodeMailer
@@ -0,0 +1,214 @@
const assert = require('chai').assert
const NodeMailer = require('../../../src/lib/nodemailer')
const sinon = require('sinon')
const util = require('util')
util.inspect.defaultOptions = { depth: 1 }
let sandbox
let uut
describe('NodeMailer', () => {
beforeEach(() => {
uut = new NodeMailer()
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe('sendEmail()', () => {
it('should throw error if email property is not provided', async () => {
try {
const data = {
formMessage: 'test msg',
name: 'test name',
subject: 'test subject',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'email\' must be a string!')
}
})
it('should throw error if formMessage property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
name: 'test name',
subject: 'test subject',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'formMessage\' must be a string!')
}
})
it('should throw error if <to> property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
name: 'test name',
subject: 'test subject'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'to\' must be a array!')
}
})
it('should throw error if <to> is wrong type', async () => {
try {
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
subject: 'test subject',
to: 'test'
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, "Property 'to' must be a array!")
}
})
it('should throw error if subject Property is not provided', async () => {
try {
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
to: ['test2@email.com']
}
await uut.sendEmail(data)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'subject\' must be a string!')
}
})
it('should send email with default html data', async () => {
try {
sandbox.stub(uut.transporter, 'sendMail').resolves({ messageId: 'messageId' })
const data = {
email: 'test@email.com',
formMessage: 'test msg',
to: ['test2@email.com'],
subject: 'test subject'
}
const info = await uut.sendEmail(data)
assert.isObject(info)
assert.isString(info.messageId)
} catch (err) {
assert(false, 'Unexpected result')
}
})
it('should send email if htmlData is provided', async () => {
try {
sandbox.stub(uut.transporter, 'sendMail').resolves({ messageId: 'messageId' })
const data = {
email: 'test@email.com',
formMessage: 'test msg',
name: 'test name',
to: ['test2@email.com'],
subject: 'test subject',
htmlData: '<p> Unit test </p>'
}
const info = await uut.sendEmail(data)
assert.isObject(info)
assert.isString(info.messageId)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
describe('validateEmailArray()', () => {
it('should throw error if email list is not provided ', async () => {
try {
await uut.validateEmailArray()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'emailList\' must be a array!')
}
})
it('should throw error if email list is empty', async () => {
try {
const emailList = []
await uut.validateEmailArray(emailList)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'emailList\' cant be empty!')
}
})
it('should return true ', async () => {
try {
const emailList = [
'test@email.com',
'simple@email.com'
]
const result = await uut.validateEmailArray(emailList)
assert.isTrue(result)
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
describe('getHtmlFromObject()', () => {
it('should throw error if the input is not provided ', async () => {
try {
await uut.getHtmlFromObject()
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'objectData\' must be a object!')
}
})
it('should throw error if the object is empty', async () => {
try {
await uut.getHtmlFromObject({})
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'subject\' must be a string!')
}
})
it('should throw error if "formMessage" property is not provided', async () => {
try {
const obj = {
subject: 'unit'
}
await uut.getHtmlFromObject(obj)
assert(false, 'Unexpected result')
} catch (err) {
assert.include(err.message, 'Property \'formMessage\' must be a string!')
}
})
it('should return the html', async () => {
try {
const obj = {
subject: 'unit ',
formMessage: 'test',
value1: 'value1',
value2: 'value2',
value3: 'value3'
}
const result = await uut.getHtmlFromObject(obj)
assert.isString(result)
assert.include(result, '<p>', 'expect html tag')
assert.include(result, '</p>', 'expect html tag')
assert.include(result, 'value1', 'Expect value 1 is included in the html')
assert.include(result, 'value2', 'expect is included in the html')
assert.include(result, 'value3', 'expect is included in the html')
} catch (err) {
assert(false, 'Unexpected result')
}
})
})
})