From 4f3f1dd484fddb398559fe798259740d26c326b1 Mon Sep 17 00:00:00 2001 From: Cassio Santos Date: Mon, 1 Jun 2020 10:29:34 -0300 Subject: [PATCH] maintenance commit --- backend/.gitignore | 3 +- backend/app.js | 27 +- backend/controllers/auth.js | 2 +- backend/controllers/contact.js | 36 +- backend/controllers/message.js | 88 +++-- backend/controllers/session.json | 2 +- backend/controllers/wbotMessageListener.js | 63 ++- backend/middleware/is-auth.js | 2 +- backend/models/Contact.js | 12 +- backend/models/Message.js | 2 + backend/package-lock.json | 423 ++++++++++++++++----- backend/package.json | 9 +- backend/routes/message.js | 5 - backend/util/database.js | 4 + frontend/package-lock.json | 22 ++ frontend/package.json | 3 + frontend/src/pages/Chat/Chat.js | 52 ++- frontend/src/pages/ChatBox/ChatBox.css | 153 +++++--- frontend/src/pages/ChatBox/ChatBox.js | 311 ++++++++++++--- 19 files changed, 926 insertions(+), 293 deletions(-) diff --git a/backend/.gitignore b/backend/.gitignore index b512c09..7ba46c6 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +public/* \ No newline at end of file diff --git a/backend/app.js b/backend/app.js index c3e3033..48ad8fc 100644 --- a/backend/app.js +++ b/backend/app.js @@ -1,6 +1,9 @@ const express = require("express"); +const path = require("path"); const cors = require("cors"); const sequelize = require("./util/database"); +const multer = require("multer"); + const wBot = require("./controllers/wbot"); const Contact = require("./models/Contact"); const wbotMessageListener = require("./controllers/wbotMessageListener"); @@ -11,8 +14,19 @@ const AuthRoutes = require("./routes/auth"); const app = express(); +const fileStorage = multer.diskStorage({ + destination: (req, file, cb) => { + cb(null, "public"); + }, + filename: (req, file, cb) => { + cb(null, new Date().getTime() + "-" + file.originalname); + }, +}); + app.use(cors()); app.use(express.json()); +app.use(multer({ storage: fileStorage }).single("media")); +app.use("/public", express.static(path.join(__dirname, "public"))); app.use(messageRoutes); app.use(ContactRoutes); @@ -32,7 +46,18 @@ sequelize const server = app.listen(8080); const io = require("./socket").init(server); io.on("connection", socket => { - console.log("Cliente Connected"); + console.log("Client Connected"); + socket.on("joinChatBox", contactId => { + socket.join(contactId); + }); + + socket.on("joinNotification", () => { + socket.join("notification"); + }); + + socket.on("disconnect", () => { + console.log("Client disconnected"); + }); }); wBot.init(); diff --git a/backend/controllers/auth.js b/backend/controllers/auth.js index 9a08471..bd77069 100644 --- a/backend/controllers/auth.js +++ b/backend/controllers/auth.js @@ -49,7 +49,7 @@ exports.login = async (req, res, next) => { const token = jwt.sign( { email: loadedUser.email, userId: loadedUser.id }, "mysecret", - { expiresIn: "1h" } + { expiresIn: "24h" } ); return res .status(200) diff --git a/backend/controllers/contact.js b/backend/controllers/contact.js index c2ba2fb..0f4309a 100644 --- a/backend/controllers/contact.js +++ b/backend/controllers/contact.js @@ -1,18 +1,32 @@ const Contact = require("../models/Contact"); const Message = require("../models/Message"); -// const io = require("../socket"); +const Sequelize = require("sequelize"); exports.getContacts = async (req, res) => { - // const contacts = await Contact.findAll(); - const contacts = await Contact.findAll({ - include: { - model: Message, - where: { - read: false, + try { + const contacts = await Contact.findAll({ + include: { model: Message, attributes: [] }, + attributes: { + include: [ + [ + Sequelize.literal(`( + SELECT COUNT(*) + FROM messages AS message + WHERE + message.contactId = contact.id + AND + message.read = 0 + + )`), + "unreadMessages", + ], + ], }, - required: false, - }, - }); + order: [[Message, "createdAt", "DESC"]], + }); - return res.json(contacts); + return res.json(contacts); + } catch (err) { + console.log(err); + } }; diff --git a/backend/controllers/message.js b/backend/controllers/message.js index b3f27ef..4d08934 100644 --- a/backend/controllers/message.js +++ b/backend/controllers/message.js @@ -1,55 +1,69 @@ +const fs = require("fs"); const Message = require("../models/Message"); const Contact = require("../models/Contact"); const io = require("../socket"); const wbot = require("./wbot"); +const { MessageMedia } = require("whatsapp-web.js"); -exports.getContactMessages = async (req, res) => { +exports.getContactMessages = async (req, res, next) => { const { contactId } = req.params; - const contact = await Contact.findByPk(contactId); - const contactMessages = await contact.getMessages(); + try { + const contact = await Contact.findByPk(contactId); + const contactMessages = await contact.getMessages(); - return res.json(contactMessages); + const result = await Message.update( + { read: true }, + { + where: { + contactId: contactId, + read: false, + }, + } + ); + + return res.json(contactMessages); + } catch (err) { + next(err); + } }; -exports.postCreateContactMessage = async (req, res) => { +exports.postCreateContactMessage = async (req, res, next) => { const { contactId } = req.params; const message = req.body; + const media = req.file; - const contact = await Contact.findByPk(contactId); + try { + const contact = await Contact.findByPk(contactId); + if (media) { + const newMedia = MessageMedia.fromFilePath(req.file.path); + message.mediaUrl = req.file.path; + if (newMedia.mimetype) { + message.mediaType = newMedia.mimetype.split("/")[0]; + } else { + message.mediaType = "other"; + } - const newMessage = await contact.createMessage(message); + wbot.getWbot().sendMessage(`${contact.number}@c.us`, newMedia); + } else { + wbot.getWbot().sendMessage(`${contact.number}@c.us`, message.messageBody); + } - if (!newMessage) { - return res.status(500).json({ message: "A mensagem não foi criada" }); + const newMessage = await contact.createMessage(message); + if (!newMessage) { + const error = new Error("Erro ao inserir a mensagem no banco de dados"); + error.satusCode = 501; + throw error; + } + + io.getIO().to(contactId).emit("appMessage", { + action: "create", + message: newMessage, + }); + + return res.json({ message: "Mensagem enviada" }); + } catch (err) { + next(err); } - - wbot.getWbot().sendMessage(`${contact.number}@c.us`, message.messageBody); - - io.getIO().emit("appMessage", { - action: "create", - message: newMessage.dataValues, - }); - - return res.json(newMessage); -}; - -exports.postUpdateMessageStatus = async (req, res) => { - const { messagesToSetRead } = req.body; - - await Promise.all( - messagesToSetRead.map(async message => { - await Message.update( - { read: 1 }, - { - where: { - id: message.id, - }, - } - ); - }) - ); - - res.json({ message: "Mensagens lidas!" }); }; diff --git a/backend/controllers/session.json b/backend/controllers/session.json index bc15a85..9a7a2cf 100644 --- a/backend/controllers/session.json +++ b/backend/controllers/session.json @@ -1 +1 @@ -{"WABrowserId":"\"ynZiZqR67F6o3M5nCIE3Ig==\"","WASecretBundle":"{\"key\":\"3kFQ7T0G4sbiCrb3ZwzDKzDdKLo6hObbUfygGby91H0=\",\"encKey\":\"ezpzST8/4752gQLd+Lj+yfZGqwzFqBlkvpelptnJ5dI=\",\"macKey\":\"3kFQ7T0G4sbiCrb3ZwzDKzDdKLo6hObbUfygGby91H0=\"}","WAToken1":"\"9g0Q+hqE6PdVX8yf2m2poDqpN+VB1NDbsSF3bp0xxE0=\"","WAToken2":"\"1@DnfzCyncYsMRZnUA+PnrZfYpux6mUSqrGPAFBgkU8b7NS6mge9SuJ4QDKUvt8HthVmH9mvovbb26zQ==\""} \ No newline at end of file +{"WABrowserId":"\"W5pw0Llb60mSeV7WOHnk8A==\"","WASecretBundle":"{\"key\":\"alDLbPjonDFzCh5PEPql9cy59LNh1HFG/AZJVoucuYI=\",\"encKey\":\"FQ1MZ2eIH9hKV4dqFoBYTv1/89aopcMAa4CXgh/9csM=\",\"macKey\":\"alDLbPjonDFzCh5PEPql9cy59LNh1HFG/AZJVoucuYI=\"}","WAToken1":"\"mjiCXmqu33f9L6eQ/8RP/ud+axdbx9y4wDFAqfJD90o=\"","WAToken2":"\"1@o99W6mNitfwQz+tg3dNp4f5/z0mMj3tR/fRgy2wuneqfze+ccCkZ9O8NT15xRlqPwAbgdpT+nJ0krg==\""} \ No newline at end of file diff --git a/backend/controllers/wbotMessageListener.js b/backend/controllers/wbotMessageListener.js index 05ca585..e27ab0c 100644 --- a/backend/controllers/wbotMessageListener.js +++ b/backend/controllers/wbotMessageListener.js @@ -1,38 +1,77 @@ -const io = require("../socket"); const Contact = require("../models/Contact"); +const path = require("path"); +const fs = require("fs"); -const wbot = require("./wbot"); +const { getIO } = require("../socket"); +const { getWbot } = require("./wbot"); const wbotMessageListener = () => { - wbot.getWbot().on("message", async msg => { + getWbot().on("message", async msg => { + let newMessage; const msgContact = await msg.getContact(); + const imageUrl = await msgContact.getProfilePicUrl(); try { let contact = await Contact.findOne({ where: { number: msgContact.number }, }); + // await contact.update({ imageURL: imageUrl }); + if (!contact) { try { contact = await Contact.create({ - name: msgContact.number.toString(), + name: msgContact.pushname || msgContact.number.toString(), number: msgContact.number, - imageUrl: "", + imageURL: imageUrl, }); - io.getIO().emit("contact", { + + contact.dataValues.unreadMessages = 1; + + getIO().emit("contact", { action: "create", - contact: contact.dataValues, + contact: contact, }); } catch (err) { console.log(err); } } + if (msg.hasMedia) { + const media = await msg.downloadMedia(); - const newMessage = await contact.createMessage({ - messageBody: msg.body, - }); - io.getIO().emit("appMessage", { + if (media) { + if (!media.filename) { + let ext = media.mimetype.split("/")[1].split(";")[0]; + let aux = Math.random(5).toString(); + media.filename = aux.split(".")[1] + "." + ext; + } + + fs.writeFile( + path.join(__dirname, "..", "public", media.filename), + media.data, + "base64", + err => { + console.log(err); + } + ); + + newMessage = await contact.createMessage({ + mediaUrl: path.join("public", media.filename), + mediaType: media.mimetype.split("/")[0], + messageBody: msg.body || media.filename, + }); + } + } else { + newMessage = await contact.createMessage({ + messageBody: msg.body, + }); + } + + getIO().to(contact.id).to("notification").emit("appMessage", { action: "create", - message: newMessage.dataValues, + message: newMessage, }); + + let chat = await msg.getChat(); + chat.sendSeen(); } catch (err) { console.log(err); } diff --git a/backend/middleware/is-auth.js b/backend/middleware/is-auth.js index 3c72e63..7841141 100644 --- a/backend/middleware/is-auth.js +++ b/backend/middleware/is-auth.js @@ -6,7 +6,7 @@ module.exports = (req, res, next) => { const token = req.get("Authorization").split(" ")[1]; decodedToken = jwt.verify(token, "mysecret"); } catch (err) { - err.statusCode = 500; + err.statusCode = 401; next(err); } diff --git a/backend/models/Contact.js b/backend/models/Contact.js index e015189..e89612c 100644 --- a/backend/models/Contact.js +++ b/backend/models/Contact.js @@ -5,17 +5,15 @@ const sequelize = require("../util/database"); const Message = require("./Message"); const Contact = sequelize.define("contact", { - id: { - type: Sequelize.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true, - }, name: { type: Sequelize.STRING(100), allowNull: false }, number: { type: Sequelize.STRING(15), allowNull: false }, imageURL: { type: Sequelize.STRING(200) }, + ateraId: Sequelize.INTEGER(), }); -Contact.hasMany(Message); +Contact.hasMany(Message, { + onDelete: "CASCADE", + onUpdate: "RESTRICT", +}); module.exports = Contact; diff --git a/backend/models/Message.js b/backend/models/Message.js index c573521..bcd358e 100644 --- a/backend/models/Message.js +++ b/backend/models/Message.js @@ -5,6 +5,8 @@ const Message = sequelize.define("message", { userId: { type: Sequelize.INTEGER, defaultValue: 0 }, messageBody: { type: Sequelize.STRING(250), allowNull: false }, read: { type: Sequelize.BOOLEAN, defaultValue: false }, + mediaUrl: { type: Sequelize.STRING(250) }, + mediaType: { type: Sequelize.STRING(250) }, }); module.exports = Message; diff --git a/backend/package-lock.json b/backend/package-lock.json index 20538b0..9caefba 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -30,15 +30,19 @@ "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", "dev": true }, - "@types/mime-types": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.0.tgz", - "integrity": "sha1-nKUs2jY/aZxpRmwqbM2q2RPqenM=" - }, "@types/node": { - "version": "13.13.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.5.tgz", - "integrity": "sha512-3ySmiBYJPqgjiHA7oEaIo2Rzz0HrOZ7yrNO5HWyaE5q0lQ3BppDZ3N53Miz8bw2I7gh1/zir2MGVZBvpb1zq9g==" + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", + "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==" + }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } }, "abbrev": { "version": "1.1.1", @@ -106,6 +110,11 @@ "picomatch": "^2.0.4" } }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -136,6 +145,11 @@ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, "base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -160,6 +174,33 @@ "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", @@ -261,6 +302,15 @@ "fill-range": "^7.0.1" } }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -276,6 +326,38 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -400,6 +482,11 @@ "readdirp": "~3.4.0" } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -626,6 +713,38 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "dot-prop": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", @@ -705,7 +824,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -904,19 +1022,12 @@ } }, "express-validator": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.4.1.tgz", - "integrity": "sha512-9lVLCv9n735j6LjZwrINKhfv30ek1U4LVy/2jU1j4QotQ8A72Saw63wTu8/zXGZajP3scqf46PJxqquGF340Bg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.5.0.tgz", + "integrity": "sha512-kXi99TuVeLWkxO0RtDOSj56T7YR0H5KZZyhtzoPSZ5TffBvrJpZPSp/frYcT/zVoLhH8NXDk+T0LCSeI6TbOGA==", "requires": { "lodash": "^4.17.15", - "validator": "^12.1.0" - }, - "dependencies": { - "validator": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-12.2.0.tgz", - "integrity": "sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ==" - } + "validator": "^13.0.0" } }, "ext": { @@ -935,23 +1046,36 @@ } }, "extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", "requires": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "minimist": "^1.2.5" + "ms": "^2.1.1" } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -1004,6 +1128,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -1178,6 +1307,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -1514,6 +1648,14 @@ "dev": true, "requires": { "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "media-typer": { @@ -1588,15 +1730,20 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "moment": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.25.3.tgz", - "integrity": "sha512-PuYv0PHxZvzc15Sp8ybUCoQ+xpyPWvjOuK72a5ovzp2LI32rJXOiIfyoFoYvG3s6EwwrdkMyWuRiEHSZRLJNdg==" + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", + "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" }, "moment-timezone": { - "version": "0.5.28", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz", - "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==", + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", "requires": { "moment": ">= 2.9.0" } @@ -1606,6 +1753,31 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multer": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + } + } + }, "mysql2": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.1.0.tgz", @@ -1667,9 +1839,9 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, "nodemon": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.3.tgz", - "integrity": "sha512-lLQLPS90Lqwc99IHe0U94rDgvjo+G9I4uEIxRG3evSLROcqQ9hwc0AxlSHKS4T1JW/IMj/7N5mthiN58NL/5kw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", + "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", "dev": true, "requires": { "chokidar": "^3.2.2", @@ -1698,12 +1870,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true } } }, @@ -1810,6 +1976,14 @@ "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "parseqs": { @@ -1905,16 +2079,15 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -1930,20 +2103,20 @@ } }, "puppeteer": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-2.1.1.tgz", - "integrity": "sha512-LWzaDVQkk1EPiuYeTOj+CZRIjda4k2s5w4MK4xoH2+kgWV/SDlkYHmxatDdtYrciHUKSXTsGgPgPP8ILVdBsxg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-3.1.0.tgz", + "integrity": "sha512-jLa9sqdVx0tPnr2FcwAq+8DSjGhSM4YpkwOf3JE22Ycyqm71SW7B5uGfTyMGFoLCmbCozbLZclCjasPb0flTRw==", "requires": { - "@types/mime-types": "^2.1.0", "debug": "^4.1.0", - "extract-zip": "^1.6.6", + "extract-zip": "^2.0.0", "https-proxy-agent": "^4.0.0", "mime": "^2.0.3", - "mime-types": "^2.1.25", "progress": "^2.0.1", "proxy-from-env": "^1.0.0", - "rimraf": "^2.6.1", - "ws": "^6.1.0" + "rimraf": "^3.0.2", + "tar-fs": "^2.0.0", + "unbzip2-stream": "^1.3.3", + "ws": "^7.2.3" }, "dependencies": { "debug": { @@ -1955,22 +2128,14 @@ } }, "mime": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", - "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==" + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", - "requires": { - "async-limiter": "~1.0.0" - } } } }, @@ -2104,9 +2269,9 @@ } }, "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "requires": { "glob": "^7.1.3" } @@ -2122,9 +2287,10 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, "semver-diff": { "version": "3.1.1", @@ -2133,6 +2299,14 @@ "dev": true, "requires": { "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "send": { @@ -2168,9 +2342,9 @@ "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" }, "sequelize": { - "version": "5.21.8", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.8.tgz", - "integrity": "sha512-UOxGMJ7eSnProTMWX9wRr0T9TcuW0YedFmU7s+YBZT9/RmfJeANYPdJXjXg4E+Yg+dJl4WWvBEu9r2oe+d/1/Q==", + "version": "5.21.11", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.11.tgz", + "integrity": "sha512-ZJw3Hp+NS7iHcTz4fHlKvIBm4I7xYibYRCP4HhSyMB26xgqFYFOXTaeWbHD2UUwAFaksTLw5ntzfpA9kE33SVA==", "requires": { "bluebird": "^3.5.0", "cls-bluebird": "^2.1.0", @@ -2201,6 +2375,16 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" } } }, @@ -2390,6 +2574,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2438,12 +2627,52 @@ "has-flag": "^3.0.0" } }, + "tar-fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "term-size": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "timers-ext": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", @@ -2545,6 +2774,15 @@ "bluebird": "^3.7.2" } }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -2619,9 +2857,9 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.0.0.tgz", + "integrity": "sha512-anYx5fURbgF04lQV18nEQWZ/3wHGnxiKdG4aL8J+jEDsm98n/sU/bey+tYk6tnGJzm7ioh5FoqrAiQ6m03IgaA==" }, "vary": { "version": "1.1.2", @@ -2629,13 +2867,21 @@ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, "whatsapp-web.js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.5.1.tgz", - "integrity": "sha512-l9/LZ1o6tuXGgeTJIYc9ZVrT3Sa/uHYBUXzgWJf4hBNOzGvFOLLoidEOgWCZXhxHHM6SnCK54QvDDpIeMTv+Lg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/whatsapp-web.js/-/whatsapp-web.js-1.6.0.tgz", + "integrity": "sha512-Lr4KG5nA9u18IBGCSVLxwBT1qlJXtLSA83/0efXobQ5j76fVw2I0sIe8KCcMcFnrTr0IIAnnxEqmXcEKnSiaqg==", "requires": { "@pedroslopez/moduleraid": "^4.1.0", - "jsqr": "^1.2.0", - "puppeteer": "^2.1.1" + "jsqr": "^1.3.1", + "mime": "^2.4.5", + "puppeteer": "^3.0.4" + }, + "dependencies": { + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + } } }, "which-module": { @@ -2743,6 +2989,11 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/backend/package.json b/backend/package.json index e790cfa..54a9afd 100644 --- a/backend/package.json +++ b/backend/package.json @@ -18,16 +18,17 @@ "bcryptjs": "^2.4.3", "cors": "^2.8.5", "express": "^4.17.1", - "express-validator": "^6.4.1", + "express-validator": "^6.5.0", "jsonwebtoken": "^8.5.1", + "multer": "^1.4.2", "mysql2": "^2.1.0", "qrcode-terminal": "^0.12.0", - "sequelize": "^5.21.8", + "sequelize": "^5.21.11", "sequelize-cli": "^5.5.1", "socket.io": "^2.3.0", - "whatsapp-web.js": "^1.5.1" + "whatsapp-web.js": "^1.6.0" }, "devDependencies": { - "nodemon": "^2.0.3" + "nodemon": "^2.0.4" } } diff --git a/backend/routes/message.js b/backend/routes/message.js index 219d750..713e22b 100644 --- a/backend/routes/message.js +++ b/backend/routes/message.js @@ -5,11 +5,6 @@ const MessangeController = require("../controllers/message"); const routes = express.Router(); -routes.post( - "/messages/setread", - isAuth, - MessangeController.postUpdateMessageStatus -); routes.get( "/messages/:contactId", isAuth, diff --git a/backend/util/database.js b/backend/util/database.js index b381995..0123800 100644 --- a/backend/util/database.js +++ b/backend/util/database.js @@ -1,6 +1,10 @@ const Sequelize = require("sequelize"); const sequelize = new Sequelize("econo_whatsbot", "root", "nodecomplete", { + define: { + charset: "utf8mb4", + collate: "utf8mb4_bin", + }, dialect: "mysql", host: "localhost", logging: false, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b82814f..9d961e4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -4830,6 +4830,15 @@ } } }, + "emoji-mart": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-3.0.0.tgz", + "integrity": "sha512-r5DXyzOLJttdwRYfJmPq/XL3W5tiAE/VsRnS0Hqyn27SqPA/GOYwVUSx50px/dXdJyDSnvmoPbuJ/zzhwSaU4A==", + "requires": { + "@babel/runtime": "^7.0.0", + "prop-types": "^15.6.0" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -10811,6 +10820,14 @@ "whatwg-fetch": "^3.0.0" } }, + "react-audio-player": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/react-audio-player/-/react-audio-player-0.13.0.tgz", + "integrity": "sha512-ivXIjQMM59Kp6Bat62VkqI5ymhgUOO8XdCsfyqeLJ5E3Hgx+Cqj1zq+x1ltU+xhSp+zW2xEEnyWHOQGdJibNfA==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-bootstrap": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.0.1.tgz", @@ -11108,6 +11125,11 @@ "resolved": "https://registry.npmjs.org/react-loading/-/react-loading-2.0.3.tgz", "integrity": "sha512-Vdqy79zq+bpeWJqC+xjltUjuGApyoItPgL0vgVfcJHhqwU7bAMKzysfGW/ADu6i0z0JiOCRJjo+IkFNkRNbA3A==" }, + "react-modal-image": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-modal-image/-/react-modal-image-2.5.0.tgz", + "integrity": "sha512-QucQrgOLmF44CD4EFDLZ9ICrbHEZwztjALgx1GsNmMWZrAtmzDLarG+T1TK2OSE4w1eHfkXtmEhQibjbt0mT2g==" + }, "react-moment": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.9.7.tgz", diff --git a/frontend/package.json b/frontend/package.json index fa9a2d8..b3befac 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,12 +9,15 @@ "@testing-library/user-event": "^7.2.1", "axios": "^0.19.2", "bootstrap": "^4.5.0", + "emoji-mart": "^3.0.0", "moment": "^2.26.0", "react": "^16.13.1", + "react-audio-player": "^0.13.0", "react-bootstrap": "^1.0.1", "react-dom": "^16.13.1", "react-icons": "^3.10.0", "react-loading": "^2.0.3", + "react-modal-image": "^2.5.0", "react-moment": "^0.9.7", "react-router-bootstrap": "^0.25.0", "react-router-dom": "^5.2.0", diff --git a/frontend/src/pages/Chat/Chat.js b/frontend/src/pages/Chat/Chat.js index cb7c06b..5a3f6d3 100644 --- a/frontend/src/pages/Chat/Chat.js +++ b/frontend/src/pages/Chat/Chat.js @@ -10,6 +10,7 @@ import LogedinNavbar from "../../components/Navbar/LogedinNavbar"; import DefaultNavbar from "../../components/Navbar/DefaultNavbar"; import ChatBox from "../ChatBox/ChatBox"; +// let socket; const Chat = ({ showToast }) => { const token = localStorage.getItem("token"); @@ -18,18 +19,28 @@ const Chat = ({ showToast }) => { const [currentPeerContact, setCurrentPeerContact] = useState(null); const [contacts, setContacts] = useState([]); const [displayedContacts, setDisplayedContacts] = useState([]); + const [notification, setNotification] = useState(true); useEffect(() => { const fetchContacts = async () => { - const res = await api.get("/contacts", { - headers: { Authorization: "Bearer " + token }, - }); - setContacts(res.data); - setDisplayedContacts(res.data); + try { + const res = await api.get("/contacts", { + headers: { Authorization: "Bearer " + token }, + }); + setContacts(res.data); + setDisplayedContacts(res.data); + } catch (err) { + alert(err.response.data.message); + } }; fetchContacts(); + }, [currentPeerContact, token, notification]); + + useEffect(() => { const socket = openSocket("http://localhost:8080"); + socket.emit("joinNotification"); + socket.on("contact", data => { console.log(data); if (data.action === "create") { @@ -37,14 +48,31 @@ const Chat = ({ showToast }) => { } }); + socket.on("appMessage", data => { + console.log("recebendo msg"); + setNotification(prevState => !prevState); + // handleUnreadMessages(data.message.contactId); + }); + return () => { socket.disconnect(); }; - }, [currentPeerContact, token]); + }, [contacts]); + + // const handleUnreadMessages = contactId => { + // console.log("Atualizando mensagens n lidas"); + // console.log(contacts); + // let aux = [...contacts]; + // let contactIndex = aux.findIndex(contact => contact.id === contactId); + // aux[contactIndex].unreadMessages++; + + // aux.unshift(aux.splice(contactIndex, 1)[0]); + + // setDisplayedContacts(aux); + // }; const addContact = contact => { setContacts(prevState => [...prevState, contact]); - console.log("adicionando contato", contact); setDisplayedContacts(prevState => [...prevState, contact]); }; @@ -109,16 +137,20 @@ const Chat = ({ showToast }) => {
{contact.name}
- {contact.messages && contact.messages.length > 0 && ( + {contact.unreadMessages > 0 && (

- {contact.messages.length} + {contact.unreadMessages}

)} diff --git a/frontend/src/pages/ChatBox/ChatBox.css b/frontend/src/pages/ChatBox/ChatBox.css index a9b7878..75c9c97 100644 --- a/frontend/src/pages/ChatBox/ChatBox.css +++ b/frontend/src/pages/ChatBox/ChatBox.css @@ -12,8 +12,8 @@ backface-visibility: hidden; border-left: 1px solid #ededed; /* border-right: 5px solid #DFA375; */ - max-height: 104%; - min-height: 104%; + max-height: 104.3%; + min-height: 104.3%; /* margin-right: 20px; */ border-radius: 10px; /* box-shadow: 0 5px 5px #808888; */ @@ -67,12 +67,6 @@ background-color: #e8e8e8; } -.teste { - border-radius: 10px; - box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); - background-color: #e8e8e8; -} - .viewBottom { display: flex; flex-direction: row; @@ -83,10 +77,14 @@ background-color: #f0f0f0; } -.icOpenGallery { - width: 30px; - height: 30px; - margin-left: 10px; +.viewMediaBottom { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + height: 100px; + + background-color: #f0f0f0; } .viewInputGallery { @@ -97,18 +95,59 @@ width: 30px; } -.icOpenSticker { - width: 30px; - height: 30px; - margin-left: 5px; - margin-right: 5px; +.icOpenGallery { + width: 20px; + height: 20px; + margin-left: 10px; + margin-right: 10px; + cursor: pointer; +} + +.icOpenGallery:hover { + opacity: 70%; + width: 20px; + height: 20px; + margin-left: 10px; + margin-right: 10px; + cursor: pointer; +} + +.icOpenEmojis { + width: 20px; + height: 20px; + margin-left: 10px; + cursor: pointer; +} + +.icOpenEmojis:hover { + opacity: 70%; + width: 20px; + height: 20px; + margin-left: 10px; + cursor: pointer; } .icSend { - width: 30px; - height: 30px; + width: 20px; + height: 20px; margin-left: 5px; margin-right: 30px; + cursor: pointer; +} + +.icSend:hover { + opacity: 70%; + width: 20px; + height: 20px; + margin-left: 5px; + margin-right: 30px; + cursor: pointer; +} + +.viewMediaInput { + flex: 1; + width: 100%; + margin-right: 10px; } .viewInput { @@ -132,9 +171,30 @@ input::placeholder { /* View item message */ .viewItemRight { - width: 300px; + min-width: 100px; + max-width: 600px; height: auto; + margin-right: 20px; + margin-top: 5px; + background-color: #dcf8c6; + align-self: flex-end; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 0px; + padding-left: 20px; + padding-right: 20px; + padding-top: 10px; + padding-bottom: 10px; + color: #203152; + box-shadow: 0 5px 5px #808888; +} + +.viewItemRight2 { + width: 300px; + padding: 4px; + height: auto; background-color: #dcf8c6; align-self: flex-end; margin-right: 20px; @@ -144,27 +204,7 @@ input::placeholder { border-bottom-left-radius: 8px; border-bottom-right-radius: 0px; color: #203152; - text-align: left; - padding-left: 20px; - padding-right: 20px; - padding-top: 10px; - padding-bottom: 10px; - box-shadow: 0 5px 5px #808888; -} - -.viewItemRight2 { - width: 300px; - height: auto; - background-color: #e1f3fb; - align-self: flex-end; - margin-right: 20px; - margin-top: 10px; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - border-bottom-left-radius: 8px; - border-bottom-right-radius: 0px; - color: #203152; - text-align: left; + /* text-align: left; */ box-shadow: 0 5px 5px #808888; } @@ -207,10 +247,14 @@ input::placeholder { } .viewItemLeft { - width: 300px; + min-width: 100px; + max-width: 600px; height: auto; - margin-top: 10px; + + margin-left: 20px; + margin-top: 5px; background-color: #ffffff; + align-self: flex-start; border-top-left-radius: 8px; border-top-right-radius: 8px; border-bottom-left-radius: 0px; @@ -225,17 +269,22 @@ input::placeholder { .viewItemLeft2 { width: 300px; + padding: 4px; height: auto; - background-color: #203152; + margin-left: 10px; + margin-top: 10px; + background-color: #ffffff; border-top-left-radius: 8px; border-top-right-radius: 8px; border-bottom-left-radius: 0px; border-bottom-right-radius: 8px; - color: white; + color: #203152; box-shadow: 0 5px 5px #808888; } .viewItemLeft3 { + margin-left: 10px; + margin-top: 10px; width: 300px; height: auto; border-top-left-radius: 8px; @@ -280,7 +329,7 @@ input::placeholder { .textContentItem { font-size: 16px; - word-break: break-all; + overflow-wrap: break-word; } .viewListContentChat div:last-child { @@ -319,11 +368,9 @@ input::placeholder { /* Stickers */ .viewStickers { - display: block; + position: absolute; + bottom: 90px; border-top: 1px solid #e8e8e8; - height: 100px; - align-items: center; - justify-content: space-around; overflow-x: scroll; } .viewStickers::-webkit-scrollbar-track { @@ -360,9 +407,3 @@ input::placeholder { color: #808888; font-size: 14px; } - -.imgWaveHand { - width: 40px; - height: 40px; - margin-left: 10px; -} diff --git a/frontend/src/pages/ChatBox/ChatBox.js b/frontend/src/pages/ChatBox/ChatBox.js index 35822e6..d131783 100644 --- a/frontend/src/pages/ChatBox/ChatBox.js +++ b/frontend/src/pages/ChatBox/ChatBox.js @@ -1,25 +1,35 @@ import React, { useState, useEffect } from "react"; import { Card } from "react-bootstrap"; -import profileDefaultPic from "../../Images/profile_default.png"; -import uploadPic from "../../Images/upload.png"; -import sendPic from "../../Images/send.png"; +import { FiPaperclip, FiSend, FiX, FiSmile, FiDownload } from "react-icons/fi"; +import { RiSendPlane2Line } from "react-icons/ri"; +import "emoji-mart/css/emoji-mart.css"; +import { Picker } from "emoji-mart"; +import ModalImage from "react-modal-image"; + import api from "../../util/api"; import openSocket from "socket.io-client"; +import profileDefaultPic from "../../Images/profile_default.png"; +import ReactAudioPlayer from "react-audio-player"; import ScrollToBottom from "react-scroll-to-bottom"; import "react-toastify/dist/ReactToastify.css"; import "./ChatBox.css"; +// let socket; const ChatBox = ({ currentPeerContact }) => { + const SERVER_URL = "http://localhost:8080/"; const contactId = currentPeerContact.id; const unreadMessages = currentPeerContact.messages; const userId = localStorage.getItem("userId"); const username = localStorage.getItem("username"); const token = localStorage.getItem("token"); + const mediaInitialState = { preview: "", raw: "", name: "" }; const [listMessages, setListMessages] = useState([]); const [inputMessage, setInputMessage] = useState(""); + const [media, setMedia] = useState(mediaInitialState); + const [showEmoji, setShowEmoji] = useState(false); useEffect(() => { const fetchMessages = async () => { @@ -33,44 +43,88 @@ const ChatBox = ({ currentPeerContact }) => { } }; - const readMesages = async () => { - try { - await api.post( - "/messages/setread", - { messagesToSetRead: unreadMessages }, - { headers: { Authorization: "Bearer " + token } } - ); - } catch (err) { - alert(err); - } - }; + fetchMessages(); + + return () => { + setInputMessage(""); + setShowEmoji(false); + setMedia({}); + }; + }, [contactId, unreadMessages, token]); + + useEffect(() => { + const socket = openSocket(SERVER_URL); + + socket.emit("joinChatBox", contactId, () => {}); - const socket = openSocket("http://localhost:8080"); socket.on("appMessage", data => { if (data.action === "create") { - if (contactId === data.message.contactId) { - addMessage(data.message); - } + addMessage(data.message); } }); - fetchMessages(); - readMesages(); - return () => { socket.disconnect(); }; - }, [contactId, unreadMessages, token]); + }, [contactId]); + + const addMessage = message => { + setListMessages(prevState => [...prevState, message]); + }; const handleChangeInput = e => { setInputMessage(e.target.value); }; + const handleAddEmoji = e => { + let emoji = e.native; + setInputMessage(prevState => prevState + emoji); + }; + + const handleChangeMedia = e => { + if (e.target.files.length) { + setMedia({ + preview: URL.createObjectURL(e.target.files[0]), + raw: e.target.files[0], + name: e.target.files[0].name, + }); + } + }; + + const handleInputPaste = e => { + if (e.clipboardData.files[0]) { + setMedia({ + preview: URL.createObjectURL(e.clipboardData.files[0]), + raw: e.clipboardData.files[0], + name: e.clipboardData.files[0].name, + }); + } + }; + + const handleUploadMedia = async e => { + e.preventDefault(); + const formData = new FormData(); + formData.append("media", media.raw); + formData.append("userId", userId); + formData.append("messageBody", media.name); + + try { + await api.post(`/messages/${contactId}`, formData, { + headers: { Authorization: "Bearer " + token }, + }); + } catch (err) { + console.log(err); + alert(err); + } + setMedia(mediaInitialState); + }; + const handleSendMessage = async () => { if (inputMessage.trim() === "") return; const message = { read: 1, userId: userId, + mediaUrl: "", messageBody: `${username}: ${inputMessage.trim()}`, }; try { @@ -81,57 +135,194 @@ const ChatBox = ({ currentPeerContact }) => { alert(err); } setInputMessage(""); + setShowEmoji(false); }; - const addMessage = message => { - setListMessages(prevState => [...prevState, message]); + const renderMessages = () => { + if (listMessages.length > 0) { + let viewListMessages = []; + listMessages.forEach((message, index) => { + if (message.userId === 0) { + if (message.mediaUrl && message.mediaType === "image") { + viewListMessages.push( +
+ + {message.messageBody} +
+ ); + } else if (message.mediaUrl && message.mediaType === "audio") { + viewListMessages.push( +
+ {message.messageBody} + +
+ ); + } else if (message.mediaUrl) { + viewListMessages.push( +
+ + {message.messageBody} +
+ Download +
+
+ ); + } else { + viewListMessages.push( +
+ {message.messageBody} +
+ ); + } + } else { + if (message.mediaUrl && message.mediaType === "image") { + viewListMessages.push( +
+ + {message.messageBody} +
+ ); + } else if (message.mediaUrl && message.mediaType === "audio") { + viewListMessages.push( +
+ {message.messageBody} + +
+ ); + } else if (message.mediaUrl) { + viewListMessages.push( +
+ + {message.messageBody} +
+ Download +
+
+ ); + } else { + viewListMessages.push( +
+ {message.messageBody} +
+ ); + } + } + }); + return viewListMessages; + } else { + return ( +
+ Diga olá para o seu novo contato +
+ ); + } }; return (
- +

{currentPeerContact.name}

+
+ +

Status do contato

+
+
-
- {listMessages.map((message, index) => - message.userId === 0 ? ( -
- {message.messageBody} -
- ) : ( -
- {message.messageBody} -
- ) - )} -
+
{renderMessages()}
-
- - input && input.focus()} - name="inputMessage" - className="viewInput" - placeholder="mensagem" - value={inputMessage} - onChange={handleChangeInput} - onKeyPress={e => { - if (e.key === "Enter") { - handleSendMessage(); - } - }} - > - -
+ {media.preview ? ( +
+ setMedia(mediaInitialState)} + /> + + {media.name} + {/* */} + + +
+ ) : ( +
+
+ {showEmoji ? ( +
+ +
+ ) : null} + + setShowEmoji(prevState => !prevState)} + /> + + +
+ + inputMessage && inputMessage.focus()} + name="inputMessage" + autoComplete="off" + className="viewInput" + placeholder="Digite uma mensagem" + onPaste={handleInputPaste} + value={inputMessage} + onChange={handleChangeInput} + onKeyPress={e => { + if (e.key === "Enter") { + handleSendMessage(); + } + }} + /> + + +
+ )}
); };