Skip to content

Commit

Permalink
Implementação NotificameHub
Browse files Browse the repository at this point in the history
  • Loading branch information
rtenorioh committed Oct 14, 2024
1 parent addd9c4 commit 4cf78a3
Show file tree
Hide file tree
Showing 52 changed files with 2,474 additions and 367 deletions.
26 changes: 20 additions & 6 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"main": "index.js",
"scripts": {
"build": "tsc",
"migrate": "tsc && npx sequelize-cli db:migrate",
"migrate:undo": "tsc && npx sequelize-cli db:migrate:undo",
"watch": "tsc -w",
"start": "nodemon dist/server.js",
"dev:server": "ts-node-dev --respawn --transpile-only --ignore node_modules src/server.ts",
Expand All @@ -15,21 +17,29 @@
"author": "",
"license": "MIT",
"dependencies": {
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@sentry/node": "^5.29.2",
"@types/mime-types": "^2.1.4",
"@types/pino": "^6.3.4",
"axios": "^1.7.7",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
"date-fns": "^2.16.1",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"file-type": "^19.4.1",
"fluent-ffmpeg": "^2.1.3",
"http-graceful-shutdown": "^2.3.2",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"mime": "^4.0.4",
"mime-types": "^2.1.35",
"multer": "^1.4.2",
"mustache": "^4.2.0",
"mysql2": "^2.2.5",
"notificamehubsdk": "^0.0.19",
"openai": "^3.2.1",
"pg": "^8.4.1",
"pino": "^8.11.0",
Expand All @@ -41,9 +51,10 @@
"sequelize-cli": "^5.5.1",
"sequelize-typescript": "^1.1.0",
"socket.io": "^3.0.5",
"swagger-ui-express": "^4.3.0",
"whatsapp-web.js": "^1.25.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^4.6.3",
"uuid": "^8.3.2",
"whatsapp-web.js": "^1.25.0",
"yup": "^0.32.8"
},
"devDependencies": {
Expand All @@ -54,13 +65,15 @@
"@types/express": "^4.17.13",
"@types/factory-girl": "^5.0.2",
"@types/faker": "^5.1.3",
"@types/fluent-ffmpeg": "^2.1.21",
"@types/fluent-ffmpeg": "^2.1.26",
"@types/jest": "^26.0.15",
"@types/jsonwebtoken": "^8.5.0",
"@types/lodash": "^4.14.185",
"@types/multer": "^1.4.4",
"@types/mustache": "^4.1.2",
"@types/node": "^14.11.8",
"@types/node": "^14.18.63",
"@types/pino-pretty": "~4.7.1",
"@types/sequelize": "^4.28.20",
"@types/supertest": "^2.0.10",
"@types/swagger-ui-express": "^4.1.3",
"@types/uuid": "^8.3.3",
Expand All @@ -81,10 +94,11 @@
"prettier": "^2.1.2",
"supertest": "^5.0.0",
"ts-jest": "^26.4.1",
"ts-node": "^10.9.2",
"ts-node-dev": "^1.0.0-pre.63",
"typescript": "^4.8.3"
"typescript": "^4.9.5"
},
"engines": {
"node": ">=18.0.0"
}
}
}
6 changes: 6 additions & 0 deletions backend/sequelize-cli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"config": "src/config/database.ts",
"migrations-path": "src/database/migrations",
"models-path": "src/models",
"seeders-path": "src/database/seeders"
}
35 changes: 35 additions & 0 deletions backend/src/controllers/ChannelHubController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Request, Response } from "express";
import { setChannelWebhook } from "../helpers/setChannelHubWebhook";
import CreateChannelsService from "../services/HubServices/CreateHubChannelsService";
import ListChannels from "../services/HubServices/ListHubChannels";

export interface IChannel {
name: string;
status?: string;
isDefault?: boolean;
qrcode?: string;
type?: string;
channel?: string;
id?: string;
}

export const store = async (req: Request, res: Response): Promise<Response> => {
const { whatsapps } = await CreateChannelsService(req.body);

whatsapps.forEach(whatsapp => {
setTimeout(() => {
setChannelWebhook(whatsapp, whatsapp.id.toString());
}, 2000);
});

return res.status(200).json(whatsapps);
};

export const index = async (req: Request, res: Response): Promise<Response> => {
try {
const channels = await ListChannels();
return res.status(200).json(channels);
} catch (error) {
return res.status(500).json({ error });
}
};
62 changes: 33 additions & 29 deletions backend/src/controllers/ContactController.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import * as Yup from "yup";
import { Request, Response } from "express";
import * as Yup from "yup";
import { getIO } from "../libs/socket";

import ListContactsService from "../services/ContactServices/ListContactsService";
import CreateContactService from "../services/ContactServices/CreateContactService";
import DeleteAllContactService from "../services/ContactServices/DeleteAllContactService";
import DeleteContactService from "../services/ContactServices/DeleteContactService";
import ListContactsService from "../services/ContactServices/ListContactsService";
import ShowContactService from "../services/ContactServices/ShowContactService";
import UpdateContactService from "../services/ContactServices/UpdateContactService";
import DeleteContactService from "../services/ContactServices/DeleteContactService";
import DeleteAllContactService from "../services/ContactServices/DeleteAllContactService";

import CheckContactNumber from "../services/WbotServices/CheckNumber"
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";
import AppError from "../errors/AppError";
import GetContactService from "../services/ContactServices/GetContactService";
import CheckIsValidContact from "../services/WbotServices/CheckIsValidContact";
import CheckContactNumber from "../services/WbotServices/CheckNumber";
import GetProfilePicUrl from "../services/WbotServices/GetProfilePicUrl";

type IndexQuery = {
searchParam: string;
Expand All @@ -34,6 +34,9 @@ interface ContactData {
name: string;
number: string;
email?: string;
messengerId?: string;
instagramId?: string;
telegramId?: string;
extraInfo?: ExtraInfo[];
}

Expand All @@ -48,7 +51,10 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
return res.json({ contacts, count, hasMore });
};

export const getContact = async (req: Request, res: Response): Promise<Response> => {
export const getContact = async (
req: Request,
res: Response
): Promise<Response> => {
const { name, number, email } = req.body as IndexGetContactQuery;

const contact = await GetContactService({
Expand All @@ -62,13 +68,7 @@ export const getContact = async (req: Request, res: Response): Promise<Response>

export const store = async (req: Request, res: Response): Promise<Response> => {
const newContact: ContactData = req.body;
newContact.number = newContact.number.replace("-", "")
.replace(" ", "")
.replace("(", "")
.replace(")", "")
.replace("+", "")
.replace(".", "")
.replace("_", "");;
newContact.number = newContact.number.replace("-", "").replace(" ", "");

const schema = Yup.object().shape({
name: Yup.string().required(),
Expand All @@ -84,14 +84,14 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
}

await CheckIsValidContact(newContact.number);
const validNumber: any = await CheckContactNumber(newContact.number)
const validNumber: any = await CheckContactNumber(newContact.number);

const profilePicUrl = await GetProfilePicUrl(validNumber);

let name = newContact.name
let number = validNumber
let email = newContact.email
let extraInfo = newContact.extraInfo
let { name } = newContact;
let number = validNumber;
let { email } = newContact;
let { extraInfo } = newContact;

const contact = await CreateContactService({
name,
Expand Down Expand Up @@ -123,11 +123,11 @@ export const update = async (
const contactData: ContactData = req.body;

const schema = Yup.object().shape({
name: Yup.string(),
number: Yup.string().matches(
/^\d+$/,
"Invalid number format. Only numbers is allowed."
)
name: Yup.string()
// number: Yup.string().matches(
// /^\d+$/,
// "Invalid number format. Only numbers is allowed."
// )
});

try {
Expand All @@ -136,7 +136,13 @@ export const update = async (
throw new AppError(err.message);
}

await CheckIsValidContact(contactData.number);
if (
!contactData.messengerId &&
!contactData.instagramId &&
!contactData.telegramId
) {
await CheckIsValidContact(contactData.number);
}

const { contactId } = req.params;

Expand Down Expand Up @@ -172,9 +178,7 @@ export const removeAll = async (
req: Request,
res: Response
): Promise<Response> => {
const { contactId } = req.params;

await DeleteAllContactService();

return res.send();
};
};
96 changes: 96 additions & 0 deletions backend/src/controllers/MessageHubController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Request, Response } from "express";
import { getIO } from "../libs/socket";
import Contact from "../models/Contact";
import Ticket from "../models/Ticket";
import Whatsapp from "../models/Whatsapp";
import CreateHubTicketService from "../services/HubServices/CreateHubTicketService";
import { SendMediaMessageService } from "../services/HubServices/SendMediaMessageHubService";
import { SendTextMessageService } from "../services/HubServices/SendTextMessageHubService";

interface TicketData {
contactId: number;
status: string;
queueId: number;
userId: number;
channel: string;
}

export const send = async (req: Request, res: Response): Promise<Response> => {
const { body: message } = req.body;
const { ticketId } = req.params;
const medias = req.files as Express.Multer.File[];

const ticket = await Ticket.findByPk(ticketId, {
include: [
{
model: Contact,
as: "contact",
attributes: [
"number",
"email",
"messengerId",
"instagramId",
"telegramId",
"webchatId"
]
},
{
model: Whatsapp,
as: "whatsapp",
attributes: ["qrcode", "type"]
}
]
});

if (!ticket) {
return res.status(404).json({ message: "Ticket not found" });
}

try {
if (medias) {
await Promise.all(
medias.map(async (media: Express.Multer.File) => {
await SendMediaMessageService(
media,
message,
ticket.id,
ticket.contact,
ticket.whatsapp
);
})
);
} else {
await SendTextMessageService(
message,
ticket.id,
ticket.contact,
ticket.whatsapp
);
}

return res.status(200).json({ message: "Message sent" });
} catch (error) {
console.log(error);

return res.status(400).json({ message: error });
}
};

export const store = async (req: Request, res: Response): Promise<Response> => {
const { contactId, status, userId, channel }: TicketData = req.body;

const ticket = await CreateHubTicketService({
contactId,
status,
userId,
channel
});

const io = getIO();
io.to(ticket.status).emit("ticket", {
action: "update",
ticket
});

return res.status(200).json(ticket);
};
27 changes: 27 additions & 0 deletions backend/src/controllers/WebhookHubController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Request, Response } from "express";
import Whatsapp from "../models/Whatsapp";
import HubMessageListener from "../services/HubServices/HubMessageListener";

export const listen = async (
req: Request,
res: Response
): Promise<Response> => {
const medias = req.files as Express.Multer.File[];
const { channelId } = req.params;

const connection = await Whatsapp.findOne({
where: { qrcode: channelId }
});

if (!connection) {
return res.status(404).json({ message: "Whatsapp channel not found" });
}

try {
await HubMessageListener(req.body, connection, medias);

return res.status(200).json({ message: "Webhook received" });
} catch (error) {
return res.status(400).json({ message: error });
}
};
Loading

0 comments on commit 4cf78a3

Please sign in to comment.