diff --git a/backend/src/controllers/ImportPhoneContactsController.ts b/backend/src/controllers/ImportPhoneContactsController.ts new file mode 100644 index 0000000..34f193a --- /dev/null +++ b/backend/src/controllers/ImportPhoneContactsController.ts @@ -0,0 +1,38 @@ +// const Contact = require("../models/Contact"); +// const Whatsapp = require("../models/Whatsapp"); +// const { getIO } = require("../libs/socket"); +// const { getWbot, initWbot } = require("../libs/wbot"); + +// exports.store = async (req, res, next) => { +// const defaultWhatsapp = await Whatsapp.findOne({ +// where: { default: true } +// }); + +// if (!defaultWhatsapp) { +// return res +// .status(404) +// .json({ error: "No default WhatsApp found. Check Connection page." }); +// } + +// const io = getIO(); +// const wbot = getWbot(defaultWhatsapp); + +// let phoneContacts; + +// try { +// phoneContacts = await wbot.getContacts(); +// } catch (err) { +// console.log(err); +// return res.status(500).json({ +// error: "Could not check whatsapp contact. Check connection page." +// }); +// } + +// await Promise.all( +// phoneContacts.map(async ({ number, name }) => { +// await Contact.create({ number, name }); +// }) +// ); + +// return res.status(200).json({ message: "contacts imported" }); +// }; diff --git a/backend/src/controllers/MessageController.ts b/backend/src/controllers/MessageController.ts new file mode 100644 index 0000000..30c0975 --- /dev/null +++ b/backend/src/controllers/MessageController.ts @@ -0,0 +1,203 @@ +// const Message = require("../models/Message"); +// const Contact = require("../models/Contact"); +// const User = require("../models/User"); +// const Whatsapp = require("../models/Whatsapp"); + +// const Ticket = require("../models/Ticket"); +// const { getIO } = require("../libs/socket"); +// const { getWbot } = require("../libs/wbot"); +// const Sequelize = require("sequelize"); + +// const { MessageMedia } = require("whatsapp-web.js"); + +// const setMessagesAsRead = async ticket => { +// const io = getIO(); +// const wbot = getWbot(ticket.whatsappId); + +// await Message.update( +// { read: true }, +// { +// where: { +// ticketId: ticket.id, +// read: false, +// }, +// } +// ); + +// try { +// await wbot.sendSeen(`${ticket.contact.number}@c.us`); +// } catch (err) { +// console.log( +// "Could not mark messages as read. Maybe whatsapp session disconnected?" +// ); +// } + +// io.to("notification").emit("ticket", { +// action: "updateUnread", +// ticketId: ticket.id, +// }); +// }; + +// exports.index = async (req, res, next) => { +// const { ticketId } = req.params; +// const { searchParam = "", pageNumber = 1 } = req.query; + +// const whereCondition = { +// body: Sequelize.where( +// Sequelize.fn("LOWER", Sequelize.col("body")), +// "LIKE", +// "%" + searchParam.toLowerCase() + "%" +// ), +// }; + +// const limit = 20; +// const offset = limit * (pageNumber - 1); + +// const ticket = await Ticket.findByPk(ticketId, { +// include: [ +// { +// model: Contact, +// as: "contact", +// include: "extraInfo", +// attributes: ["id", "name", "number", "profilePicUrl"], +// }, +// { +// model: User, +// as: "user", +// }, +// ], +// }); + +// if (!ticket) { +// return res.status(404).json({ error: "No ticket found with this ID" }); +// } + +// await setMessagesAsRead(ticket); + +// const ticketMessages = await ticket.getMessages({ +// where: whereCondition, +// limit, +// offset, +// order: [["createdAt", "DESC"]], +// }); + +// const count = await ticket.countMessages(); + +// const serializedMessages = ticketMessages.map(message => { +// return { +// ...message.dataValues, +// mediaUrl: `${ +// message.mediaUrl +// ? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${message.mediaUrl}` +// : "" +// }`, +// }; +// }); + +// const hasMore = count > offset + ticketMessages.length; + +// return res.json({ +// messages: serializedMessages.reverse(), +// ticket, +// count, +// hasMore, +// }); +// }; + +// exports.store = async (req, res, next) => { +// const io = getIO(); + +// const { ticketId } = req.params; +// const message = req.body; +// const media = req.file; +// let sentMessage; + +// const ticket = await Ticket.findByPk(ticketId, { +// include: [ +// { +// model: Contact, +// as: "contact", +// attributes: ["number", "name", "profilePicUrl"], +// }, +// ], +// }); + +// if (!ticket) { +// return res.status(404).json({ error: "No ticket found with this ID" }); +// } + +// if (!ticket.whatsappId) { +// const defaultWhatsapp = await Whatsapp.findOne({ +// where: { default: true }, +// }); + +// if (!defaultWhatsapp) { +// return res +// .status(404) +// .json({ error: "No default WhatsApp found. Check Connection page." }); +// } + +// await ticket.setWhatsapp(defaultWhatsapp); +// } + +// const wbot = getWbot(ticket.whatsappId); + +// try { +// if (media) { +// const newMedia = MessageMedia.fromFilePath(req.file.path); + +// message.mediaUrl = req.file.filename; +// if (newMedia.mimetype) { +// message.mediaType = newMedia.mimetype.split("/")[0]; +// } else { +// message.mediaType = "other"; +// } + +// sentMessage = await wbot.sendMessage( +// `${ticket.contact.number}@c.us`, +// newMedia +// ); + +// await ticket.update({ lastMessage: message.mediaUrl }); +// } else { +// sentMessage = await wbot.sendMessage( +// `${ticket.contact.number}@c.us`, +// message.body +// ); +// await ticket.update({ lastMessage: message.body }); +// } +// } catch (err) { +// console.log( +// "Could not create whatsapp message. Is session details valid? " +// ); +// } + +// if (sentMessage) { +// message.id = sentMessage.id.id; +// const newMessage = await ticket.createMessage(message); + +// const serialziedMessage = { +// ...newMessage.dataValues, +// mediaUrl: `${ +// message.mediaUrl +// ? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${message.mediaUrl}` +// : "" +// }`, +// }; + +// io.to(ticketId).to("notification").emit("appMessage", { +// action: "create", +// message: serialziedMessage, +// ticket: ticket, +// contact: ticket.contact, +// }); + +// await setMessagesAsRead(ticket); + +// return res.status(200).json({ newMessage, ticket }); +// } + +// return res +// .status(500) +// .json({ error: "Cannot sent whatsapp message. Check connection page." }); +// }; diff --git a/backend/src/controllers/TicketController.ts b/backend/src/controllers/TicketController.ts index 6b43b3b..8186fe0 100644 --- a/backend/src/controllers/TicketController.ts +++ b/backend/src/controllers/TicketController.ts @@ -1,4 +1,7 @@ import { Request, Response } from "express"; +import GetDefaultWhatsapp from "../helpers/GetDefaultWhatsapp"; +import Ticket from "../models/Ticket"; +import CreateTicketService from "../services/TicketServices/CreateTicketService"; import ListTicketsService from "../services/TicketServices/ListTicketsService"; // const Sequelize = require("sequelize"); // const { startOfDay, endOfDay, parseISO } = require("date-fns"); @@ -10,9 +13,7 @@ import ListTicketsService from "../services/TicketServices/ListTicketsService"; // const { getIO } = require("../libs/socket"); -import Whatsapp from "../models/Whatsapp"; -import Ticket from "../models/Ticket"; -import Whatsapp from "../models/Whatsapp"; +// import FindWhatsAppService from "../services/WhatsappService/FindWhatsAppService"; type RequestQuery = { searchParam: string; @@ -93,28 +94,17 @@ export const index = async (req: Request, res: Response): Promise => { return res.status(200).json({ tickets, count, hasMore }); }; +interface TicketData { + contactId: number; + status: string; +} + export const store = async (req: Request, res: Response): Promise => { // const io = getIO(); - const defaultWhatsapp = await Whatsapp.findOne({ - where: { default: true } - }); + const { contactId, status }: TicketData = req.body; - const ticketData = req.body; - - if (!defaultWhatsapp) { - return res - .status(404) - .json({ error: "No default WhatsApp found. Check Connection page." }); - } - - const ticket: Ticket = await defaultWhatsapp.$create("ticket", req.body); - - await ticket.$get("contact"); - - const wapp = await ticket.$get("whatsapp"); - - const tickets = await wapp?.$get("tickets"); + const ticket = await CreateTicketService({ contactId, status }); // const serializaedTicket = { ...ticket.dataValues, contact: contact }; @@ -123,7 +113,7 @@ export const store = async (req: Request, res: Response): Promise => { // ticket: serializaedTicket // }); - return res.status(200).json({ ticket }); + return res.status(200).json(ticket); }; // export const update = (req: Request, res: Response): Promise => { diff --git a/backend/src/controllers/UserController.ts b/backend/src/controllers/UserController.ts index 062222c..07dbe64 100644 --- a/backend/src/controllers/UserController.ts +++ b/backend/src/controllers/UserController.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; -import CheckSettingsHelper from "../helpers/CheckSettingsHelper"; +import CheckSettingsHelper from "../helpers/CheckSettings"; import AppError from "../errors/AppError"; import CreateUserService from "../services/UserServices/CreateUserService"; diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index bc7627c..5cf4e17 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -3,7 +3,7 @@ import { Request, Response } from "express"; import CreateWhatsAppService from "../services/WhatsappService/CreateWhatsAppService"; import DeleteWhatsApprService from "../services/WhatsappService/DeleteWhatsApprService"; import ListWhatsAppsService from "../services/WhatsappService/ListWhatsAppsService"; -import ShowWhatsAppService from "../services/WhatsappService/ShowWhatsAppService"; +import FindWhatsAppService from "../services/WhatsappService/FindWhatsAppService"; import UpdateWhatsAppService from "../services/WhatsappService/UpdateWhatsAppService"; // import Yup from "yup"; // import Whatsapp from "../models/Whatsapp"; @@ -53,7 +53,7 @@ export const store = async (req: Request, res: Response): Promise => { export const show = async (req: Request, res: Response): Promise => { const { whatsappId } = req.params; - const whatsapp = await ShowWhatsAppService(whatsappId); + const whatsapp = await FindWhatsAppService(whatsappId); return res.status(200).json(whatsapp); }; diff --git a/backend/src/controllers/WhatsAppSessionController.ts b/backend/src/controllers/WhatsAppSessionController.ts new file mode 100644 index 0000000..38f5416 --- /dev/null +++ b/backend/src/controllers/WhatsAppSessionController.ts @@ -0,0 +1,32 @@ +// const Whatsapp = require("../models/Whatsapp"); +// const { getIO } = require("../libs/socket"); +// const { getWbot, initWbot, removeWbot } = require("../libs/wbot"); +// const wbotMessageListener = require("../services/wbotMessageListener"); +// const wbotMonitor = require("../services/wbotMonitor"); + +// exports.show = async (req, res) => { +// const { whatsappId } = req.params; +// const dbSession = await Whatsapp.findByPk(whatsappId); + +// if (!dbSession) { +// return res.status(200).json({ message: "Session not found" }); +// } + +// return res.status(200).json(dbSession); +// }; + +// exports.delete = async (req, res) => { +// const { whatsappId } = req.params; + +// const dbSession = await Whatsapp.findByPk(whatsappId); + +// if (!dbSession) { +// return res.status(404).json({ message: "Session not found" }); +// } + +// const wbot = getWbot(dbSession.id); + +// wbot.logout(); + +// return res.status(200).json({ message: "Session disconnected." }); +// }; diff --git a/backend/src/helpers/CheckSettingsHelper.ts b/backend/src/helpers/CheckSettings.ts similarity index 100% rename from backend/src/helpers/CheckSettingsHelper.ts rename to backend/src/helpers/CheckSettings.ts diff --git a/backend/src/helpers/GetDefaultWhatsapp.ts b/backend/src/helpers/GetDefaultWhatsapp.ts new file mode 100644 index 0000000..8c37e6b --- /dev/null +++ b/backend/src/helpers/GetDefaultWhatsapp.ts @@ -0,0 +1,17 @@ +import AppError from "../errors/AppError"; +import Whatsapp from "../models/Whatsapp"; +import FindWhatsAppService from "../services/WhatsappService/FindWhatsAppService"; + +const GetDefaultWhatsapp = async (): Promise => { + const defaultWhatsapp = await FindWhatsAppService({ + where: { isDefault: true } + }); + + if (!defaultWhatsapp) { + throw new AppError("No default WhatsApp found. Check Connection page."); + } + + return defaultWhatsapp; +}; + +export default GetDefaultWhatsapp; diff --git a/backend/src/routes/routes/whatsappsessions.js b/backend/src/routes/routes/whatsappsessions.js deleted file mode 100644 index 2eb87f9..0000000 --- a/backend/src/routes/routes/whatsappsessions.js +++ /dev/null @@ -1,20 +0,0 @@ -const express = require("express"); -const isAuth = require("../../middleware/is-auth"); - -const WhatsAppSessionController = require("../../controllers/WhatsAppSessionController"); - -const routes = express.Router(); - -routes.get( - "/whatsappsession/:whatsappId", - isAuth, - WhatsAppSessionController.show -); - -routes.delete( - "/whatsappsession/:whatsappId", - isAuth, - WhatsAppSessionController.delete -); - -module.exports = routes; diff --git a/backend/src/routes/whatsappSessionRoutes.ts b/backend/src/routes/whatsappSessionRoutes.ts new file mode 100644 index 0000000..ead10c2 --- /dev/null +++ b/backend/src/routes/whatsappSessionRoutes.ts @@ -0,0 +1,20 @@ +// const express = require("express"); +// const isAuth = require("../../middleware/is-auth"); + +// const WhatsAppSessionController = require("../../controllers/WhatsAppSessionController"); + +// const routes = express.Router(); + +// routes.get( +// "/whatsappsession/:whatsappId", +// isAuth, +// WhatsAppSessionController.show +// ); + +// routes.delete( +// "/whatsappsession/:whatsappId", +// isAuth, +// WhatsAppSessionController.delete +// ); + +// module.exports = routes; diff --git a/backend/src/services/ContactServices/ListContactsService.ts b/backend/src/services/ContactServices/ListContactsService.ts index 52c7f8a..f0ab9c9 100644 --- a/backend/src/services/ContactServices/ListContactsService.ts +++ b/backend/src/services/ContactServices/ListContactsService.ts @@ -16,6 +16,16 @@ const ListContactsService = async ({ searchParam = "", pageNumber = "1" }: Request): Promise => { + let includeCondition = [ + { + model: Contact, + as: "contact", + attributes: ["name", "number", "profilePicUrl"] + } + ]; + + // let whereCondition = {}; + const whereCondition = { [Op.or]: [ { @@ -33,6 +43,7 @@ const ListContactsService = async ({ const { count, rows: contacts } = await Contact.findAndCountAll({ where: whereCondition, + include: includeCondition, limit, offset, order: [["createdAt", "DESC"]] diff --git a/backend/src/services/TicketServices/CreateTicketService.ts b/backend/src/services/TicketServices/CreateTicketService.ts index d334989..2df4650 100644 --- a/backend/src/services/TicketServices/CreateTicketService.ts +++ b/backend/src/services/TicketServices/CreateTicketService.ts @@ -1,24 +1,34 @@ -import * as Yup from "yup"; - import AppError from "../../errors/AppError"; -import User from "../../models/User"; +import GetDefaultWhatsapp from "../../helpers/GetDefaultWhatsapp"; +import Ticket from "../../models/Ticket"; interface Request { - email: string; - password: string; - name: string; - profile?: string; + contactId: number; + status?: string; } -interface Response { - email: string; - name: string; - id: number; - profile: string; -} +const CreateTicketService = async ({ + contactId, + status +}: Request): Promise => { + const defaultWhatsapp = await GetDefaultWhatsapp(); -const CreateTicketService = async (): Promise => { - return true; + if (!defaultWhatsapp) { + throw new AppError("No default WhatsApp found. Check Connection page."); + } + + const { id } = await defaultWhatsapp.$create("ticket", { + contactId, + status + }); + + const ticket = await Ticket.findByPk(id, { include: ["contact"] }); + + if (!ticket) { + throw new AppError("Error, ticket not created."); + } + + return ticket; }; export default CreateTicketService; diff --git a/backend/src/services/TicketServices/FindTicketService.ts b/backend/src/services/TicketServices/FindTicketService.ts new file mode 100644 index 0000000..4846f61 --- /dev/null +++ b/backend/src/services/TicketServices/FindTicketService.ts @@ -0,0 +1,28 @@ +import Whatsapp from "../../models/Whatsapp"; +import AppError from "../../errors/AppError"; + +interface WhereParams { + id?: number; + name?: string; + isDefault?: boolean; +} + +interface Request { + where?: WhereParams; +} + +const FindTicketService = async ({ where }: Request): Promise => { + const whereCondition = { ...where }; + + const whatsapp = await Whatsapp.findOne({ + where: whereCondition + }); + + if (!whatsapp) { + throw new AppError("No whatsapp found with this conditions.", 404); + } + + return whatsapp; +}; + +export default FindTicketService; diff --git a/backend/src/services/TicketServices/ListTicketsService.ts b/backend/src/services/TicketServices/ListTicketsService.ts index 5fecc22..5b5d402 100644 --- a/backend/src/services/TicketServices/ListTicketsService.ts +++ b/backend/src/services/TicketServices/ListTicketsService.ts @@ -1,7 +1,9 @@ -import { Op } from "sequelize"; +import { Op, fn, where, col } from "sequelize"; import { startOfDay, endOfDay, parseISO } from "date-fns"; import Ticket from "../../models/Ticket"; +import Contact from "../../models/Contact"; +import Message from "../../models/Message"; interface Request { searchParam?: string; @@ -27,6 +29,15 @@ const ListTicketsService = async ({ userId }: Request): Promise => { let whereCondition = {}; + let includeCondition = []; + + includeCondition = [ + { + model: Contact, + as: "contact", + attributes: ["name", "number", "profilePicUrl"] + } + ]; if (showAll === "true") { whereCondition = {}; @@ -41,6 +52,46 @@ const ListTicketsService = async ({ }; } + if (searchParam) { + includeCondition = [ + ...includeCondition, + { + model: Message, + as: "messages", + attributes: ["id", "body"], + where: { + body: where( + fn("LOWER", col("body")), + "LIKE", + `%${searchParam.toLowerCase()}%` + ) + }, + required: false, + duplicating: false + } + ]; + + whereCondition = { + [Op.or]: [ + { + "$contact.name$": where( + fn("LOWER", col("name")), + "LIKE", + `%${searchParam.toLowerCase()}%` + ) + }, + { "$contact.number$": { [Op.like]: `%${searchParam}%` } }, + { + "$message.body$": where( + fn("LOWER", col("body")), + "LIKE", + `%${searchParam.toLowerCase()}%` + ) + } + ] + }; + } + if (date) { whereCondition = { ...whereCondition, @@ -55,8 +106,8 @@ const ListTicketsService = async ({ const { count, rows: tickets } = await Ticket.findAndCountAll({ where: whereCondition, - // distinct: true, - // include: includeCondition, + include: includeCondition, + distinct: true, limit, offset, order: [["updatedAt", "DESC"]] diff --git a/backend/src/services/WhatsappService/FindWhatsAppService.ts b/backend/src/services/WhatsappService/FindWhatsAppService.ts new file mode 100644 index 0000000..1f0d893 --- /dev/null +++ b/backend/src/services/WhatsappService/FindWhatsAppService.ts @@ -0,0 +1,30 @@ +import Whatsapp from "../../models/Whatsapp"; +import AppError from "../../errors/AppError"; + +interface WhereParams { + id?: number; + name?: string; + isDefault?: boolean; +} + +interface Request { + where?: WhereParams; +} + +const FindWhatsAppService = async ({ + where +}: Request): Promise => { + const whereCondition = { ...where }; + + const whatsapp = await Whatsapp.findOne({ + where: whereCondition + }); + + if (!whatsapp) { + throw new AppError("No whatsapp found with this conditions.", 404); + } + + return whatsapp; +}; + +export default FindWhatsAppService; diff --git a/backend/src/services/WhatsappService/ShowWhatsAppService.ts b/backend/src/services/WhatsappService/ShowWhatsAppService.ts deleted file mode 100644 index 00050fb..0000000 --- a/backend/src/services/WhatsappService/ShowWhatsAppService.ts +++ /dev/null @@ -1,18 +0,0 @@ -import Whatsapp from "../../models/Whatsapp"; -import AppError from "../../errors/AppError"; - -const ShowWhatsAppService = async ( - id: string -): Promise => { - const whatsapp = await Whatsapp.findOne({ - where: { id } - }); - - if (!whatsapp) { - throw new AppError("No whatsapp found with this ID.", 404); - } - - return whatsapp; -}; - -export default ShowWhatsAppService;