Skip to content

Commit

Permalink
Implement queue configs for email sending
Browse files Browse the repository at this point in the history
  • Loading branch information
rusiruavb committed Jan 4, 2022
1 parent 2c8871a commit 3dbdf42
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 121 deletions.
37 changes: 5 additions & 32 deletions src/api/controllers/Application.controller.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Request, Response, NextFunction } from "express";
import ApplicationService from "../services";
import EmailService from "../../util/email.handler";
import logger from "../../util/logger";
import { IApplication } from "../../interfaces";
import { request } from "http";
import { createChannel, publishMessageToQueue } from "../../util/queue.config";
import { configs } from "../../config";

/**
* @param {Request} request - Request from the frontend
Expand All @@ -13,34 +11,9 @@ import { request } from "http";
*/
export const addApplication = async (request: Request, response: Response, next: NextFunction) => {
await ApplicationService.addApplication(request.body)
.then((data) => {
// Send email
const emailTemplate = "Application-Email-Template.html";
const to = data.email;
const subject = "MS Club SLIIT - Application Received";
const emailBodyData = {
studentId: data.studentId,
name: data.name,
email: data.email,
contactNumber: data.contactNumber,
currentAcademicYear: data.currentAcademicYear,
linkedIn: data.linkedIn,
gitHub: data.gitHub,
skillsAndTalents: data.skillsAndTalents,
};

EmailService.sendEmailWithTemplate(emailTemplate, to, subject, emailBodyData)
.then(() => {
request.handleResponse.successRespond(response)({
applicationData: data,
});
})
.catch((error) => {
request.handleResponse.errorRespond(response)({
message: error.message,
data: data,
});
});
.then(async (data) => {
request.handleResponse.successRespond(response)(data);
next();
})
.catch((error: any) => {
request.handleResponse.errorRespond(response)(error.message);
Expand Down
28 changes: 2 additions & 26 deletions src/api/controllers/Contact.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Request, Response, NextFunction } from "express";
import ContactService from "../services";
import EmailService from "../../util/email.handler";
import moment from "moment";

/**
* @param {Request} request - Request from the frontend
Expand All @@ -12,30 +10,8 @@ import moment from "moment";
export const createContact = async (request: Request, response: Response, next: NextFunction) => {
await ContactService.insertContact(request.body)
.then((data) => {
// Send email
const emailTemplate = "Contact-Us-Email-Template.html";
const to = data.email;
const subject = "MS Club SLIIT - Contact Us";
const emailBodyData = {
name: data.name,
email: data.email,
message: data.message,
date_time: moment(data.createdAt).format("LLL"),
};

EmailService.sendEmailWithTemplate(emailTemplate, to, subject, emailBodyData)
.then((emailData) => {
request.handleResponse.successRespond(response)({
contactData: data,
emailData: emailData,
});
})
.catch((error) => {
request.handleResponse.errorRespond(response)({
message: error.message,
data: data,
});
});
request.handleResponse.successRespond(response)(data);
next();
})
.catch((error: any) => {
request.handleResponse.errorRespond(response)(error.message);
Expand Down
68 changes: 50 additions & 18 deletions src/api/services/Application.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { DocumentDefinition, FilterQuery } from "mongoose";
import EmailService from "../../util/email.handler";
import { IApplication, IInterview } from "../../interfaces";
import ApplicationModel from "../models/Application.model";
import { createChannel, publishMessageToQueue } from "../../util/queue.config";
import { configs } from "../../config";

/**
* Application Service
Expand All @@ -10,7 +11,32 @@ import ApplicationModel from "../models/Application.model";
*/
export const addApplication = async (applicationData: DocumentDefinition<IApplication>) => {
return await ApplicationModel.create(applicationData)
.then((application) => {
.then(async (application) => {
// Send email
const emailTemplate = "Application-Email-Template.html";
const to = application.email;
const subject = "MS Club SLIIT - Application Received";
const emailBodyData = {
studentId: application.studentId,
name: application.name,
email: application.email,
contactNumber: application.contactNumber,
currentAcademicYear: application.currentAcademicYear,
linkedIn: application.linkedIn,
gitHub: application.gitHub,
skillsAndTalents: application.skillsAndTalents,
};

const email = {
template: emailTemplate,
to: to,
subject: subject,
body: emailBodyData,
};

// Send email data to message queue
const channel = await createChannel();
publishMessageToQueue(channel, configs.queue.emailService, JSON.stringify(email));
return application;
})
.catch((error) => {
Expand Down Expand Up @@ -91,14 +117,17 @@ export const changeApplicationStatusIntoInterview = async (
format: interviewData.format,
};

return await EmailService.sendEmailWithTemplate(emailTemplate, to, subject, emailBodyData)
.then(async () => {
application.status = "INTERVIEW";
return await application.save();
})
.catch(() => {
return application;
});
const email = {
template: emailTemplate,
to: to,
subject: subject,
body: emailBodyData,
};

// Send email data to message queue
const channel = await createChannel();
publishMessageToQueue(channel, configs.queue.emailService, JSON.stringify(email));
return application;
} else {
return null;
}
Expand Down Expand Up @@ -127,14 +156,17 @@ export const changeApplicationStatusIntoSelected = async (
name: application.name,
};

return await EmailService.sendEmailWithTemplate(emailTemplate, to, subject, emailBodyData)
.then(async () => {
application.status = "SELECTED";
return await application.save();
})
.catch(() => {
return application;
});
const email = {
template: emailTemplate,
to: to,
subject: subject,
body: emailBodyData,
};

// Send email data to message queue
const channel = await createChannel();
publishMessageToQueue(channel, configs.queue.emailService, JSON.stringify(email));
return application;
} else {
return null;
}
Expand Down
26 changes: 25 additions & 1 deletion src/api/services/Contact.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import { DocumentDefinition } from "mongoose";
import { IContact } from "../../interfaces";
import { createChannel, publishMessageToQueue } from "../../util/queue.config";
import ContactModel from "../models/Contact.model";
import moment from "moment";
import { configs } from "../../config";

/**
* @param {IContact} contactData
* @returns {IContact} Contact data
*/
export const insertContact = async (contactData: DocumentDefinition<IContact>) => {
return await ContactModel.create(contactData)
.then((data) => {
.then(async (data) => {
// Send email
const emailTemplate = "Contact-Us-Email-Template.html";
const to = data.email;
const subject = "MS Club SLIIT - Contact Us";
const emailBodyData = {
name: data.name,
email: data.email,
message: data.message,
date_time: moment(data.createdAt).format("LLL"),
};

const email = {
template: emailTemplate,
to: to,
subject: subject,
body: emailBodyData,
};

// Send email data to message queue
const channel = await createChannel();
publishMessageToQueue(channel, configs.queue.emailService, JSON.stringify(email));
return data;
})
.catch((error) => {
Expand Down
4 changes: 2 additions & 2 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ if (environment == "Development") {
emailTemplateBucket: process.env.EMAIL_TEMPLATE_BUCKET as string,
},
queue: {
messageBrokerURL: process.env.MESSAGE_BROKER_URL as string,
messageBrokerURL: process.env.DEV_MESSAGE_BROKER_URL as string,
exchangeName: process.env.EXCHANGE_NAME as string,
emailService: process.env.EMAIL_SERVICE_NAME as string,
emailQueue: process.env.EMAIL_QUEUE_NAME as string,
Expand Down Expand Up @@ -88,7 +88,7 @@ if (environment == "Production") {
emailTemplateBucket: process.env.EMAIL_TEMPLATE_BUCKET as string,
},
queue: {
messageBrokerURL: process.env.MESSAGE_BROKER_URL as string,
messageBrokerURL: process.env.PROD_MESSAGE_BROKER_URL as string,
exchangeName: process.env.EXCHANGE_NAME as string,
emailService: process.env.EMAIL_SERVICE_NAME as string,
emailQueue: process.env.EMAIL_QUEUE_NAME as string,
Expand Down
7 changes: 0 additions & 7 deletions src/email/Email.service.ts

This file was deleted.

32 changes: 0 additions & 32 deletions src/email/email.queue.ts

This file was deleted.

21 changes: 18 additions & 3 deletions src/util/email.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import logger from "./logger";
import { configs } from "../config";
import moment from "moment";
import fetch from "cross-fetch";
import { Channel } from "amqplib";
import { subscribeMessages } from "./queue.config";

const cc =
"senurajayadeva@gmail.com,Lasalshettiarachchi458@gmail.com,rusiruavbpersonal98@gmail.com,yasirurandika99@gmail.com";
Expand All @@ -20,15 +22,28 @@ let template: HandlebarsTemplateDelegate;
let htmlToSend: string;

class EmailService {
static sendEmailWithTemplate(fileName: string, to: string, subject: string, emailBodyData: any) {
channel: Channel;

constructor(channel: Channel) {
this.channel = channel;
subscribeMessages(this.channel, this);
}

sendEmailWithTemplate(data: any) {
console.log(data);
let fileName = data.email.template;
let to = data.email.to;
let subject = data.email.subject;
let emailBodyData = data.email.body;

return new Promise(async (resolve, reject) => {
this.getEmailTemplatePath(fileName)
EmailService.getEmailTemplatePath(fileName)
.then((emailTemplate) => {
if (emailTemplate) {
template = handlebars.compile(emailTemplate);
htmlToSend = template(emailBodyData);

this.retry(
EmailService.retry(
5, // Retry count
function () {
return EmailService.sendEmail(to, subject, htmlToSend)
Expand Down
39 changes: 39 additions & 0 deletions src/util/queue.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import amqp, { Channel } from "amqplib";
import { configs } from "../config";
import EmailService from "./email.handler";

// Create a channel
const createChannel = async () => {
try {
const connection = await amqp.connect(configs.queue.messageBrokerURL);
const channel = await connection.createChannel();
await channel.assertExchange(configs.queue.exchangeName, "direct", { durable: false });
return channel;
} catch (error) {
throw error;
}
};

// Publish the messages
const publishMessageToQueue = async (channel: Channel, bindingKey: string, message: any) => {
try {
await channel.publish(configs.queue.exchangeName, bindingKey, Buffer.from(JSON.stringify(message)));
} catch (error) {
throw error;
}
};

// Subscribe to messages
const subscribeMessages = async (channel: Channel, service: EmailService) => {
const serviceQueue = await channel.assertQueue(configs.queue.emailQueue);
channel.bindQueue(serviceQueue.queue, configs.queue.exchangeName, configs.queue.emailService);
channel.consume(serviceQueue.queue, (data) => {
if (data) {
const queueItem = JSON.parse(JSON.parse(data.content.toString()));
service.sendEmailWithTemplate(queueItem);
channel.ack(data); // Send acknowledgement to queue after consume the message
}
});
};

export { createChannel, publishMessageToQueue, subscribeMessages };

0 comments on commit 3dbdf42

Please sign in to comment.