-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
777 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
require("dotenv/config"); | ||
const email_service_1 = require("./services/email.service"); | ||
const envs_1 = require("./config/envs"); | ||
const consumer_service_1 = require("./services/consumer.service"); | ||
const queue_service_1 = require("./services/queue.service"); | ||
const VERIFY_QUEUE = 'verify-email'; | ||
const PASSWORD_QUEUE = 'change-password'; | ||
const NOTIFICATION_QUEUE = 'animal-changed-notification'; | ||
const CHAT_MESSAGE_QUEUE = 'chat-message'; | ||
(() => __awaiter(void 0, void 0, void 0, function* () { | ||
yield main(); | ||
}))(); | ||
function main() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const errorLogsService = new queue_service_1.QueueService(envs_1.envs.RABBITMQ_URL, 'error-notification'); | ||
const emailService = new email_service_1.EmailService({ | ||
mailerService: envs_1.envs.MAIL_SERVICE, | ||
mailerEmail: envs_1.envs.MAILER_EMAIL, | ||
senderEmailPassword: envs_1.envs.MAILER_SECRET_KEY, | ||
}, errorLogsService, envs_1.envs.WEBSERVICE_URL); | ||
const verifyEmailConsumer = new consumer_service_1.ConsumerService(emailService, errorLogsService, envs_1.envs.RABBITMQ_URL, VERIFY_QUEUE); | ||
yield verifyEmailConsumer.consume(); | ||
const animalChangedNotificationConsumer = new consumer_service_1.ConsumerService(emailService, errorLogsService, envs_1.envs.RABBITMQ_URL, NOTIFICATION_QUEUE); | ||
yield animalChangedNotificationConsumer.consume(); | ||
const changePasswordConsumer = new consumer_service_1.ConsumerService(emailService, errorLogsService, envs_1.envs.RABBITMQ_URL, PASSWORD_QUEUE); | ||
yield changePasswordConsumer.consume(); | ||
const unreadMessagesConsumer = new consumer_service_1.ConsumerService(emailService, errorLogsService, envs_1.envs.RABBITMQ_URL, CHAT_MESSAGE_QUEUE); | ||
yield unreadMessagesConsumer.consume(); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.envs = void 0; | ||
require("dotenv/config"); | ||
const env_var_1 = require("env-var"); | ||
exports.envs = { | ||
//* Email Service | ||
MAIL_SERVICE: (0, env_var_1.get)('MAIL_SERVICE').required().asString(), | ||
MAILER_EMAIL: (0, env_var_1.get)('MAILER_EMAIL').required().asString(), | ||
MAILER_SECRET_KEY: (0, env_var_1.get)('MAILER_SECRET_KEY').required().asString(), | ||
//* FRONTEND URL | ||
WEBSERVICE_URL: (0, env_var_1.get)('WEBSERVICE_URL').required().asString(), | ||
//* RABBITMQ | ||
RABBITMQ_USER: (0, env_var_1.get)('RABBITMQ_USER').required().asString(), | ||
RABBITMQ_PASS: (0, env_var_1.get)('RABBITMQ_PASS').required().asString(), | ||
RABBITMQ_URL: (0, env_var_1.get)('RABBITMQ_URL').required().asString(), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ConsumerService = void 0; | ||
const amqp_connection_manager_1 = __importDefault(require("amqp-connection-manager")); | ||
/** | ||
* Creates an instance of ConsumerService. | ||
* @param emailService The email service used to send emails. | ||
* @param errorLogsService The queue service used to log error messages. | ||
* @param rabbitmqUrl The URL of the RabbitMQ server. | ||
* @param queue The name of the queue to consume messages from. | ||
*/ | ||
class ConsumerService { | ||
constructor(emailService, errorLogsService, rabbitmqUrl, queue) { | ||
this.emailService = emailService; | ||
this.errorLogsService = errorLogsService; | ||
this.rabbitmqUrl = rabbitmqUrl; | ||
this.queue = queue; | ||
this.channelWrapper = undefined; | ||
this.EXCHANGE = 'email-request'; | ||
try { | ||
const connection = amqp_connection_manager_1.default.connect(this.rabbitmqUrl); | ||
this.channelWrapper = connection.createChannel(); | ||
} | ||
catch (error) { | ||
console.log(error); | ||
} | ||
} | ||
/** | ||
* Starts consuming messages from the specified queue. | ||
*/ | ||
consume() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
yield this.channelWrapper.addSetup((channel) => __awaiter(this, void 0, void 0, function* () { | ||
yield channel.assertQueue(this.queue, { durable: true }); | ||
yield channel.bindQueue(this.queue, this.EXCHANGE, this.queue); | ||
yield channel.consume(this.queue, (message) => __awaiter(this, void 0, void 0, function* () { | ||
if (message) { | ||
const content = JSON.parse(message.content.toString()); | ||
switch (this.queue) { | ||
case 'animal-changed-notification': { | ||
yield this.emailService.sendAnimalChangedNotification(content); | ||
break; | ||
} | ||
case 'verify-email': { | ||
yield this.emailService.sendEmailValidationLink(content); | ||
break; | ||
} | ||
case 'change-password': { | ||
yield this.emailService.sendEmailValidationLink(content); | ||
break; | ||
} | ||
case 'chat-message': { | ||
yield this.emailService.sendUnreadChatMessage(content); | ||
} | ||
default: { | ||
('Unknown queue'); | ||
} | ||
} | ||
channel.ack(message); | ||
} | ||
})); | ||
})); | ||
console.log(`${this.queue} consumer service started and listening for messages`); | ||
} | ||
catch (err) { | ||
console.log('Error starting the consumer: ', err); | ||
this.errorLogsService.addMessageToQueue({ | ||
message: `Error starting the ${this.queue} consumer: ${err}`, | ||
level: 'high', | ||
origin: 'WebSocket Server', | ||
}, 'error-logs'); | ||
} | ||
}); | ||
} | ||
} | ||
exports.ConsumerService = ConsumerService; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.EmailService = void 0; | ||
const nodemailer_1 = __importDefault(require("nodemailer")); | ||
const petChanged_1 = require("../templates/petChanged"); | ||
const chatMessages_1 = require("../templates/chatMessages"); | ||
const mailValidation_1 = require("../templates/mailValidation"); | ||
/** | ||
* Service for sending emails. | ||
*/ | ||
class EmailService { | ||
constructor({ mailerService, mailerEmail, senderEmailPassword }, errorLogsService, webServiceUrl) { | ||
this.errorLogsService = errorLogsService; | ||
this.webServiceUrl = webServiceUrl; | ||
this.transporter = nodemailer_1.default.createTransport({ | ||
service: mailerService, | ||
auth: { | ||
user: mailerEmail, | ||
pass: senderEmailPassword, | ||
}, | ||
}); | ||
} | ||
/** | ||
* Sends an email notification for unread chat messages. | ||
* @param options Options for sending unread chat message notification. | ||
* @returns A boolean indicating whether the email was sent successfully. | ||
*/ | ||
sendUnreadChatMessage({ chat, email }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const title = 'Tienes mensajes de chat sin leer'; | ||
const endPoint = 'private/chat'; | ||
const link = `${this.webServiceUrl}/${endPoint}/${chat}`; | ||
// const html = ` | ||
// <h1>${title}</h1> | ||
// <p>Por favor haz click en el siguiente link para acceder al chat</p> | ||
// <a href="${link}">${title}</a> | ||
// `; | ||
const html = (0, chatMessages_1.chatMessages)(link); | ||
const options = { | ||
to: email, | ||
subject: title, | ||
htmlBody: html, | ||
}; | ||
const isSent = yield this.sendEmail(options); | ||
if (!isSent) | ||
return false; | ||
return true; | ||
}); | ||
} | ||
/** | ||
* Sends a notification when an animal of interest changes. | ||
* @param options Options for sending animal changed notification. | ||
* @returns A boolean indicating whether the email was sent successfully. | ||
*/ | ||
sendAnimalChangedNotification({ link, email, }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const title = 'Un animal de tus favoritos ha cambiado!'; | ||
// const html = ` | ||
// <h1>${title}</h1> | ||
// <p>Por favor haz click en el siguiente link para ver el animal</p> | ||
// <a href=${this.webServiceUrl}/${link}>${title}</a> | ||
// `; | ||
const html = (0, petChanged_1.petChanged)(this.webServiceUrl, link); | ||
const options = { | ||
to: email, | ||
subject: title, | ||
htmlBody: html, | ||
}; | ||
const isSent = yield this.sendEmail(options); | ||
if (!isSent) | ||
return false; | ||
return true; | ||
}); | ||
} | ||
/** | ||
* Sends an email validation link. | ||
* @param options Options for sending email validation link. | ||
* @returns A boolean indicating whether the email was sent successfully. | ||
*/ | ||
sendEmailValidationLink({ email, verificationToken, type, }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { html, title } = this.generateEmailContent(type, verificationToken, email); | ||
const options = { | ||
to: email, | ||
subject: title, | ||
htmlBody: html, | ||
}; | ||
const isSent = yield this.sendEmail(options); | ||
if (!isSent) | ||
return false; | ||
return true; | ||
}); | ||
} | ||
/** | ||
* Generates email content based on the type of email and token provided. | ||
* @param type The type of email (either 'email' or 'reset-password'). | ||
* @param token The token to include in the email link. | ||
* @param email The recipient's email address. | ||
* @returns An object containing the HTML content of the email and its title. | ||
*/ | ||
generateEmailContent(type, token, email) { | ||
const endPoint = type === 'email' ? 'verify-email' : 'reset-password'; | ||
const title = type === 'email' ? 'Valida tu Email' : 'Cambia tu password'; | ||
const action = type === 'email' ? 'validar tu email' : 'cambiar tu password'; | ||
const link = `${this.webServiceUrl}/${endPoint}/${token}`; | ||
// const html = ` | ||
// <h1>${title}</h1> | ||
// <p>Por favor haz click en el siguiente link para ${action}</p> | ||
// <a href="${link}">${title}</a> | ||
// `; | ||
const html = (0, mailValidation_1.mailValidation)(title, action, link); | ||
return { html, title }; | ||
} | ||
/** | ||
* Sends an email based on the provided options. | ||
* @param options The options for sending the email. | ||
* @returns A boolean indicating whether the email was sent successfully. | ||
*/ | ||
sendEmail(options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const { to, subject, htmlBody, attachments: attachments = [] } = options; | ||
if ((typeof to === 'string' && to === 'test@test.com') || | ||
to.includes('test@test.com')) | ||
return false; | ||
try { | ||
const sentInformation = yield this.transporter.sendMail({ | ||
to: to, | ||
subject: subject, | ||
html: htmlBody, | ||
attachments: attachments, | ||
}); | ||
return true; | ||
} | ||
catch (error) { | ||
console.log({ error }); | ||
this.errorLogsService.addMessageToQueue({ | ||
message: `Error sending email: ${error}`, | ||
level: 'high', | ||
origin: 'Email Service', | ||
}, 'error-logs'); | ||
return false; | ||
} | ||
}); | ||
} | ||
} | ||
exports.EmailService = EmailService; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.QueueService = void 0; | ||
const amqp_connection_manager_1 = __importDefault(require("amqp-connection-manager")); | ||
/** | ||
* ProducerService class for sending messages to RabbitMQ queues. | ||
*/ | ||
class QueueService { | ||
/** | ||
* Constructs an instance of ProducerService. | ||
* @param rabbitmqUrl - URL of the RabbitMQ server. | ||
* @param exchange - Name of the exchange to publish messages. | ||
*/ | ||
constructor(rabbitmqUrl, exchange) { | ||
this.rabbitmqUrl = rabbitmqUrl; | ||
this.exchange = exchange; | ||
// Establishes connection to RabbitMQ server and creates a channel wrapper. | ||
const connection = amqp_connection_manager_1.default.connect(this.rabbitmqUrl); | ||
this.channelWrapper = connection.createChannel({ | ||
// Ensures the exchange is declared upon channel creation. | ||
setup: (channel) => { | ||
return channel.assertExchange(this.exchange, 'direct', { | ||
durable: true, | ||
}); | ||
}, | ||
}); | ||
console.log(`${this.exchange} exchange created`); | ||
} | ||
/** | ||
* Adds a message to the specified queue in the exchange. | ||
* @param payload - Data to be sent in the message. | ||
* @param queue - Name of the queue to send the message. | ||
*/ | ||
addMessageToQueue(payload, queue) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
console.log({ payload, queue }); | ||
// Publishes the message to the specified queue in the exchange. | ||
yield this.channelWrapper.publish('email-request', queue, Buffer.from(JSON.stringify(payload)), { persistent: true }); | ||
console.log('Message sent to queue'); | ||
} | ||
catch (error) { | ||
console.log('Error sending message to queue', error); | ||
} | ||
}); | ||
} | ||
} | ||
exports.QueueService = QueueService; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.