PK!A7��nconst contactGroup = require("../models/contactGroup"); const contact = require("../models/contact"); const campaign = require("../models/campaign"); const emailIdModel = require("../models/EmailId"); const accountCreditsModel = require("../models/accountCredits"); const campaignReport = require("../models/campaignReport"); const campaignEmailReport = require("../models/campignEmailReport"); const combineEmailReport = require("../models/combineEmailReport"); const emailTemplate = require("../models/emailTemplate"); const reports = require("../models/reports"); const reqLib = require("../library/request"); const messageIdGen = require("../library/messageIdGenerate"); const http = require("http"); const https = require("https"); const dotenv = require("dotenv"); const jwt = require("jsonwebtoken"); const readXlsxFile = require("read-excel-file/node"); const excelJS = require("exceljs"); const nodemailer = require("nodemailer"); const fsPromises = require("fs").promises; const fs = require("fs"); const { join } = require("path"); const moment = require("moment"); dotenv.config(); const config = process.env; var multer = require("multer"); var forms = multer(); var randomstring = require("randomstring"); const { promisify } = require("util"); const util = require("util"); const mv = promisify(fs.rename); var format = require("text-template"); const common = require("../helper/common"); const { getMaxListeners } = require("process"); const { exec } = require("child_process"); const opts = { errorEventName: "error", logDirectory: "logs", fileNamePattern: "log-.log", dateFormat: "YYYY-MM-DD", }; const log = require("simple-node-logger").createRollingFileLogger(opts); async function runCustomEmailCampaign(req, res) { try { const userId = req.headers["id"]; let { name, type, groupId, message, emailSenderId, templateId, isScheduled, scheduledAt, subject, } = req.body; const file = req.file; log.info( `[Custom Email Campaign], [runCustomEmailcampaign], User Id [${userId}], name [${name}], Type [${type}], Group Id [${groupId}], Email Sender Id [${emailSenderId}], Template Id [${templateId}] Subject [${subject}]` ); const isExists = await campaign.isCampaignNameExistsByUserId(name, userId); if (isExists) { log.info( `[Custom Email Campaign], [runCustomEmailcampaign], [Campaign Name is already exists]` ); return res.status(400).json({ msg: "Campaign Name is already exists" }); } if ( !name || !type || !groupId || !message || !emailSenderId || !templateId || !subject ) { log.info( `[Custom Email Campaign], [runCustomEmailcampaign], [Missing parameters]` ); return res.status(400).json({ msg: "Missing parameters" }); } let groupContacts = await contact.getCorrectEmailContactList(groupId); // if (groupContacts) { // groupContacts = groupContacts?.filter((contact) => contact.email); // } let contactLength = groupContacts?.length; let balanceConsumed = groupContacts?.length; //checking message length // let isLengthExceeds = message?.length / 160; // if (isLengthExceeds > 1) { // balanceConsumed = balanceConsumed * Math.ceil(isLengthExceeds); // log.info( // `[Custom Campaign], [runcampaign], Message Length Exceeds [${message?.length}], Contact Length [${groupContacts?.length}], Balance Consumed [${balanceConsumed}]` // ); // } //checking account balance const accountBal = await accountCreditsModel.checkAccountBal(userId); const isSufficientBal = common.checkingBalance( "Custom Email Campaign", "runCustomEmailcampaign", accountBal, balanceConsumed, type ); if (!isSufficientBal) { return res .status(400) .json({ msg: "Insufficient balance to run this campaign" }); } if (!isScheduled || isScheduled == "false") { isScheduled = 2; } else { isScheduled = 1; if (!scheduledAt) { log.info( `[Custom Email Campaign], [runCustomEmailcampaign], [Missing parameters scheduledAt]` ); return res.status(400).json({ msg: "Missing parameters" }); } } if (contactLength > 0) { $senderIdDetails = await emailIdModel.getemailIdById(emailSenderId); if (false == $senderIdDetails) { log.info( `[Custom Email Campaign], [runCustomEmailcampaign], Campaign Id [${campaignId}], Group Id [${groupId}], Sender Id not found` ); return res.status(400).json({ msg: "No sender Id found" }); } let template = await emailTemplate.getTemplateById(templateId); if (false == template) { log.info( `[Custom Email Campaign], [runCustomEmailcampaign], Campaign Id [${campaignId}], Group Id [${groupId}], Template Id [${templateId}], SMS template not found` ); return res.status(400).json({ msg: "Email template not found" }); } let customMessage = template["data"]; let mergeFields = template["merge_fields"]; let templateName = template["name"]; const date = moment().format("YYYY-MM-DD"); const time = moment().format("hh:mm:ss"); const newname = name + "_" + date + "_" + time; let attachmentName = ""; if (file) { //attachmentName = `attachment.${file?.mimetype.split("/")[1]}`; let splitByName = file?.originalname.split("."); let fileExtention = splitByName[splitByName.length-1]; attachmentName = `attachment.${fileExtention}`; } if (2 == isScheduled) { const campaignId = await campaign.addTemplateCampaign( userId, groupId, newname, customMessage, type, emailSenderId, contactLength, templateId, balanceConsumed, attachmentName, subject ); if (file) { log.info( `[Custom Email campaign], [runcampaign], [Campaign started], Campaign Id [${campaignId}], Attachment [${JSON.stringify( file )}]` ); exec(`mkdir -p users/upload/emailAttachments/campaign/${campaignId}`); exec( `mv users/upload/emailAttachments/${file?.filename} users/upload/emailAttachments/campaign/${campaignId}/${attachmentName}` ); } await accountCreditsModel.deductBalance( userId, accountBal?.email - balanceConsumed, "email" ); log.info( `[Custom Email Campaign], [runCustomEmailcampaign], [Campaign started], Campaign Id [${campaignId}], Balance Consumed [${balanceConsumed}], Campaign Type [EMAIL], Group Id [${groupId}], Template Name [${templateName}]` ); processCampaignPush( groupId, emailSenderId, campaignId, newname, type, customMessage, mergeFields, userId, templateName, subject, file ); const NewAccountBal = await accountCreditsModel.checkAccountBal(userId); return res.status(200).json({ msg: "Campaign has been started", userCredit: NewAccountBal, }); } else { const campaignId = await campaign.addScheduleTemplateCampaign( userId, groupId, newname, customMessage, type, emailSenderId, contactLength, templateId, balanceConsumed, scheduledAt, isScheduled, attachmentName, subject ); if (file) { log.info( `[Custom Email campaign], [runcampaign], [Campaign started], Campaign Id [${campaignId}], Attachment [${JSON.stringify( file )}]` ); exec(`mkdir -p users/upload/emailAttachments/campaign/${campaignId}`); exec( `mv users/upload/emailAttachments/${file?.filename} users/upload/emailAttachments/campaign/${campaignId}/${attachmentName}` ); } log.info( `[Custom Email Campaign], [runCustomEmailcampaign], [Campaign Scheduled], Campaign Id [${campaignId}], Group Id [${groupId}]` ); await accountCreditsModel.deductBalance( userId, accountBal?.email - balanceConsumed, "email" ); log.info( `[Custom Email Campaign], [runcampaign], [Campaign started], Campaign Id [${campaignId}], Balance Consumed [${balanceConsumed}], Campaign Type [EMAIL], Group Id [${groupId}], Template Name [${templateName}]` ); } const NewAccountBal = await accountCreditsModel.checkAccountBal(userId); return res.status(200).json({ msg: "Campaign has been scheduled", isScheduled, userCredit: NewAccountBal, }); } else { log.info( `[Custom Email Campaign], [runcampaign], Group Id [${groupId}], No contacts found in the group` ); return res.status(400).json({ msg: "Please add contacts to the group." }); } } catch (e) { log.info(`[Custom Email Campaign], [runcampaign], Error [${e}]`); return res.status(500).json(e); } } async function processCampaignPush( groupId, emailSenderId, campaignId, newname, type, customMessage, mergeFields, userId, templateName, subject, file ) { return new Promise(async (resolve, reject) => { try { let groupContacts = await contact.getCorrectEmailContactList(groupId); // if (groupContacts) { // groupContacts = groupContacts?.filter((contact) => contact.email); // } const senderIdDetails = await emailIdModel.getemailIdById(emailSenderId); // await campaign.setTotalSent(campaignId, groupContacts.length); log.info( `[Custom Email campaign], [processCampaignPush], Campaign Id [${campaignId}], Campaign Name [${newname}], Campaign Started )}]` ); const path = `./users/upload/campaign/${campaignId}`; let folderAction = await fs.promises.mkdir(path, { recursive: true }); const workbook = new excelJS.Workbook(); const worksheet = workbook.addWorksheet("Contacts"); worksheet.columns = [ { header: "First Name", key: "firstName", width: 20 }, { header: "Last Name", key: "lastName", width: 15 }, { header: "Email", key: "email", width: 20 }, { header: "Mobile", key: "mobile", width: 20 }, { header: "Sender Name", key: "senderName", width: 20 }, { header: "Campaign Name", key: "campaignName", width: 40 }, { header: "Status", key: "status", width: 20 }, { header: "Message", key: "message", width: 160 }, ]; worksheet.getRow(1).eachCell((cell) => { cell.font = { bold: true }; }); var xlsxFileName = `${campaignId}.xlsx`; groupContacts.map(async (contact) => { //Email Type let message = customMessage || ""; var fields = mergeFields.split(","); var jsonObj = {}; fields.map((field) => { if (field.trim() == "First Name") { message = message.replace(/{{First Name}}/g, contact["first_name"]); } if (field.trim() == "Last Name") { message = message.replace(/{{Last Name}}/g, contact["last_name"]); } if (field.trim() == "Mobile Number") { message = message.replace(/{{Mobile Number}}/g, contact["mobile"]); } if (field.trim() == "Email") { message = message.replace(/{{Email}}/g, contact["email"]); } }); log.info( `[Custom Email campaign], [processCampaignPush],Campaign Name [${newname}], Sender ID [${senderIdDetails["emailid"]}], Campaign Id [${campaignId}], Group Id [${groupId}], Mobile [${contact["mobile"]}], First Name [${contact["first_name"]}], Last Name [${contact["last_name"]}], Type [Email], Template Name [${templateName}], Message [${message}]` ); var rowdata = { firstName: contact["first_name"], lastName: contact["last_name"], email: contact["email"], mobile: contact["mobile"], senderName: senderIdDetails["emailid"], campaignName: newname, status: "Sent", message: message, }; worksheet.addRow(rowdata); // reqLib.sendSMSWithDLR( // senderIdDetails["emailid"], // contact["mobile"], // userId, // campaignId, // message, // "MTN_BULK" // ); campaignEmailReport.createEmailCampaignReport( userId, contact["first_name"], contact["last_name"], contact["email"], campaignId, contact["name"], 1, senderIdDetails["emailid"], templateName, contact["mobile"], message, 1, subject ); log.info( `[campaign], [processCampaignPush],Campaign Name [${newname}], Sender ID [${senderIdDetails["emailid"]}], Campaign Id [${campaignId}], Group Id [${groupId}], Mobile [${contact["mobile"]}], First Name [${contact["first_name"]}], Last Name [${contact["last_name"]}], Email [${contact["email"]}] Type [EMAIL] Subject [${subject}] Message[${message}]` ); try { let transporter = nodemailer.createTransport({ host: process.env.EMAIL_HOST, port: process.env.EMAIL_PORT, secure: false, // auth: { // user: process.env.EMAIL_USER, // pass: process.env.EMAIL_PASS, // }, }); let attachments = []; if (file) { //let attachmentName = `attachment.${file?.mimetype.split("/")[1]}`; let splitByName = file?.originalname.split("."); let fileExtention = splitByName[splitByName.length-1]; let attachmentName = `attachment.${fileExtention}`; attachments = [ { filename: file?.originalname, path: `users/upload/emailAttachments/campaign/${campaignId}/${attachmentName}`, }, ]; } let fromEmail = `${senderIdDetails["emailid"]}<${process.env.EMAIL_SENDER}>`; let info = await transporter.sendMail({ from: fromEmail, // sender address to: contact["email"], // list of receivers subject: subject, // Subject line text: "", html: `

${message}

`, // html body attachments, }); log.info( `[Email Custom Campaign], [sendMail], Mail response [${JSON.stringify( info )}]` ); campaignEmailReport.updateEmailstatus( process.env.DELIVERED, contact["email"] ); campaignEmailReport.setCampaignCount(campaignId); combineEmailReport.createEmailCustomCombineReport( userId, campaignId, senderIdDetails["emailid"], contact["email"], message, process.env.DELIVERED, templateName ); } catch (mailErr) { log.info( `[Email Custom Campaign], [sendMail], Mail Error [${JSON.stringify( mailErr )}]` ); campaignEmailReport.updateEmailstatus( process.env.FAILED, contact["email"] ); combineEmailReport.createEmailCustomCombineReport( userId, campaignId, senderIdDetails["emailid"], contact["email"], message, process.env.FAILED, templateName ); } }); await campaign.setCampaignStatus(campaignId, 2); log.info( `[Custom Email campaign], [processCampaignPush], Campaign Id [${campaignId}], Campaign Name [${newname}], Campaign Ended` ); await workbook.xlsx.writeFile(`${path}/` + xlsxFileName); var fileUrl = `${config.FILEPATH_URL}/upload/campaign/${campaignId}/${xlsxFileName}`; await campaign.updateCampaignReport(fileUrl, campaignId); return resolve(true); } catch (error) { log.info( `[Custom Email campaign], [processCampaignPush], Campaign Id [${campaignId}], ERROR [${error}] ` ); } }); } var self = (module.exports = { runCustomEmailCampaign, processCampaignPush, });