diff --git a/backend/src/controllers/MessageController.ts b/backend/src/controllers/MessageController.ts index 2016bca..9555e14 100644 --- a/backend/src/controllers/MessageController.ts +++ b/backend/src/controllers/MessageController.ts @@ -21,6 +21,7 @@ import sendWhatsAppMessageOfficialAPI from "../helpers/sendWhatsAppMessageOffici import Whatsapp from "../models/Whatsapp"; import checkLastClientMsg24hs from "../helpers/CheckLastClientMsg24hs"; import AppError from "../errors/AppError"; +import { get } from "../helpers/RedisClient"; type IndexQuery = { pageNumber: string; @@ -35,7 +36,7 @@ type MessageData = { params: any; }; -export const index = async (req: Request, res: Response): Promise => { +export const index = async (req: Request, res: Response): Promise => { const { ticketId } = req.params; const { pageNumber } = req.query as IndexQuery; @@ -97,7 +98,8 @@ export const store = async (req: Request, res: Response): Promise => { } const name = params.find((p: any) => p?.template_name); - const { language }: any = params?.find((p: any) => p?.language) || 'pt_BR' + const { language }: any = + params?.find((p: any) => p?.language) || "pt_BR"; const { template_name } = name; diff --git a/backend/src/controllers/QueueController.ts b/backend/src/controllers/QueueController.ts index 68b9854..493b951 100644 --- a/backend/src/controllers/QueueController.ts +++ b/backend/src/controllers/QueueController.ts @@ -5,14 +5,12 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService"; import ListQueuesService from "../services/QueueService/ListQueuesService"; import ShowQueueService from "../services/QueueService/ShowQueueService"; import UpdateQueueService from "../services/QueueService/UpdateQueueService"; -import Queue from "../models/Queue" -import AppError from "../errors/AppError" -import { get, set } from "../helpers/RedisClient"; - - +import Queue from "../models/Queue"; +import AppError from "../errors/AppError"; +import { del, get, set } from "../helpers/RedisClient"; export const index = async (req: Request, res: Response): Promise => { - const queues = await ListQueuesService(); + const queues = await ListQueuesService(); return res.status(200).json(queues); }; @@ -125,7 +123,7 @@ export const customization = async ( await set("ura", ura); - const _ura = await get("ura"); + const _ura = await get({ key: "ura", parse: true }); console.log("_URA: ", _ura); return res.status(200).json({ new_queues }); @@ -164,6 +162,8 @@ export const remove = async ( await DeleteQueueService(queueId); + await del(`queue:${queueId}`); + const io = getIO(); io.emit("queue", { action: "delete", diff --git a/backend/src/controllers/TicketController.ts b/backend/src/controllers/TicketController.ts index 13773b3..ce39f15 100644 --- a/backend/src/controllers/TicketController.ts +++ b/backend/src/controllers/TicketController.ts @@ -75,8 +75,21 @@ import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl"; import CreateContactService from "../services/ContactServices/CreateContactService"; import { botSendMessage } from "../services/WbotServices/wbotMessageListener"; import WhatsappQueue from "../models/WhatsappQueue"; +import { get } from "../helpers/RedisClient" + +export const index = async (req: Request, res: Response): Promise => { + + + const QueuesGreetingMessage = await get({ + key: "whatsapp:*", + value: "*1* - MESA DE SERVICIO" + }); + + console.log( + " TTTTTTTTTTTTTTTT EEEEEEEEEEEEE SSSSSSSSSSS TTTTTTTTTT KKKKKKKK: ", + QueuesGreetingMessage + ); -export const index = async (req: Request, res: Response): Promise => { const { pageNumber, status, diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index 3588ea0..3a0dda6 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -230,7 +230,10 @@ export const weebhook = async ( req.body.entry[0].changes[0].value.metadata.display_phone_number; let type = message.type; - const contact_to_exist = await get("whatsapp:*", `${contact_to}`); + const contact_to_exist = await get({ + key: "whatsapp:*", + value: `${contact_to}` + }); if (contact_to_exist == null) { console.log( @@ -408,7 +411,15 @@ export const store = async (req: Request, res: Response): Promise => { client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); } else { - await set(`whatsapp:${whatsapp.id}`, `${number}`); + await set( + `whatsapp:${whatsapp.id}`, + JSON.stringify({ + number: whatsapp?.number, + id: whatsapp?.id, + greetingMessage: whatsapp?.greetingMessage, + phoneNumberId: whatsapp?.phoneNumberId + }) + ); } const io = getIO(); @@ -484,7 +495,15 @@ export const update = async ( client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); } else { - await set(`whatsapp:${whatsapp.id}`, `${number}`); + await set( + `whatsapp:${whatsapp.id}`, + JSON.stringify({ + number: whatsapp?.number, + id: whatsapp?.id, + greetingMessage: whatsapp?.greetingMessage, + phoneNumberId: whatsapp?.phoneNumberId + }) + ); } const io = getIO(); diff --git a/backend/src/database/migrations/20240312130345-add-fromAgent-to-message.ts b/backend/src/database/migrations/20240312130345-add-fromAgent-to-message.ts new file mode 100644 index 0000000..39f1158 --- /dev/null +++ b/backend/src/database/migrations/20240312130345-add-fromAgent-to-message.ts @@ -0,0 +1,15 @@ +import { QueryInterface, DataTypes } from "sequelize"; + +module.exports = { + up: (queryInterface: QueryInterface) => { + return queryInterface.addColumn("Messages", "fromAgent", { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false + }); + }, + + down: (queryInterface: QueryInterface) => { + return queryInterface.removeColumn("Messages", "fromAgent"); + } +}; diff --git a/backend/src/helpers/BotIsOnQueue.ts b/backend/src/helpers/BotIsOnQueue.ts index 5955fb7..c534bb4 100644 --- a/backend/src/helpers/BotIsOnQueue.ts +++ b/backend/src/helpers/BotIsOnQueue.ts @@ -4,9 +4,8 @@ const fs = require("fs"); import ListUsersService from "../services/UserServices/ListUsersService"; import { get } from "./RedisClient"; -const _botIsOnQueue = async (botName: string) => { - - const botInfo = await get("botInfo"); +const _botIsOnQueue = async (botName: string) => { + const botInfo = await get({ key: "botInfo", parse: true }); if ( botInfo && @@ -19,8 +18,8 @@ const _botIsOnQueue = async (botName: string) => { botQueueId: botInfo.queueId, isOnQueue: botInfo.botIsOnQueue }; - } - return { userIdBot: null, botQueueId: null, isOnQueue: false }; + } + return { userIdBot: null, botQueueId: null, isOnQueue: false }; }; export default _botIsOnQueue; diff --git a/backend/src/helpers/RedisClient.ts b/backend/src/helpers/RedisClient.ts index e218e85..7154d15 100644 --- a/backend/src/helpers/RedisClient.ts +++ b/backend/src/helpers/RedisClient.ts @@ -8,6 +8,12 @@ type WhatsappData = { value?: string; }; +type getData = { + key: string; + value?: string; + parse?: boolean; +}; + export async function set(key: string, value: string | object) { if (typeof value == "object") await redis.set(key, JSON.stringify(value)); else { @@ -15,21 +21,30 @@ export async function set(key: string, value: string | object) { } } -export async function get(key: string, value?: string) { - if (key.includes("*")) { - const keys = await redis.keys(key); +export async function getSimple(key: string) { + const value: any = await redis.get(key); + return value; +} - // If there are keys, delete them +export async function get({ key, value, parse }: getData) { + if (key.includes("*")) { + const keys = await redis.keys(key); if (keys.length > 0) { for (const key of keys) { - const val = await redis.get(key); - if (value == val) return value; + const val = await redis.get(key); + if (val.includes(value)) { + if (parse) return JSON.parse(val); + return val; + } } } return null; } else { const value: any = await redis.get(key); - return JSON.parse(value); + + if (parse) return JSON.parse(value); + + return value; } } diff --git a/backend/src/models/Message.ts b/backend/src/models/Message.ts index 40fe9f8..7455195 100644 --- a/backend/src/models/Message.ts +++ b/backend/src/models/Message.ts @@ -31,6 +31,10 @@ class Message extends Model { @Column fromMe: boolean; + @Default(false) + @Column + fromAgent: boolean; + @Column(DataType.TEXT) body: string; diff --git a/backend/src/server.ts b/backend/src/server.ts index 5381d13..16c065a 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -27,6 +27,7 @@ import { clearAllKeys, get, set } from "./helpers/RedisClient"; import ShowUserService from "./services/UserServices/ShowUserService"; import { json } from "sequelize"; import { setBotInfo } from "./helpers/SetBotInfo"; +import Queue from "./models/Queue"; const server = app.listen(process.env.PORT, () => { logger.info(`Server started on port: ${process.env.PORT}`); @@ -47,7 +48,7 @@ gracefulShutdown(server); (async () => { console.log("os.tmpdir(): ", os.tmpdir()); - await clearAllKeys("user:*", "whatsapp:*"); + await clearAllKeys("user:*", "whatsapp:*", "queue:*"); const users = await User.findAll(); @@ -62,23 +63,37 @@ gracefulShutdown(server); await set(`user:${id}`, { id, name }); } + // const queues = await Queue.findAll(); + + // for (const queue of queues) { + // const { id, greetingMessage, name } = queue; + // await set(`queue:${id}`, { id, name, greetingMessage }); + // } + loadSettings(); let whatsapps: any = await Whatsapp.findAll({ - attributes: ["id", "url", "phoneNumberId", "number"] + attributes: ["id", "url", "phoneNumberId", "number", "greetingMessage"] }); if (whatsapps && whatsapps.length > 0) { for (let i = 0; i < whatsapps.length; i++) { try { - const { phoneNumberId } = whatsapps[i]; + const { phoneNumberId, id, greetingMessage } = whatsapps[i]; if (phoneNumberId) { await set( `whatsapp:${whatsapps[i].dataValues.id}`, - `${whatsapps[i].dataValues.number}` + JSON.stringify({ + number: whatsapps[i].dataValues.number, + id, + greetingMessage, + phoneNumberId + }) ); + } + if (phoneNumberId) { continue; } diff --git a/backend/src/services/MessageServices/CreateMessageService.ts b/backend/src/services/MessageServices/CreateMessageService.ts index 95af0e3..1c37495 100644 --- a/backend/src/services/MessageServices/CreateMessageService.ts +++ b/backend/src/services/MessageServices/CreateMessageService.ts @@ -13,6 +13,7 @@ interface MessageData { read?: boolean; mediaType?: string; mediaUrl?: string; + fromAgent?: boolean; } interface Request { messageData: MessageData; diff --git a/backend/src/services/QueueService/CreateQueueService.ts b/backend/src/services/QueueService/CreateQueueService.ts index b783da8..528d1b1 100644 --- a/backend/src/services/QueueService/CreateQueueService.ts +++ b/backend/src/services/QueueService/CreateQueueService.ts @@ -1,6 +1,7 @@ import * as Yup from "yup"; import AppError from "../../errors/AppError"; import Queue from "../../models/Queue"; +import { set } from "../../helpers/RedisClient"; interface QueueData { name: string; @@ -9,68 +10,67 @@ interface QueueData { } const CreateQueueService = async (queueData: QueueData): Promise => { - try { - const { color, name } = queueData; - const queueSchema = Yup.object().shape({ - name: Yup.string() - .min(2, "ERR_QUEUE_INVALID_NAME") - .required("ERR_QUEUE_INVALID_NAME") - .test( - "Check-unique-name", - "ERR_QUEUE_NAME_ALREADY_EXISTS", - async value => { - if (value) { - const queueWithSameName = await Queue.findOne({ - where: { name: value } - }); + const queueSchema = Yup.object().shape({ + name: Yup.string() + .min(2, "ERR_QUEUE_INVALID_NAME") + .required("ERR_QUEUE_INVALID_NAME") + .test( + "Check-unique-name", + "ERR_QUEUE_NAME_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameName = await Queue.findOne({ + where: { name: value } + }); - return !queueWithSameName; + return !queueWithSameName; + } + return false; + } + ), + color: Yup.string() + .required("ERR_QUEUE_INVALID_COLOR") + .test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => { + if (value) { + const colorTestRegex = /^#[0-9a-f]{3,6}$/i; + return colorTestRegex.test(value); } return false; - } - ), - color: Yup.string() - .required("ERR_QUEUE_INVALID_COLOR") - .test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => { - if (value) { - const colorTestRegex = /^#[0-9a-f]{3,6}$/i; - return colorTestRegex.test(value); - } - return false; - }) - .test( - "Check-color-exists", - "ERR_QUEUE_COLOR_ALREADY_EXISTS", - async value => { - if (value) { - const queueWithSameColor = await Queue.findOne({ - where: { color: value } - }); - return !queueWithSameColor; + }) + .test( + "Check-color-exists", + "ERR_QUEUE_COLOR_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameColor = await Queue.findOne({ + where: { color: value } + }); + return !queueWithSameColor; + } + return false; } - return false; - } - ) - }); + ) + }); - try { - await queueSchema.validate({ color, name }); - } catch (err: any) { - throw new AppError(err.message); - } + try { + await queueSchema.validate({ color, name }); + } catch (err: any) { + throw new AppError(err.message); + } - const queue = await Queue.create(queueData); + const queue = await Queue.create(queueData); - return queue; + // const { id, greetingMessage } = queue; + // await set(`queue:${id}`, { id, name, greetingMessage }); + return queue; } catch (error: any) { - console.error('===> Error on CreateQueueService.ts file: \n', error) + console.error("===> Error on CreateQueueService.ts file: \n", error); throw new AppError(error.message); } - }; export default CreateQueueService; diff --git a/backend/src/services/QueueService/UpdateQueueService.ts b/backend/src/services/QueueService/UpdateQueueService.ts index d52da18..59a6077 100644 --- a/backend/src/services/QueueService/UpdateQueueService.ts +++ b/backend/src/services/QueueService/UpdateQueueService.ts @@ -3,6 +3,7 @@ import * as Yup from "yup"; import AppError from "../../errors/AppError"; import Queue from "../../models/Queue"; import ShowQueueService from "./ShowQueueService"; +import { set } from "../../helpers/RedisClient" interface QueueData { name?: string; @@ -14,9 +15,7 @@ const UpdateQueueService = async ( queueId: number | string, queueData: QueueData ): Promise => { - try { - const { color, name } = queueData; const queueSchema = Yup.object().shape({ @@ -30,7 +29,7 @@ const UpdateQueueService = async ( const queueWithSameName = await Queue.findOne({ where: { name: value, id: { [Op.not]: queueId } } }); - + return !queueWithSameName; } return true; @@ -59,24 +58,25 @@ const UpdateQueueService = async ( } ) }); - + try { await queueSchema.validate({ color, name }); } catch (err: any) { throw new AppError(err.message); } - + const queue = await ShowQueueService(queueId); - + await queue.update(queueData); - + + // const { id, greetingMessage } = queue; + // await set(`queue:${id}`, { id, name, greetingMessage }); + return queue; - } catch (error: any) { - console.error('===> Error on UpdateQueueService.ts file: \n', error) + console.error("===> Error on UpdateQueueService.ts file: \n", error); throw new AppError(error.message); - } - + } }; export default UpdateQueueService; diff --git a/backend/src/services/WbotServices/CheckIsValidContact.ts b/backend/src/services/WbotServices/CheckIsValidContact.ts index bb1496c..cf9afec 100644 --- a/backend/src/services/WbotServices/CheckIsValidContact.ts +++ b/backend/src/services/WbotServices/CheckIsValidContact.ts @@ -29,9 +29,7 @@ const CheckIsValidContact = async ( try { let _status: any; - if (!isValidNumber) { - - console.log('kkkkkkkkkkkkkkkkkkkkkkkkkkkkk ') + if (!isValidNumber) { const { data, status } = await axios.post( `${process.env.WHATS_NUMBER_VALIDATOR_URL}/api/validate`, diff --git a/backend/src/services/WbotServices/wbotMessageListener.ts b/backend/src/services/WbotServices/wbotMessageListener.ts index d838b00..f4e006a 100644 --- a/backend/src/services/WbotServices/wbotMessageListener.ts +++ b/backend/src/services/WbotServices/wbotMessageListener.ts @@ -92,7 +92,8 @@ import { createObject, findByContain, findObject, - get + get, + getSimple } from "../../helpers/RedisClient"; import FindOrCreateTicketServiceBot from "../TicketServices/FindOrCreateTicketServiceBot"; import ShowTicketService from "../TicketServices/ShowTicketService"; @@ -175,9 +176,14 @@ const verifyMediaMessage = async ( mediaUrl: media.filename, mediaType: media.mimetype.split("/")[0], quotedMsgId: quotedMsg, - phoneNumberId: msg?.phoneNumberId + phoneNumberId: msg?.phoneNumberId, + fromAgent: false }; + if (msg?.fromMe) { + messageData = { ...messageData, fromAgent: true }; + } + if (!ticket?.phoneNumberId) { if (!media.filename) { const ext = media.mimetype.split("/")[1].split(";")[0]; @@ -280,18 +286,33 @@ const verifyMessage = async ( contact: Contact, quotedMsg?: any ) => { - const messageData = { + let messageData = { id: msg.id.id, ticketId: ticket.id, contactId: msg.fromMe ? undefined : contact.id, body: msg.body, fromMe: msg.fromMe, + fromAgent: false, mediaType: msg.type, read: msg.fromMe, quotedMsgId: quotedMsg, phoneNumberId: msg?.phoneNumberId }; + if (msg?.fromMe) { + const botInfo = await BotIsOnQueue("botqueue"); + + if (botInfo.isOnQueue) { + const ura: any = await get({ key: "ura" }); + + if (ura && !ura.includes(JSON.stringify(msg?.body))) { + messageData = { ...messageData, fromAgent: true }; + } + } else if (msg?.body?.trim().length > 0 && !/\u200e/.test(msg.body[0])) { + messageData = { ...messageData, fromAgent: true }; + } + } + await ticket.update({ lastMessage: msg.body }); await CreateMessageService({ messageData }); @@ -349,7 +370,7 @@ const verifyQueue = async ( ticketId: ticket.id }); - const data = await get("ura"); + const data = await get({ key: "ura", parse: true }); await createObject({ whatsappId: `${ticket.whatsappId}`, @@ -965,7 +986,7 @@ const handleMessage = async ( const menu = async (userTyped: string, whatsappId: any, contactId: any) => { let lastId = await findObject(whatsappId, contactId, "ura"); - const data: any = await get("ura"); + const data: any = await get({ key: "ura", parse: true }); console.log("lastId[0]: ", lastId[0]);