From 9368ef25126fa30ed2da1182a408c3b766b89300 Mon Sep 17 00:00:00 2001 From: canove Date: Sat, 19 Sep 2020 22:49:27 -0300 Subject: [PATCH] started messages migration to ts --- backend/src/controllers/MessageController.ts | 353 +++++++++--------- backend/src/controllers/TicketController.ts | 25 +- backend/src/controllers/UserController.ts | 4 +- backend/src/controllers/WhatsAppController.ts | 2 +- backend/src/routes/messageRoutes.ts | 8 +- .../ContactServices/ListContactsService.ts | 11 - .../MessageServices/CreateMessageService.ts | 24 ++ .../MessageServices/ListMessagesService.ts | 60 +++ .../TicketServices/FindTicketService.ts | 35 +- .../TicketServices/ListTicketsService.ts | 3 +- 10 files changed, 295 insertions(+), 230 deletions(-) create mode 100644 backend/src/services/MessageServices/CreateMessageService.ts create mode 100644 backend/src/services/MessageServices/ListMessagesService.ts diff --git a/backend/src/controllers/MessageController.ts b/backend/src/controllers/MessageController.ts index 30c0975..c492e13 100644 --- a/backend/src/controllers/MessageController.ts +++ b/backend/src/controllers/MessageController.ts @@ -1,203 +1,188 @@ -// const Message = require("../models/Message"); -// const Contact = require("../models/Contact"); -// const User = require("../models/User"); -// const Whatsapp = require("../models/Whatsapp"); +import { Request, Response } from "express"; +import CreateMessageService from "../services/MessageServices/CreateMessageService"; +import ListMessagesService from "../services/MessageServices/ListMessagesService"; +// import Sequelize from "sequelize"; +// import { MessageMedia } from "whatsapp-web.js"; +// import Message from "../models/Message"; +// import Contact from "../models/Contact"; +// import User from "../models/User"; +// import Whatsapp from "../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"); +// import Ticket from "../models/Ticket"; +// import { getIO } from "../libs/socket"; +// import { getWbot } from "../libs/wbot"; // const setMessagesAsRead = async ticket => { -// const io = getIO(); -// const wbot = getWbot(ticket.whatsappId); +// const io = getIO(); +// const wbot = getWbot(ticket.whatsappId); -// await Message.update( -// { read: true }, -// { -// where: { -// ticketId: ticket.id, -// read: false, -// }, -// } -// ); +// 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?" -// ); -// } +// 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, -// }); +// 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; +type IndexQuery = { + searchParam: string; + pageNumber: string; +}; -// const whereCondition = { -// body: Sequelize.where( -// Sequelize.fn("LOWER", Sequelize.col("body")), -// "LIKE", -// "%" + searchParam.toLowerCase() + "%" -// ), -// }; +export const index = async (req: Request, res: Response): Promise => { + const { ticketId } = req.params; + const { searchParam, pageNumber } = req.query as IndexQuery; -// const limit = 20; -// const offset = limit * (pageNumber - 1); + const { count, messages, ticket, hasMore } = await ListMessagesService({ + searchParam, + pageNumber, + ticketId + }); -// const ticket = await Ticket.findByPk(ticketId, { -// include: [ -// { -// model: Contact, -// as: "contact", -// include: "extraInfo", -// attributes: ["id", "name", "number", "profilePicUrl"], -// }, -// { -// model: User, -// as: "user", -// }, -// ], -// }); + // const ticketMessages = await ticket.getMessages({ + // where: whereCondition, + // limit, + // offset, + // order: [["createdAt", "DESC"]] + // }); -// if (!ticket) { -// return res.status(404).json({ error: "No ticket found with this ID" }); -// } + // const count = await ticket.countMessages(); -// await setMessagesAsRead(ticket); + // const serializedMessages = ticketMessages.map(message => { + // return { + // ...message.dataValues, + // mediaUrl: `${ + // message.mediaUrl + // ? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${message.mediaUrl}` + // : "" + // }` + // }; + // }); -// const ticketMessages = await ticket.getMessages({ -// where: whereCondition, -// limit, -// offset, -// order: [["createdAt", "DESC"]], -// }); + // const hasMore = count > offset + ticketMessages.length; -// const count = await ticket.countMessages(); + // return res.json({ + // messages: serializedMessages.reverse(), + // ticket, + // count, + // hasMore + // }); + return res.json({ count, messages, ticket, hasMore }); +}; -// const serializedMessages = ticketMessages.map(message => { -// return { -// ...message.dataValues, -// mediaUrl: `${ -// message.mediaUrl -// ? `${process.env.BACKEND_URL}:${process.env.PROXY_PORT}/public/${message.mediaUrl}` -// : "" -// }`, -// }; -// }); +export const store = async (req: Request, res: Response): Promise => { + // const io = getIO(); -// const hasMore = count > offset + ticketMessages.length; + const { ticketId } = req.params; + const messageData = req.body; -// 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." }); + const message = await CreateMessageService({ messageData, ticketId }); + + // 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, + // contact: ticket.contact + // }); + + // await setMessagesAsRead(ticket); + + return res.status(200).json(message); +}; + +// 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 bad73ae..7684d47 100644 --- a/backend/src/controllers/TicketController.ts +++ b/backend/src/controllers/TicketController.ts @@ -1,23 +1,12 @@ import { Request, Response } from "express"; -import GetDefaultWhatsapp from "../helpers/GetDefaultWhatsapp"; -import Ticket from "../models/Ticket"; import CreateTicketService from "../services/TicketServices/CreateTicketService"; import DeleteTicketService from "../services/TicketServices/DeleteTicketService"; import ListTicketsService from "../services/TicketServices/ListTicketsService"; import UpdateTicketService from "../services/TicketServices/UpdateTicketService"; -// const Sequelize = require("sequelize"); -// const { startOfDay, endOfDay, parseISO } = require("date-fns"); - -// const Ticket = require("../models/Ticket"); -// const Contact = require("../models/Contact"); -// const Message = require("../models/Message"); -// const Whatsapp = require("../models/Whatsapp"); // const { getIO } = require("../libs/socket"); -// import FindWhatsAppService from "../services/WhatsappService/FindWhatsAppService"; - -type RequestQuery = { +type IndexQuery = { searchParam: string; pageNumber: string; status: string; @@ -25,6 +14,11 @@ type RequestQuery = { showAll: string; }; +interface TicketData { + contactId: number; + status: string; +} + export const index = async (req: Request, res: Response): Promise => { const { pageNumber, @@ -32,7 +26,7 @@ export const index = async (req: Request, res: Response): Promise => { date, searchParam, showAll - } = req.query as RequestQuery; + } = req.query as IndexQuery; const userId = req.user.id; @@ -96,11 +90,6 @@ 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 { contactId, status }: TicketData = req.body; diff --git a/backend/src/controllers/UserController.ts b/backend/src/controllers/UserController.ts index 14c0401..521a6eb 100644 --- a/backend/src/controllers/UserController.ts +++ b/backend/src/controllers/UserController.ts @@ -9,7 +9,7 @@ import UpdateUserService from "../services/UserServices/UpdateUserService"; import FindUserService from "../services/UserServices/FindUserService"; import DeleteUserService from "../services/UserServices/DeleteUserService"; -type RequestQuery = { +type IndexQuery = { searchParam: string; pageNumber: string; }; @@ -18,7 +18,7 @@ export const index = async (req: Request, res: Response): Promise => { if (req.user.profile !== "admin") { throw new AppError("Only administrators can access this route.", 403); // should be handled better. } - const { searchParam, pageNumber } = req.query as RequestQuery; + const { searchParam, pageNumber } = req.query as IndexQuery; const { users, count, hasMore } = await ListUsersService({ searchParam, diff --git a/backend/src/controllers/WhatsAppController.ts b/backend/src/controllers/WhatsAppController.ts index 9dca11f..38d1c8f 100644 --- a/backend/src/controllers/WhatsAppController.ts +++ b/backend/src/controllers/WhatsAppController.ts @@ -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 FindWhatsAppService(whatsappId); + const whatsapp = await FindWhatsAppService({ where: { id: +whatsappId } }); return res.status(200).json(whatsapp); }; diff --git a/backend/src/routes/messageRoutes.ts b/backend/src/routes/messageRoutes.ts index 59d81db..808ac6d 100644 --- a/backend/src/routes/messageRoutes.ts +++ b/backend/src/routes/messageRoutes.ts @@ -1,12 +1,12 @@ import { Router } from "express"; -// import isAuth from "../middleware/isAuth"; +import isAuth from "../middleware/isAuth"; -// import { index, store } from "../controllers/MessageController"; +import * as MessageController from "../controllers/MessageController"; const messageRoutes = Router(); -// messageRoutes.get("/messages/:ticketId", isAuth, index); +messageRoutes.get("/messages/:ticketId", isAuth, MessageController.index); -// messageRoutes.post("/messages/:ticketId", isAuth, store); +messageRoutes.post("/messages/:ticketId", isAuth, MessageController.store); export default messageRoutes; diff --git a/backend/src/services/ContactServices/ListContactsService.ts b/backend/src/services/ContactServices/ListContactsService.ts index f0ab9c9..52c7f8a 100644 --- a/backend/src/services/ContactServices/ListContactsService.ts +++ b/backend/src/services/ContactServices/ListContactsService.ts @@ -16,16 +16,6 @@ const ListContactsService = async ({ searchParam = "", pageNumber = "1" }: Request): Promise => { - let includeCondition = [ - { - model: Contact, - as: "contact", - attributes: ["name", "number", "profilePicUrl"] - } - ]; - - // let whereCondition = {}; - const whereCondition = { [Op.or]: [ { @@ -43,7 +33,6 @@ 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/MessageServices/CreateMessageService.ts b/backend/src/services/MessageServices/CreateMessageService.ts new file mode 100644 index 0000000..4a6c59e --- /dev/null +++ b/backend/src/services/MessageServices/CreateMessageService.ts @@ -0,0 +1,24 @@ +import Message from "../../models/Message"; +import FindTicketService from "../TicketServices/FindTicketService"; + +interface Request { + ticketId: string; + messageData: Message; +} + +const CreateMessageService = async ({ + messageData, + ticketId +}: Request): Promise => { + const ticket = await FindTicketService({ where: { id: +ticketId } }); + + if (!ticket) { + throw new Error("No ticket found with this ID"); + } + + const message = Message.create({ ...messageData, ticketId }); + + return message; +}; + +export default CreateMessageService; diff --git a/backend/src/services/MessageServices/ListMessagesService.ts b/backend/src/services/MessageServices/ListMessagesService.ts new file mode 100644 index 0000000..a4bc52c --- /dev/null +++ b/backend/src/services/MessageServices/ListMessagesService.ts @@ -0,0 +1,60 @@ +import { where, fn, col } from "sequelize"; +import Message from "../../models/Message"; +import Ticket from "../../models/Ticket"; +import FindTicketService from "../TicketServices/FindTicketService"; + +interface Request { + ticketId: string; + searchParam?: string; + pageNumber?: string; +} + +interface Response { + messages: Message[]; + ticket: Ticket; + count: number; + hasMore: boolean; +} + +const ListMessagesService = async ({ + searchParam = "", + pageNumber = "1", + ticketId +}: Request): Promise => { + const whereCondition = { + body: where( + fn("LOWER", col("body")), + "LIKE", + `%${searchParam.toLowerCase()}%` + ), + ticketId + }; + + const ticket = await FindTicketService({ where: { id: +ticketId } }); + + if (!ticket) { + throw new Error("No ticket found with this ID"); + } + + // await setMessagesAsRead(ticket); + const limit = 20; + const offset = limit * (+pageNumber - 1); + + const { count, rows: messages } = await Message.findAndCountAll({ + where: whereCondition, + limit, + offset, + order: [["createdAt", "DESC"]] + }); + + const hasMore = count > offset + messages.length; + + return { + messages: messages.reverse(), + ticket, + count, + hasMore + }; +}; + +export default ListMessagesService; diff --git a/backend/src/services/TicketServices/FindTicketService.ts b/backend/src/services/TicketServices/FindTicketService.ts index 4846f61..6490ebd 100644 --- a/backend/src/services/TicketServices/FindTicketService.ts +++ b/backend/src/services/TicketServices/FindTicketService.ts @@ -1,28 +1,45 @@ -import Whatsapp from "../../models/Whatsapp"; +import Ticket from "../../models/Ticket"; import AppError from "../../errors/AppError"; +import Contact from "../../models/Contact"; +import User from "../../models/User"; interface WhereParams { id?: number; - name?: string; - isDefault?: boolean; + status?: string; + userId?: number; + contactId?: number; + whatsappId?: number; } interface Request { where?: WhereParams; } -const FindTicketService = async ({ where }: Request): Promise => { +const FindTicketService = async ({ where }: Request): Promise => { const whereCondition = { ...where }; - const whatsapp = await Whatsapp.findOne({ - where: whereCondition + const ticket = await Ticket.findOne({ + where: whereCondition, + include: [ + { + model: Contact, + as: "contact", + attributes: ["id", "name", "number", "profilePicUrl"], + include: ["extraInfo"] + }, + { + model: User, + as: "user", + attributes: ["id", "name"] + } + ] }); - if (!whatsapp) { - throw new AppError("No whatsapp found with this conditions.", 404); + if (!ticket) { + throw new AppError("No ticket found with this conditions.", 404); } - return whatsapp; + return ticket; }; export default FindTicketService; diff --git a/backend/src/services/TicketServices/ListTicketsService.ts b/backend/src/services/TicketServices/ListTicketsService.ts index 5b5d402..ece7f91 100644 --- a/backend/src/services/TicketServices/ListTicketsService.ts +++ b/backend/src/services/TicketServices/ListTicketsService.ts @@ -35,7 +35,8 @@ const ListTicketsService = async ({ { model: Contact, as: "contact", - attributes: ["name", "number", "profilePicUrl"] + attributes: ["id", "name", "number", "profilePicUrl"], + include: ["extraInfo"] } ];