import { Request, Response } from "express"; import { getIO } from "../libs/socket"; import { removeWbot } from "../libs/wbot"; import { StartWhatsAppSession } from "../services/WbotServices/StartWhatsAppSession"; import { removeDir } from "../helpers/DeleteDirectory"; import CreateWhatsAppService from "../services/WhatsappService/CreateWhatsAppService"; import DeleteWhatsAppService from "../services/WhatsappService/DeleteWhatsAppService"; import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService"; import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService"; import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppService"; import AppError from "../errors/AppError"; import getNumberFromName from "../helpers/GetNumberSequence"; import phoneNumberStart from "../helpers/PhoneNumberStatusCode"; import path, { join } from "path"; import validatePhoneName from "../helpers/ValidatePhoneName"; import postData from "../helpers/AxiosPost"; import Whatsapp from "../models/Whatsapp"; import Message from "../models/Message"; import FindOrCreateTicketService from "../services/TicketServices/FindOrCreateTicketService"; import { handleMessage, handleMsgAck, verifyContact, verifyMessage } from "../services/WbotServices/wbotMessageListener"; import Contact from "../models/Contact"; import CreateOrUpdateContactService from "../services/ContactServices/CreateOrUpdateContactService"; import GetDefaultWhatsApp from "../helpers/GetDefaultWhatsApp"; import ShowUserService from "../services/UserServices/ShowUserService"; import fs from "fs"; import receiveWhatsAppMediaOfficialAPI from "../helpers/ReceiveWhatsAppMediaOfficialAPI"; import whatsappOfficialAPI from "../helpers/WhatsappOfficialAPI"; import whatsappOfficialNumberInfo from "../helpers/WhatsappOfficialNumberInfo"; import { getSettingValue } from "../helpers/WhaticketSettings"; interface WhatsappData { name: string; queueIds: number[]; url: string; urlApi: string; greetingMessage?: string; farewellMessage?: string; status?: string; isDefault?: boolean; isOfficial?: boolean; phoneNumberId?: string; wabaId?: string; } let count: number = 0; export const index = async (req: Request, res: Response): Promise => { let whatsapps = await ListWhatsAppsService(); if (getSettingValue("whatsaAppCloudApi")?.value == "enabled") { // Atualizar isso quando tiver tempo if (count > 12) count = 0; if (count == 0) { for (let i in whatsapps) { const { id, wabaId, isOfficial } = whatsapps[i]; if (isOfficial && wabaId) { try { const info = await whatsappOfficialNumberInfo(wabaId); if (info) { const whatsapp = await Whatsapp.findByPk(id); if (whatsapp) { whatsapp.update({ classification: info.quality_rating }); whatsapps[i].classification = info.quality_rating; } } } catch (error) { console.log('error on try update classification number from oficial whatsapp in WhatsappController.ts: ', error) } } } } console.log("count: ", count); count++; } return res.status(200).json(whatsapps); }; export const whatsAppOfficialMatchQueue = async ( req: Request, res: Response ): Promise => { const { userId, queueId }: any = req.query; let whatsapps = await GetDefaultWhatsApp({ userId, queueId }); if (whatsapps && Array.isArray(whatsapps)) { const uniqueWhatsApps = whatsapps.filter( (whatsapp, index, self) => index === self.findIndex(w => w.number === whatsapp.number) ); whatsapps = uniqueWhatsApps; } return res.status(200).json(whatsapps); }; export const whatsAppOfficialMatchQueueUser = async ( req: Request, res: Response ): Promise => { const { userId, queueId }: any = req.query; let whatsApps: any = await ListWhatsAppsService(); let user: any = await ShowUserService(userId); // console.log(JSON.stringify(user, null, 2)); let queuesConnected = whatsApps .filter((w: any) => w.status === "CONNECTED") .map((item: any) => { const { queues } = item; return { queues: queues.map((q: any) => { return { id: q.id }; }) }; }) .flatMap((item: any) => item.queues.map((queue: any) => queue.id)); queuesConnected = [...new Set(queuesConnected)].map(q => { return { id: q }; }); const userQueues = user.queues.map((item: any) => { const { id, name, color } = item; return { id, name, color, disable: queuesConnected.find((queue: any) => queue.id === id) ? false : true }; }); return res.status(200).json(userQueues); }; export const media = async (req: Request, res: Response) => { const { filename } = req.params; const filePath = join(__dirname, "..", "..", "..", "..", "public", filename); console.log("filePath: ", filePath); console.log(filename); if (!fs.existsSync(filePath)) { return res.status(404).json({ message: "File not folund!" }); } // Set appropriate headers for the download. res.setHeader("Content-Disposition", `attachment; filename=${filename}`); res.sendFile(filePath); }; export const weebhook = async ( req: Request, res: Response ): Promise => { // console.log(JSON.stringify(req.body, null, 2)); console.log("req.method: ", req.method); if (req.method == "GET") { /** * UPDATE YOUR VERIFY TOKEN *This will be the Verify Token value when you set up webhook **/ const verify_token = process.env.VERIFY_TOKEN; // Parse params from the webhook verification request let mode = req.query["hub.mode"]; let token = req.query["hub.verify_token"]; let challenge = req.query["hub.challenge"]; // Check if a token and mode were sent if (mode && token) { // Check the mode and token sent are correct if (mode === "subscribe" && token === verify_token) { // Respond with 200 OK and challenge token from the request console.log("WEBHOOK_VERIFIED"); return res.status(200).send(challenge); } else { // Responds with '403 Forbidden' if verify tokens do not match return res.sendStatus(403); } } return res.sendStatus(500); } // MESSAGE if (req.body.object) { if ( req.body.entry && req.body.entry[0].changes && req.body.entry[0].changes[0] && req.body.entry[0].changes[0].value.messages && req.body.entry[0].changes[0].value.messages[0] ) { const message = req.body.entry[0].changes[0].value.messages[0]; const contact_from = message.from; // extract the phone number from the webhook payload const contact_to = req.body.entry[0].changes[0].value.metadata.display_phone_number; let type = message.type; let wbot = {}; let msg = {}; let contacts = req.body.entry[0].changes[0].value.contacts[0]; msg = { ...msg, id: { id: message.id }, fromMe: false, type: type, read: false, hasMedia: false }; // NEW const whatsapp = await ShowWhatsAppService(null, { number: contact_to }); if (type == "text") { type = "chat"; msg = { ...msg, body: message.text.body // extract the message text from the webhook payload, }; } else { const mediaId = message[message.type].id; const mimetype = message[message.type].mime_type; let filename = await receiveWhatsAppMediaOfficialAPI( mediaId, whatsapp.phoneNumberId ); if (!filename) throw new AppError("There was an error"); msg = { ...msg, hasMedia: true }; wbot = { ...wbot, media: { filename, mimetype } }; } console.log("from: ", contact_from); console.log("to: ", contact_to); console.log("msg type: ", type); wbot = { ...wbot, id: whatsapp.id, msgContact: { number: contact_from, name: contacts?.profile?.name }, chat: { isGroup: false, unreadCount: 1 }, quotedMsg: message && message?.context ? message.context.id : undefined }; handleMessage(msg, wbot, true); return res.sendStatus(200); } // STATUS MESSAGE SENT else if ( req.body.entry && req.body.entry[0].changes && req.body.entry[0].changes[0] && req.body.entry[0].changes[0].value.statuses && req.body.entry[0].changes[0].value.statuses[0] ) { const id = req.body.entry[0].changes[0].value.statuses[0].id; const ack = req.body.entry[0].changes[0].value.statuses[0].status; handleMsgAck(id, ack, true); } } return res.sendStatus(200); }; export const store = async (req: Request, res: Response): Promise => { let { name, status, isDefault, greetingMessage, farewellMessage, queueIds, url, urlApi, phoneNumberId, wabaId, isOfficial }: WhatsappData = req.body; if (req.user.profile !== "master") { throw new AppError("ERR_NO_PERMISSION", 403); } const invalid = checkWhatsAppData({ urlApi, isOfficial, phoneNumberId, wabaId }); if (invalid) { return res.status(400).json(invalid); } if (isOfficial) { urlApi = ""; url = ""; } else if (!isOfficial) { phoneNumberId = ""; wabaId = ""; } let invalidPhoneName = validatePhoneName(name); if (invalidPhoneName) { return res.status(200).json({ message: invalidPhoneName }); } const { whatsapp, oldDefaultWhatsapp } = await CreateWhatsAppService({ name, url, urlApi, status, isDefault, greetingMessage, farewellMessage, queueIds, phoneNumberId, wabaId, isOfficial }); console.log("whatsapp.id: ", whatsapp.id); if (!isOfficial) { postData(`${whatsapp.urlApi}/api/session`, { app_name: process.env.APP_NAME, whatsappId: whatsapp.id, number: getNumberFromName(name), client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); } const io = getIO(); io.emit("whatsapp", { action: "update", whatsapp }); if (oldDefaultWhatsapp) { io.emit("whatsapp", { action: "update", whatsapp: oldDefaultWhatsapp }); } return res.status(200).json(whatsapp); }; export const show = async (req: Request, res: Response): Promise => { const { whatsappId } = req.params; const whatsapp = await ShowWhatsAppService(whatsappId); return res.status(200).json(whatsapp); }; export const update = async ( req: Request, res: Response ): Promise => { const { whatsappId } = req.params; const whatsappData = req.body; let invalidPhoneName = validatePhoneName(whatsappData.name); if (invalidPhoneName) { return res.status(200).json({ message: invalidPhoneName }); } const { urlApi, isOfficial, phoneNumberId, wabaId } = whatsappData; const invalid = checkWhatsAppData({ urlApi, isOfficial, phoneNumberId, wabaId }); if (invalid) { return res.status(400).json(invalid); } if (isOfficial) { whatsappData.urlApi = ""; whatsappData.url = ""; } else if (!isOfficial) { whatsappData.phoneNumberId = ""; whatsappData.wabaId = ""; } const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({ whatsappData, whatsappId }); if (!whatsappData?.isOfficial) { postData(`${whatsapp.urlApi}/api/session`, { app_name: process.env.APP_NAME, whatsappId: whatsapp.id, number: getNumberFromName(whatsapp.name), client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); } const io = getIO(); io.emit("whatsapp", { action: "update", whatsapp }); if (oldDefaultWhatsapp) { io.emit("whatsapp", { action: "update", whatsapp: oldDefaultWhatsapp }); } return res.status(200).json(whatsapp); }; export const remove = async ( req: Request, res: Response ): Promise => { if (req.user.profile !== "master") { throw new AppError("ERR_NO_PERMISSION", 403); } const { whatsappId } = req.params; const whatsapp: any = await Whatsapp.findByPk(whatsappId, { raw: true }); if (!whatsapp?.isOfficial) { postData(`${whatsapp.urlApi}/api/session/del`, { app_name: process.env.APP_NAME, whatsappId: whatsappId }); } await DeleteWhatsAppService(whatsappId); removeDir( path.join(process.cwd(), ".wwebjs_auth", `session-bd_${whatsappId}`) ); removeDir( path.join( process.cwd(), ".wwebjs_auth", "sessions", `session-bd_${whatsappId}` ) ); removeWbot(+whatsappId); const io = getIO(); io.emit("whatsapp", { action: "delete", whatsappId: +whatsappId }); return res.status(200).json({ message: "Whatsapp deleted." }); }; interface WhatsappDataValidate { urlApi?: string; isOfficial?: boolean; phoneNumberId?: string; wabaId?: string; } const checkWhatsAppData = ({ urlApi, isOfficial, phoneNumberId, wabaId }: WhatsappDataValidate) => { if (isOfficial && (!phoneNumberId || phoneNumberId.trim() == "")) { return { message: "Phone number Id is required!" }; } else if (isOfficial && (!wabaId || wabaId.trim() == "")) { return { message: "WABA ID is required!" }; } else if (!isOfficial && (!urlApi || urlApi.trim() == "")) { return { message: "urlApi is required!" }; } };