From e23e4c022fde17798325015bfe3017825ad9fd5d Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Dec 2025 16:36:06 +0530 Subject: [PATCH] Low - Email service issues fixed --- app/controllers/establishment.controller.js | 53 +---------- .../establishment_user.controller.js | 28 ++++-- app/controllers/submission.controller.js | 90 +++++++++---------- app/services/email.service.js | 26 ++++-- app/utils/sanitize.js | 8 ++ 5 files changed, 93 insertions(+), 112 deletions(-) diff --git a/app/controllers/establishment.controller.js b/app/controllers/establishment.controller.js index 7626663..a4f7c47 100644 --- a/app/controllers/establishment.controller.js +++ b/app/controllers/establishment.controller.js @@ -18,7 +18,7 @@ const csv = require("csv-parser"); const path = require("path"); const { version } = require("os"); const sequelize = db.sequelize; -const sanitizeForLog = require("../utils/sanitizeLog"); +const sanitizeForLog = require("../utils/sanitize"); exports.testEmail = async (req, res) => { placeHolderData = { @@ -187,15 +187,15 @@ exports.createEstablishment = async (req, res) => { //send email to user placeHolderData = { - contact_name : establishment_user.name, + contact_name : sanitizeForLog(establishment_user.name), portal_url : process.env.FE_BASE_URL, - username : establishment_user.email, + username : sanitizeForLog(establishment_user.email), password : establishment_user.password, support_email : process.env.SUPPORT_EMAIL, support_phone : process.env.SUPPORT_PHONE, } - await sendEmailService(establishment_user.email, 'establishment_user_creation_to_user', placeHolderData); + await sendEmailService(sanitizeForLog(establishment_user.email), 'establishment_user_creation_to_user', placeHolderData); // insert establishment_products // if (Array.isArray(establishment_products) && establishment_products.length > 0) { @@ -298,51 +298,6 @@ exports.createEstablishment = async (req, res) => { } }; -// Get all establishments -// exports.getAllEstablishments = async (req, res) => { -// try { - -// const data = await Establishment.findAll({ -// include: [ -// // { -// // model: EstablishmentUser, -// // as: "users", -// // attributes: ["id", "name", "email", "is_active"], -// // }, -// { -// model: CityTown, -// as: "establishment_city", -// attributes: ["name"], -// }, -// { -// model: Emirate, -// as: "establishment_emirate", -// attributes: ["name"], -// },{ -// model: CityTown, -// as: "corporate_city", -// attributes: ["name"], -// }, -// { -// model: Emirate, -// as: "corporate_emirate", -// attributes: ["name"], -// }, -// { -// model: user, -// as: "created_user", -// attributes: ["name"], -// } - -// ], -// }); - -// return res.status(200).send({'status':"success",'message':"Fetched successfully",'data': data }); - -// } catch (err) { -// return res.status(500).send({'status':"failed",'message':err.message }); -// } -// }; exports.getAllEstablishments = async (req, res) => { try { let { diff --git a/app/controllers/establishment_user.controller.js b/app/controllers/establishment_user.controller.js index 37d9040..4e64c82 100644 --- a/app/controllers/establishment_user.controller.js +++ b/app/controllers/establishment_user.controller.js @@ -3,6 +3,7 @@ const bcrypt = require("bcryptjs"); const EstablishmentUser = db.EstablishmentUser; const { sendEmailService } = require("../services/email.service"); +const { sanitizeForLog } = require("../utils/sanitize"); // Create User exports.createUser = async (req, res) => { @@ -11,10 +12,25 @@ exports.createUser = async (req, res) => { const { establishment_id, name, email, password , gender} = req.body; const hashed = await bcrypt.hash(password, 10); - // Check if establishment user already exists - const existingEstablishmentUser = await EstablishmentUser.findOne({where: { email }, }); - if (existingEstablishmentUser) { - return res.status(400).send({status: "failed",message: "Email already exists", }); + email = sanitizeForLog(email || ""); + name = sanitizeForLog(name || ""); + gender = sanitizeForLog(gender || ""); + + if (!establishment_id || !email) { + return res.status(400).send({ + status: "error", + code: "MISSING_FIELDS", + message: "establishment_id and email are required" + }); + } + + const existing = await EstablishmentUser.findOne({ where: { email, is_active: true } }); + if (existing) { + return res.status(400).send({ + status: "error", + code: "EMAIL_EXISTS", + message: "Email already exists" + }); } const user = await EstablishmentUser.create({ @@ -38,10 +54,10 @@ exports.createUser = async (req, res) => { } await sendEmailService(email, 'establishment_user_creation_to_user', placeHolderData); - return res.status(201).send({'status':"success",'message':"Creation successful",'data': user }); + return res.status(201).send({'status':"ok", 'message':"Creation successful",'data': user }); } catch (err) { - return res.status(500).send({'status':"failed",'message':err.message }); + return res.status(500).send({'status':"error",'message':err.message }); } }; diff --git a/app/controllers/submission.controller.js b/app/controllers/submission.controller.js index 59eea7a..b7a1be2 100644 --- a/app/controllers/submission.controller.js +++ b/app/controllers/submission.controller.js @@ -18,7 +18,7 @@ const { Sequelize } = require("sequelize"); const { sendEmail } = require("../services/email.service"); const { sendEmailService } = require("../services/email.service"); const { getQuarterPeriods } = require("../services/quarterService"); - +const sanitizeForLog = require("../utils/sanitize"); exports.createSubmission = async (req, res) => { @@ -741,24 +741,30 @@ exports.approveOrRejectSubmission = async (req, res) => { try { const { id } = req.params; - approve_reject_status = req.body.approve_reject_status; - reject_reason = req.body.reject_reason; - approve_or_reject_by = req.body.approve_or_reject_by || req.user.id; + const approve_reject_status = sanitizeForLog(req.body.approve_reject_status); + const reject_reason = sanitizeForLog(req.body.reject_reason || ""); + const approve_or_reject_by = sanitizeForLog(req.body.approve_or_reject_by || req.user.id); - if(approve_reject_status == 1) - { - statusString = 'Approved'; - }else{ - statusString = 'Rejected'; + if (![1, "1", 0, "0"].includes(approve_reject_status)) { + return res.status(400).json({ + status: "failed", + message: "approve_reject_status must be 1 or 0" + }); } - // Check submission exists + const statusString = approve_reject_status == 1 ? "Approved" : "Rejected"; const submission = await Submission.findByPk(id); if (!submission) return res.status(404).json({ status: "failed", message: "Submission not found" }); - // Update submission main data - const result = await submission.update({ approve_reject_status : approve_reject_status , status : statusString, reject_reason, approve_or_reject_by: approve_or_reject_by, updated_by: req.user.id, updated_at: new Date() }); + const result = await submission.update({ + approve_reject_status, + status: statusString, + reject_reason, + approve_or_reject_by, + updated_by: req.user.id, + updated_at: new Date() + }); //send email to establishment user @@ -769,54 +775,42 @@ exports.approveOrRejectSubmission = async (req, res) => { { for await (const userObj of EstablishmentUserData) { - placeHolderData = { - user_name : userObj.name, - portal_url : process.env.FE_BASE_URL, - quarter : result['quarter'], - year : result['year'], - establishment_name : EstablishmentData['factory_name'], - submission_date : result['created_at'], - rejection_reason : result['reject_reason'], - support_email : process.env.SUPPORT_EMAIL, - support_phone : process.env.SUPPORT_PHONE, - } + placeHolderData = { + user_name: sanitizeForLog(userObj.name), + portal_url : process.env.FE_BASE_URL, + quarter : result['quarter'], + year : result['year'], + establishment_name : EstablishmentData['factory_name'], + submission_date : result['created_at'], + rejection_reason : result['reject_reason'], + support_email : process.env.SUPPORT_EMAIL, + support_phone : process.env.SUPPORT_PHONE, + }; - await sendEmailService(userObj.email, 'submission_approved_mail_to_establishment_user', placeHolderData); - } - - }else{ - - for await (const userObj of EstablishmentUserData) - { - placeHolderData = { - user_name : userObj.name, - portal_url : process.env.FE_BASE_URL, - quarter : result['quarter'], - year : result['year'], - establishment_name : EstablishmentData['factory_name'], - submission_date : result['created_at'], - rejection_reason : result['reject_reason'], - support_email : process.env.SUPPORT_EMAIL, - support_phone : process.env.SUPPORT_PHONE, - } + const template = approve_reject_status == 1 + ? "submission_approved_mail_to_establishment_user" + : "submission_rejected_mail_to_establishment_user"; - await sendEmailService(userObj.email, 'submission_rejected_mail_to_establishment_user', placeHolderData); - } + await sendEmailService( + sanitizeForLog(userObj.email), + template, + placeHolderData + ); } - - - res.status(200).json({ + } + return res.status(200).json({ status: "success", message: "Submission edit access updated", data: result, }); - } catch (err) { console.error(err); - res.status(500).json({ status: "failed", message: err.message }); + res.status(500).json({ status: "failed", message: sanitizeForLog(err.message) }); } + }; + exports.getQuarterPeriods = async (req, res) => { try { const { current_year, current_quarter } = req.body; diff --git a/app/services/email.service.js b/app/services/email.service.js index f5bd10d..fcb5d2a 100644 --- a/app/services/email.service.js +++ b/app/services/email.service.js @@ -2,6 +2,7 @@ const nodemailer = require("nodemailer"); const { NotificationTemplate } = require("../models"); // adjust path if needed const logger = require("../services/logger"); require("dotenv").config(); +const sanitizeForLog = require("../utils/sanitize"); const port = Number(process.env.MAIL_PORT); @@ -45,12 +46,19 @@ function replacePlaceholders(templateHtml, data) { exports.sendEmailService = async (to, templateCode, data = {}) => { - const logPrefix = `[EMAIL SERVICE][${new Date().toISOString()}]`; - - logger.info(`${logPrefix} → Starting email send process`); - logger.info(`${logPrefix} → Template Code: ${templateCode}`); - logger.info(`${logPrefix} → Recipient: ${to}`); - logger.info(`${logPrefix} → Placeholder Data: ${JSON.stringify(data)}`); + + const sanitizedTo = sanitizeForLog(to); + const sanitizedTemplate = sanitizeForLog(templateCode); + const sanitizedData = sanitizeForLog( + typeof data === "object" ? JSON.stringify(data) : String(data) + ); + + const logPrefix = `[EMAIL SERVICE][${new Date().toISOString()}]`; + + logger.info(`${logPrefix} → Starting email process`); + logger.info(`${logPrefix} → Template Code: ${sanitizedTemplate}`); + logger.info(`${logPrefix} → Recipient: ${sanitizedTo}`); + logger.info(`${logPrefix} → Placeholder Data: ${sanitizedData}`); try { // 1. Fetch template from DB @@ -59,7 +67,7 @@ exports.sendEmailService = async (to, templateCode, data = {}) => { }); if (!template) { - logger.error(`${logPrefix} ❌ Template not found for code: ${templateCode}`); + logger.error(`${logPrefix} ❌ Template not found for code:${sanitizedTemplate}`); throw new Error(`Template not found for code: ${templateCode}`); } @@ -81,11 +89,11 @@ exports.sendEmailService = async (to, templateCode, data = {}) => { const info = await transporter.sendMail(mailOptions); logger.info(`${logPrefix} ✅ Email sent successfully`); - logger.info(`${logPrefix} Message ID: ${info.messageId}`); + logger.info(`${logPrefix} Message ID: ${sanitizeForLog(info.messageId)}`); logger.info(`${logPrefix} Response: ${info.response}`); return { - status: "success", + status: "ok", message: "Email sent successfully", messageId: info.messageId, response: info.response, diff --git a/app/utils/sanitize.js b/app/utils/sanitize.js index baa0d77..b894d0a 100644 --- a/app/utils/sanitize.js +++ b/app/utils/sanitize.js @@ -10,3 +10,11 @@ exports.sanitizeHtml = (html = "") => { disallowedTagsMode: "discard" }); }; + +exports.sanitizeForLog = (value) => { + if (typeof value !== "string") return value; + return value + .replace(/[\r\n]+/g, " ") + .replace(/\t+/g, " ") + .replace(/[^\x20-\x7E]+/g, " "); +}; \ No newline at end of file