From 2fc732eec17dd9d18fbeacb7bea4daaf8712f798 Mon Sep 17 00:00:00 2001 From: adriano Date: Wed, 6 Mar 2024 18:14:12 -0300 Subject: [PATCH] feat: Implement Redis solution for querying WhatsApp number in webhook controller --- backend/src/controllers/UserController.ts | 44 +++++----------- backend/src/controllers/WhatsAppController.ts | 22 ++++++++ backend/src/helpers/RedisClient.ts | 51 ++++++++++++------- backend/src/helpers/SetBotInfo.ts | 33 ++++++++++++ backend/src/server.ts | 26 ++++++++-- .../WhatsappService/UpdateWhatsAppService.ts | 3 ++ 6 files changed, 127 insertions(+), 52 deletions(-) create mode 100644 backend/src/helpers/SetBotInfo.ts diff --git a/backend/src/controllers/UserController.ts b/backend/src/controllers/UserController.ts index 88d463a..c4463aa 100644 --- a/backend/src/controllers/UserController.ts +++ b/backend/src/controllers/UserController.ts @@ -27,6 +27,7 @@ import { splitDateTime } from "../helpers/SplitDateTime"; import ListUserByWhatsappQueuesService from "../services/UserServices/ListUserByWhatsappQueuesService"; import { json } from "sequelize"; import { getSettingValue } from "../helpers/WhaticketSettings"; +import { setBotInfo } from "../helpers/SetBotInfo" type IndexQuery = { searchParam: string; @@ -110,8 +111,7 @@ export const all = async (req: Request, res: Response): Promise => { getSettingValue("queueTransferByWhatsappScope")?.value ); - if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") { - + if (getSettingValue("queueTransferByWhatsappScope")?.value == "enabled") { if (!userId) return res.json({ users: [], queues: [] }); const obj = await ListUserByWhatsappQueuesService( @@ -122,7 +122,7 @@ export const all = async (req: Request, res: Response): Promise => { const usersByWhatsqueue = obj.users; const queues = obj.queues; - let userIds = usersByWhatsqueue.map((w: any) => w.userId); + let userIds = usersByWhatsqueue.map((w: any) => w.userId); const users = await ListUser({ userIds @@ -167,6 +167,11 @@ export const store = async (req: Request, res: Response): Promise => { queueIds }); + if (user) { + const { id, name } = user; + await set(`user:${id}`, { id, name }); + } + const io = getIO(); io.emit("user", { action: "create", @@ -270,34 +275,11 @@ export const update = async ( let user: any = await UpdateUserService({ userData, userId }); - if (user?.name?.trim() == "botqueue") { - let botInfo; + await setBotInfo(user) - if ( - user?.queues?.length > 0 && - user.queues[0]?.name?.trim() == "botqueue" - ) { - botInfo = JSON.stringify({ - userId: user.id, - queueId: user.queues[0].id, - botIsOnQueue: true - }); - botInfo = JSON.parse(botInfo); - - await set("botInfo", botInfo); - } else if ( - user?.queues?.length == 0 || - user.queues[0]?.name?.trim() != "botqueue" - ) { - botInfo = JSON.stringify({ - userId: user.id, - queueId: 0, - botIsOnQueue: false - }); - botInfo = JSON.parse(botInfo); - - await set("botInfo", botInfo); - } + if (user) { + const { id, name } = user; + await set(`user:${id}`, { id, name }); } const io = getIO(); @@ -342,3 +324,5 @@ export const remove = async ( return res.status(200).json({ message: "User deleted" }); }; + + diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index ca61d34..014fc20 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -42,6 +42,7 @@ import { getSettingValue } from "../helpers/WhaticketSettings"; import ListWhatsAppsNumber from "../services/WhatsappService/ListWhatsAppsNumber"; import SettingTicket from "../models/SettingTicket"; import { Op } from "sequelize"; +import { get, set } from "../helpers/RedisClient"; interface WhatsappData { name: string; @@ -229,6 +230,22 @@ export const weebhook = async ( req.body.entry[0].changes[0].value.metadata.display_phone_number; let type = message.type; + const contact_from_exist = await get("whatsapp:*", `${contact_from}`); + + if (!contact_from_exist) { + console.log( + "WHATSAPP OFFICIAL", + " | CONCTACT_FROM: ", + contact_from, + " | CONTACT_TO: ", + contact_to + ); + console.log( + "NUMBER IGNORED. WHATSAPP NUMBER FROM ANOTHER OMNIHIT APPLICATION!" + ); + return res.status(403).json({ error: "Unauthorized" }); + } + let wbot = {}; let msg = {}; let contacts = req.body.entry[0].changes[0].value.contacts[0]; @@ -382,6 +399,8 @@ export const store = async (req: Request, res: Response): Promise => { number: getNumberFromName(name), client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); + } else { + await set(`whatsapp:${whatsapp.id}`, `${number}`); } const io = getIO(); @@ -441,6 +460,7 @@ export const update = async ( } else if (!isOfficial) { whatsappData.phoneNumberId = ""; whatsappData.wabaId = ""; + whatsappData.number = ""; } const { whatsapp, oldDefaultWhatsapp } = await UpdateWhatsAppService({ @@ -455,6 +475,8 @@ export const update = async ( number: getNumberFromName(whatsapp.name), client_url: `${process.env.BACKEND_URL_RAW}:${process.env.PORT}` }); + } else { + await set(`whatsapp:${whatsapp.id}`, `${number}`); } const io = getIO(); diff --git a/backend/src/helpers/RedisClient.ts b/backend/src/helpers/RedisClient.ts index 93c9e0a..c1cb419 100644 --- a/backend/src/helpers/RedisClient.ts +++ b/backend/src/helpers/RedisClient.ts @@ -9,25 +9,42 @@ type WhatsappData = { }; export async function set(key: string, value: string | object) { - await redis.set(key, JSON.stringify(value)); -} - -export async function get(key: string) { - const value: any = await redis.get(key); - return JSON.parse(value); -} - -export async function clearAllKeys() { - // Retrieve all keys matching the pattern '*' - const keys = await redis.keys("user:*"); - - // If there are keys, delete them - if (keys.length > 0) { - console.log('keys: ', keys) - await redis.del(...keys); + if (typeof value == "object") await redis.set(key, JSON.stringify(value)); + else { + await redis.set(key, value); } } +export async function get(key: string, value?: string) { + if (key.includes("*")) { + const keys = await redis.keys(key); + + // If there are keys, delete them + if (keys.length > 0) { + for (const key of keys) { + const val = await redis.get(key); + if (value == val) return value; + } + } + return null; + } else { + const value: any = await redis.get(key); + return JSON.parse(value); + } +} + +export async function clearAllKeys(...keys: string[]) { + for (const key of keys) { + // Retrieve all keys matching the pattern '*' + const del_keys = await redis.keys(key); + + // If there are keys, delete them + if (del_keys.length > 0) { + console.log("del_keys: ", del_keys); + await redis.del(...del_keys); + } + } +} export async function findByContain( key: string, @@ -54,7 +71,7 @@ export async function findByContain( results.push(obj); } } - } + } return results; } diff --git a/backend/src/helpers/SetBotInfo.ts b/backend/src/helpers/SetBotInfo.ts new file mode 100644 index 0000000..04dfd6b --- /dev/null +++ b/backend/src/helpers/SetBotInfo.ts @@ -0,0 +1,33 @@ +import { get, set } from "../helpers/RedisClient"; + +export async function setBotInfo(user: any) { + if (user?.name?.trim() == "botqueue") { + let botInfo; + + if ( + user?.queues?.length > 0 && + user.queues[0]?.name?.trim() == "botqueue" + ) { + botInfo = JSON.stringify({ + userId: user.id, + queueId: user.queues[0].id, + botIsOnQueue: true + }); + botInfo = JSON.parse(botInfo); + + await set("botInfo", botInfo); + } else if ( + user?.queues?.length == 0 || + user.queues[0]?.name?.trim() != "botqueue" + ) { + botInfo = JSON.stringify({ + userId: user.id, + queueId: 0, + botIsOnQueue: false + }); + botInfo = JSON.parse(botInfo); + + await set("botInfo", botInfo); + } + } +} diff --git a/backend/src/server.ts b/backend/src/server.ts index 6aa0b13..5381d13 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -23,7 +23,10 @@ import fs from "fs"; import dir from "path"; import { getSettingValue } from "./helpers/WhaticketSettings"; import loadSettings from "./helpers/LoadSettings"; -import { clearAllKeys, set } from "./helpers/RedisClient"; +import { clearAllKeys, get, set } from "./helpers/RedisClient"; +import ShowUserService from "./services/UserServices/ShowUserService"; +import { json } from "sequelize"; +import { setBotInfo } from "./helpers/SetBotInfo"; const server = app.listen(process.env.PORT, () => { logger.info(`Server started on port: ${process.env.PORT}`); @@ -39,24 +42,30 @@ const server = app.listen(process.env.PORT, () => { initIO(server); // StartAllWhatsAppsSessions(); -gracefulShutdown(server); +gracefulShutdown(server); (async () => { console.log("os.tmpdir(): ", os.tmpdir()); - await clearAllKeys(); + await clearAllKeys("user:*", "whatsapp:*"); const users = await User.findAll(); for (const user of users) { const { id, name } = user; + + if (name == "botqueue") { + const userService = await ShowUserService(id); + await setBotInfo(userService); + } + await set(`user:${id}`, { id, name }); } loadSettings(); let whatsapps: any = await Whatsapp.findAll({ - attributes: ["id", "url", "phoneNumberId"] + attributes: ["id", "url", "phoneNumberId", "number"] }); if (whatsapps && whatsapps.length > 0) { @@ -64,7 +73,14 @@ gracefulShutdown(server); try { const { phoneNumberId } = whatsapps[i]; - if (phoneNumberId) continue; + if (phoneNumberId) { + await set( + `whatsapp:${whatsapps[i].dataValues.id}`, + `${whatsapps[i].dataValues.number}` + ); + + continue; + } console.log( `API URL: ${whatsapps[i].dataValues.url}/api/connection/status` diff --git a/backend/src/services/WhatsappService/UpdateWhatsAppService.ts b/backend/src/services/WhatsappService/UpdateWhatsAppService.ts index 982407b..3487d15 100644 --- a/backend/src/services/WhatsappService/UpdateWhatsAppService.ts +++ b/backend/src/services/WhatsappService/UpdateWhatsAppService.ts @@ -22,6 +22,7 @@ interface WhatsappData { greetingMessage?: string; farewellMessage?: string; queueIds?: number[]; + number?:string; } interface Request { @@ -52,6 +53,7 @@ const UpdateWhatsAppService = async ({ phoneNumberId, wabaId, isOfficial, + number, url, urlApi, session, @@ -116,6 +118,7 @@ const UpdateWhatsAppService = async ({ isOfficial, phoneNumberId, wabaId, + number, classification });