PK!A7��nconst contactGroup = require("../models/contactGroup"); const contact = require("../models/contact"); const campaign = require("../models/campaign"); const combineEmailReport = require("../models/combineEmailReport"); const senderIdModel = require("../models/senderId"); const emailTemplateModel = require("../models/emailTemplate"); const emailIdModel = require("../models/EmailId"); const callerIdModel = require("../models/callerId"); const accountCreditsModel = require("../models/accountCredits"); const smsTemplateModel = require("../models/smsTemplate"); const campaignReport = require("../models/campaignReport"); const campaignEmailReport = require("../models/campignEmailReport"); 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 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 common = require("../helper/common"); const mv = promisify(fs.rename); const formidable = require("formidable"); const nodemailer = require("nodemailer"); 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 deleteScheduledEmialCampaign(req, res) { try { var userId = req.headers["id"]; const campaignId = req.body.id; log.info( `[Email campaign], [deleteScheduledCampaign], User Id [${userId}], Campaign Id [${campaignId}]` ); const isExists = await campaign.checkCampaignId(campaignId); if (!isExists) { log.info( `[Email campaign], [deleteScheduledCampaign], Campaign Id [${campaignId}], [No Campaign Found]` ); return res.status(400).json({ msg: "No Campaign Found" }); } const isScheduledStatus = await campaign.checkScheduledStatus( userId, campaignId ); if (!isScheduledStatus) { log.info( `[Email campaign], [deleteScheduledCampaign], Campaign Id [${campaignId}], [Campaign Already Completed]` ); return res.status(400).json({ msg: "Campaign Already Completed" }); } const accountBal = await accountCreditsModel.checkAccountBal(userId); await campaign.deleteScheduledCampaignDB(userId, campaignId); await accountCreditsModel.addBalance( userId, accountBal?.email + isExists?.balance_consumed, "email" ); log.info( `[Email campaign], [deleteScheduledCampaign], Campaign Id [${campaignId}], [Campaign Deleted Successfully], Balance Added [${isExists?.balance_consumed}]` ); return res.status(200).json({ msg: "Campaign Deleted Successfully" }); } catch (e) { log.info(`[Email campaign], [deleteScheduledCampaign], Error [${e}]`); res.status(500).json(e); } } async function getEmailIdContactGroups(req, res) { try { var userId = req.headers["id"]; const param = req.params.param; log.info( `[Email campaign], [getEmailIdContactGroups], User Id [${userId}], For [${param === "custom" ? "Custom Email" : "Normal Email" }]` ); const emailSenderIds = await emailIdModel.getApprovedemalids(userId); const contactGroups = await contactGroup.getUserCompletedGroupList(userId); if (param === "custom") { const templates = await emailTemplateModel.getUserActiveEmailTemplates( userId ); log.info( `[Email campaign], [getEmailIdContactGroups], [Email Sender Ids, Email Templates & Contact Group List has been sent successfully]` ); res .status(200) .json({ emailSenderIds, contactGroups, templates: templates || [] }); } else { log.info( `[Email campaign], [getEmailIdContactGroups], [Email Sender Ids & Contact Group List has been sent successfully]` ); res.status(200).json({ emailSenderIds, contactGroups }); } } catch (e) { log.info(`[Email campaign], [getEmailIdContactGroups], Error [${e}]`); res.status(500).json(e); } } async function runcampaign(req, res) { try { let userId = req.headers["id"]; let { name, type, groupId, message, emailSenderId, isScheduled, scheduledAt, subject, } = req.body; const file = req.file; log.info( `[Email campaign], [runcampaign], User Id [${userId}], Name [${name}], Type [${type}], Group Id [${groupId}], EmailSender Id [${emailSenderId}], Message [${message} Subject[${subject}]` ); if (!name || !type || !groupId || !message || !emailSenderId || !subject) { log.info(`[Email campaign], [runcampaign], [Missing parameters]`); return res.status(400).json({ msg: "Missing parameters" }); } const isExists = await campaign.isCampaignNameExistsByUserId(name, userId); if (isExists) { log.info( `[Email campaign], [runcampaign], [Campaign Name is already exists]` ); return res.status(400).json({ msg: "Campaign Name is already exists" }); } 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( // `[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( "campaign", "runcampaign", accountBal, balanceConsumed, type ); if (!accountBal || !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( `[Email campaign], [runcampaign], [Missing parameters scheduledAt]` ); return res.status(400).json({ msg: "Missing parameters" }); } } if (contactLength > 0) { const emailSenderIdDetails = await emailIdModel.getemailIdById( emailSenderId ); if (false == emailSenderIdDetails) { log.info( `[Email campaign], [runcampaign], Group Id [${groupId}], Sender Id not found` ); return res.status(200).json({ msg: "No sender Id found" }); } const date = moment().format("YYYY-MM-DD"); const time = moment().format("hh:mm:ss"); const newname = name + "_" + date + "_" + time; let attachmentName = ""; if (file) { let splitByName = file?.originalname.split("."); let fileExtention = splitByName[splitByName.length - 1]; attachmentName = `attachment.${fileExtention}`; //attachmentName = `attachment.${file?.mimetype.split("/")[1]}`; } if (2 == isScheduled) { const campaignId = await campaign.addCampaign( userId, groupId, newname, message, type, emailSenderId, contactLength, balanceConsumed, attachmentName ); if (file) { log.info( `[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( `[Email campaign], [runcampaign], [Campaign started], Campaign Id [${campaignId}], Balance Consumed [${balanceConsumed}], Campaign Type [email], Group Id [${groupId}]` ); processCampaignPush( groupId, emailSenderId, campaignId, newname, type, message, subject, userId, file ); const NewAccountBal = await accountCreditsModel.checkAccountBal(userId); return res.status(200).json({ msg: "Campaign has been started", userCredit: NewAccountBal, }); } else { log.info( `[Email campaign], [BalanceConsumend], Balance Consumed [${balanceConsumed}], Campaign Type [email], ]` ); const campaignId = await campaign.addScheduledCampaign( userId, groupId, newname, message, type, emailSenderId, scheduledAt, isScheduled, contactLength, balanceConsumed, subject, attachmentName ); if (file) { log.info( `[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( `[Email campaign], [runcampaign], [Campaign Scheduled], Campaign Id [${campaignId}], Group Id [${groupId}], Scheduled At [${scheduledAt}]` ); await accountCreditsModel.deductBalance( userId, Math.abs(accountBal?.email - balanceConsumed), "email" ); log.info( `[Email campaign], [runcampaign], [Campaign Scheduled], Campaign Id [${campaignId}], Balance Consumed [${balanceConsumed}], Campaign Type [Email], Group Id [${groupId}]` ); const NewAccountBal = await accountCreditsModel.checkAccountBal(userId); return res.status(200).json({ msg: "Campaign has been scheduled", isScheduled, userCredit: NewAccountBal, }); } } else { log.info( `[Email campaign], [runcampaign], Group Id [${groupId}], No contacts found in the group` ); return res.status(200).json({ msg: "Please add contacts to the group." }); } } catch (e) { log.info(`[Email campaign], [runcampaign], Error [${e}]`); return res.status(500).json(e); } } async function processCampaignPush( groupId, emailSenderId, campaignId, newname, type, message, subject, userId, file ) { return new Promise(async (resolve, reject) => { let groupContacts = await contact.getCorrectEmailContactList(groupId); // if (groupContacts) { // groupContacts = groupContacts?.filter((contact) => contact.email); // } const emailSenderIdDetails = await emailIdModel.getemailIdById( emailSenderId ); //await campaign.setTotalSent(campaignId, groupContacts.length); log.info( `[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: "Phone Number", 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`; for (let index = 0; index < groupContacts?.length; index++) { const contact = groupContacts[index]; // groupContacts.map(async (contact, index) => { let mobile = contact["mobile"]; mobile = mobile.toString(); mobile = "260" + mobile.slice(mobile.length - 9, mobile.length); log.info( `[Email campaign], [processCampaignPush],Campaign Name [${newname}],EmailSenderId[${emailSenderIdDetails["emailid"]}] , Campaign Id [${campaignId}], Group Id [${groupId}], Mobile [${mobile}], First Name [${contact["first_name"]}], Last Name [${contact["last_name"]}], Email[${contact["email"]}], Type [Email], Message [${message}]` ); var rowdata = { firstName: contact["first_name"], lastName: contact["last_name"], email: contact["email"], mobile: mobile, senderName: emailSenderIdDetails["emailid"], campaignName: newname, status: "Sent", message: message, }; worksheet.addRow(rowdata); // reqLib.sendSMSWithDLR( // emailSenderIdDetails["emailid"], // mobile, // userId, // campaignId, // message, // "MTN_BULK" // ); campaignEmailReport.createEmailCampaignReport( userId, contact["first_name"], contact["last_name"], contact["email"], campaignId, contact["name"], process.env.EMAIL, emailSenderIdDetails["emailid"], "N", mobile, message, 1, subject ); 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 = `${emailSenderIdDetails["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}

`, attachments, }); log.info( `[Campaign Email], [sendMail], Mail response [${JSON.stringify( info )}]` ); campaignEmailReport.updateEmailstatus( process.env.DELIVERED, contact["email"] ); campaignEmailReport.setCampaignCount(campaignId); combineEmailReport.createEmailCampignCombineReport( userId, campaignId, emailSenderIdDetails["emailid"], contact["email"], message, process.env.DELIVERED, subject, contact["mobile"] ); } catch (mailErr) { log.info( `[Campaign Email], [sendMail], Mail Error [${JSON.stringify( mailErr )}]` ); campaignEmailReport.updateEmailstatus( process.env.FAILED, contact["email"] ); combineEmailReport.createEmailCampignCombineReport( userId, campaignId, emailSenderIdDetails["emailid"], contact["email"], message, process.env.FAILED, subject, contact["mobile"] ); } // let msgId = messageIdGen.generateMessageId(userId, campaignId); // reports.addMessageReport( // userId, // campaignId, // emailSenderIdDetails["emailid"], // message, // mobile, // msgId // ); if (index % process.env.EMAIL_PAUSE_COUNT == 0 && index != 0) { log.info( `--------------------THE LOOP IS PAUSED---------------------------` ); await pauser(process.env.EMAIL_PAUSE_TIME); } else { resolve(true); } } await campaign.setCampaignStatus(campaignId, 2); log.info( `[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); }); } const pauser = (time) => { return new Promise((resolve) => { setTimeout(() => { resolve(true); log.info( `--------------------THE LOOP STARTS AGAIN---------------------------` ); }, time); }); }; var self = (module.exports = { // getCampaigns, getEmailIdContactGroups, runcampaign, deleteScheduledEmialCampaign, });