mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-19 20:29:17 +00:00
working
This commit is contained in:
1
backend/.gitignore
vendored
Normal file
1
backend/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
45
backend/app.js
Normal file
45
backend/app.js
Normal file
@@ -0,0 +1,45 @@
|
||||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const sequelize = require("./util/database");
|
||||
const wBot = require("./controllers/wbot");
|
||||
const Contact = require("./models/Contact");
|
||||
const wbotMessageListener = require("./controllers/wbotMessageListener");
|
||||
|
||||
const messageRoutes = require("./routes/message");
|
||||
const ContactRoutes = require("./routes/contacts");
|
||||
const AuthRoutes = require("./routes/auth");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
app.use(messageRoutes);
|
||||
app.use(ContactRoutes);
|
||||
app.use("/auth", AuthRoutes);
|
||||
|
||||
app.use((error, req, res, next) => {
|
||||
console.log(error);
|
||||
const status = error.statusCode || 500;
|
||||
const message = error.message;
|
||||
const data = error.data;
|
||||
res.status(status).json({ message: message, data: data });
|
||||
});
|
||||
|
||||
sequelize
|
||||
.sync()
|
||||
.then(() => {
|
||||
const server = app.listen(8080);
|
||||
const io = require("./socket").init(server);
|
||||
io.on("connection", socket => {
|
||||
console.log("Cliente Connected");
|
||||
});
|
||||
|
||||
wBot.init();
|
||||
wbotMessageListener();
|
||||
|
||||
console.log("Server started");
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
60
backend/controllers/auth.js
Normal file
60
backend/controllers/auth.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const { validationResult } = require("express-validator");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const User = require("../models/User");
|
||||
|
||||
exports.signup = async (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
const error = new Error("Validation failed");
|
||||
error.statusCode = 422;
|
||||
error.data = errors.array();
|
||||
throw error;
|
||||
}
|
||||
const { name, password, email } = req.body;
|
||||
|
||||
try {
|
||||
const hashedPw = await bcrypt.hash(password, 12);
|
||||
const user = User.build({
|
||||
email: email,
|
||||
password: hashedPw,
|
||||
name: name,
|
||||
});
|
||||
const result = await user.save();
|
||||
res.status(201).json({ message: "User created!", userId: result.id });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
};
|
||||
|
||||
exports.login = async (req, res, next) => {
|
||||
const { email, password } = req.body;
|
||||
let loadedUser;
|
||||
|
||||
try {
|
||||
const user = await User.findOne({ where: { email: email } });
|
||||
if (!user) {
|
||||
const error = new Error("Usuário não encontrado");
|
||||
error.statusCode = 401;
|
||||
throw error;
|
||||
}
|
||||
loadedUser = user;
|
||||
const isEqual = await bcrypt.compare(password, user.password);
|
||||
if (!isEqual) {
|
||||
const error = new Error("Senha incorreta");
|
||||
error.statusCode = 401;
|
||||
throw error;
|
||||
}
|
||||
const token = jwt.sign(
|
||||
{ email: loadedUser.email, userId: loadedUser.id },
|
||||
"mysecret",
|
||||
{ expiresIn: "1h" }
|
||||
);
|
||||
return res
|
||||
.status(200)
|
||||
.json({ token: token, username: loadedUser.name, userId: loadedUser.id });
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
};
|
||||
18
backend/controllers/contact.js
Normal file
18
backend/controllers/contact.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const Contact = require("../models/Contact");
|
||||
const Message = require("../models/Message");
|
||||
// const io = require("../socket");
|
||||
|
||||
exports.getContacts = async (req, res) => {
|
||||
// const contacts = await Contact.findAll();
|
||||
const contacts = await Contact.findAll({
|
||||
include: {
|
||||
model: Message,
|
||||
where: {
|
||||
read: false,
|
||||
},
|
||||
required: false,
|
||||
},
|
||||
});
|
||||
|
||||
return res.json(contacts);
|
||||
};
|
||||
55
backend/controllers/message.js
Normal file
55
backend/controllers/message.js
Normal file
@@ -0,0 +1,55 @@
|
||||
const Message = require("../models/Message");
|
||||
const Contact = require("../models/Contact");
|
||||
const io = require("../socket");
|
||||
|
||||
const wbot = require("./wbot");
|
||||
|
||||
exports.getContactMessages = async (req, res) => {
|
||||
const { contactId } = req.params;
|
||||
const contact = await Contact.findByPk(contactId);
|
||||
|
||||
const contactMessages = await contact.getMessages();
|
||||
|
||||
return res.json(contactMessages);
|
||||
};
|
||||
|
||||
exports.postCreateContactMessage = async (req, res) => {
|
||||
const { contactId } = req.params;
|
||||
const message = req.body;
|
||||
|
||||
const contact = await Contact.findByPk(contactId);
|
||||
|
||||
const newMessage = await contact.createMessage(message);
|
||||
|
||||
if (!newMessage) {
|
||||
return res.status(500).json({ message: "A mensagem não foi criada" });
|
||||
}
|
||||
|
||||
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!" });
|
||||
};
|
||||
1
backend/controllers/session.json
Normal file
1
backend/controllers/session.json
Normal file
@@ -0,0 +1 @@
|
||||
{"WABrowserId":"\"ynZiZqR67F6o3M5nCIE3Ig==\"","WASecretBundle":"{\"key\":\"3kFQ7T0G4sbiCrb3ZwzDKzDdKLo6hObbUfygGby91H0=\",\"encKey\":\"ezpzST8/4752gQLd+Lj+yfZGqwzFqBlkvpelptnJ5dI=\",\"macKey\":\"3kFQ7T0G4sbiCrb3ZwzDKzDdKLo6hObbUfygGby91H0=\"}","WAToken1":"\"9g0Q+hqE6PdVX8yf2m2poDqpN+VB1NDbsSF3bp0xxE0=\"","WAToken2":"\"1@DnfzCyncYsMRZnUA+PnrZfYpux6mUSqrGPAFBgkU8b7NS6mge9SuJ4QDKUvt8HthVmH9mvovbb26zQ==\""}
|
||||
48
backend/controllers/wbot.js
Normal file
48
backend/controllers/wbot.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const path = require("path");
|
||||
const qrCode = require("qrcode-terminal");
|
||||
const fs = require("fs");
|
||||
const { Client } = require("whatsapp-web.js");
|
||||
let wbot;
|
||||
|
||||
module.exports = {
|
||||
init: () => {
|
||||
const SESSION_FILE_PATH = path.join(__dirname, "/session.json");
|
||||
let sessionCfg;
|
||||
if (fs.existsSync(SESSION_FILE_PATH)) {
|
||||
sessionCfg = require(SESSION_FILE_PATH);
|
||||
}
|
||||
wbot = new Client({
|
||||
session: sessionCfg,
|
||||
});
|
||||
wbot.initialize();
|
||||
wbot.on("qr", qr => {
|
||||
qrCode.generate(qr, { small: true });
|
||||
});
|
||||
wbot.on("authenticated", session => {
|
||||
console.log("AUTHENTICATED");
|
||||
sessionCfg = session;
|
||||
fs.writeFile(SESSION_FILE_PATH, JSON.stringify(sessionCfg), function (
|
||||
err
|
||||
) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
wbot.on("auth_failure", msg => {
|
||||
console.error("AUTHENTICATION FAILURE", msg);
|
||||
});
|
||||
wbot.on("ready", () => {
|
||||
console.log("READY");
|
||||
});
|
||||
|
||||
return wbot;
|
||||
},
|
||||
|
||||
getWbot: () => {
|
||||
if (!wbot) {
|
||||
throw new Error("Wbot not initialized");
|
||||
}
|
||||
return wbot;
|
||||
},
|
||||
};
|
||||
42
backend/controllers/wbotMessageListener.js
Normal file
42
backend/controllers/wbotMessageListener.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const io = require("../socket");
|
||||
const Contact = require("../models/Contact");
|
||||
|
||||
const wbot = require("./wbot");
|
||||
|
||||
const wbotMessageListener = () => {
|
||||
wbot.getWbot().on("message", async msg => {
|
||||
const msgContact = await msg.getContact();
|
||||
try {
|
||||
let contact = await Contact.findOne({
|
||||
where: { number: msgContact.number },
|
||||
});
|
||||
if (!contact) {
|
||||
try {
|
||||
contact = await Contact.create({
|
||||
name: msgContact.number.toString(),
|
||||
number: msgContact.number,
|
||||
imageUrl: "",
|
||||
});
|
||||
io.getIO().emit("contact", {
|
||||
action: "create",
|
||||
contact: contact.dataValues,
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
const newMessage = await contact.createMessage({
|
||||
messageBody: msg.body,
|
||||
});
|
||||
io.getIO().emit("appMessage", {
|
||||
action: "create",
|
||||
message: newMessage.dataValues,
|
||||
});
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = wbotMessageListener;
|
||||
21
backend/middleware/is-auth.js
Normal file
21
backend/middleware/is-auth.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const jwt = require("jsonwebtoken");
|
||||
|
||||
module.exports = (req, res, next) => {
|
||||
let decodedToken;
|
||||
try {
|
||||
const token = req.get("Authorization").split(" ")[1];
|
||||
decodedToken = jwt.verify(token, "mysecret");
|
||||
} catch (err) {
|
||||
err.statusCode = 500;
|
||||
next(err);
|
||||
}
|
||||
|
||||
if (!decodedToken) {
|
||||
const error = new Error("Falha na autenticação");
|
||||
error.statusCode = 401;
|
||||
next(error);
|
||||
}
|
||||
|
||||
req.userId = decodedToken.userId;
|
||||
next();
|
||||
};
|
||||
21
backend/models/Contact.js
Normal file
21
backend/models/Contact.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const Sequelize = require("sequelize");
|
||||
|
||||
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) },
|
||||
});
|
||||
|
||||
Contact.hasMany(Message);
|
||||
|
||||
module.exports = Contact;
|
||||
10
backend/models/Message.js
Normal file
10
backend/models/Message.js
Normal file
@@ -0,0 +1,10 @@
|
||||
const Sequelize = require("sequelize");
|
||||
const sequelize = require("../util/database");
|
||||
|
||||
const Message = sequelize.define("message", {
|
||||
userId: { type: Sequelize.INTEGER, defaultValue: 0 },
|
||||
messageBody: { type: Sequelize.STRING(250), allowNull: false },
|
||||
read: { type: Sequelize.BOOLEAN, defaultValue: false },
|
||||
});
|
||||
|
||||
module.exports = Message;
|
||||
17
backend/models/User.js
Normal file
17
backend/models/User.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const Sequelize = require("sequelize");
|
||||
|
||||
const sequelize = require("../util/database");
|
||||
|
||||
const User = sequelize.define("user", {
|
||||
id: {
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: false,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
},
|
||||
name: { type: Sequelize.STRING(100), allowNull: false },
|
||||
password: { type: Sequelize.STRING(100), allowNull: false },
|
||||
email: { type: Sequelize.STRING(100), allowNull: false },
|
||||
});
|
||||
|
||||
module.exports = User;
|
||||
2797
backend/package-lock.json
generated
Normal file
2797
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
backend/package.json
Normal file
33
backend/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "nodemon app.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"ignore": [
|
||||
"controllers/session.json"
|
||||
]
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"express-validator": "^6.4.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"mysql2": "^2.1.0",
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"sequelize": "^5.21.8",
|
||||
"sequelize-cli": "^5.5.1",
|
||||
"socket.io": "^2.3.0",
|
||||
"whatsapp-web.js": "^1.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.3"
|
||||
}
|
||||
}
|
||||
30
backend/routes/auth.js
Normal file
30
backend/routes/auth.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const express = require("express");
|
||||
const { body } = require("express-validator");
|
||||
const User = require("../models/User");
|
||||
const authController = require("../controllers/auth");
|
||||
|
||||
const routes = express.Router();
|
||||
|
||||
routes.put(
|
||||
"/signup",
|
||||
[
|
||||
body("email")
|
||||
.isEmail()
|
||||
.withMessage("Email inválido")
|
||||
.custom((value, { req }) => {
|
||||
return User.findOne({ where: { email: value } }).then(user => {
|
||||
if (user) {
|
||||
return Promise.reject("Um cadastro com este email já existe!");
|
||||
}
|
||||
});
|
||||
})
|
||||
.normalizeEmail(),
|
||||
body("password").trim().isLength({ min: 5 }),
|
||||
body("name").trim().not().isEmpty(),
|
||||
],
|
||||
authController.signup
|
||||
);
|
||||
|
||||
routes.post("/login", authController.login);
|
||||
|
||||
module.exports = routes;
|
||||
11
backend/routes/contacts.js
Normal file
11
backend/routes/contacts.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const express = require("express");
|
||||
const isAuth = require("../middleware/is-auth");
|
||||
|
||||
const ContactController = require("../controllers/contact");
|
||||
|
||||
const routes = express.Router();
|
||||
|
||||
routes.get("/contacts", isAuth, ContactController.getContacts);
|
||||
// routes.post(ContactController.postCreateContact);
|
||||
|
||||
module.exports = routes;
|
||||
24
backend/routes/message.js
Normal file
24
backend/routes/message.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const express = require("express");
|
||||
const isAuth = require("../middleware/is-auth");
|
||||
|
||||
const MessangeController = require("../controllers/message");
|
||||
|
||||
const routes = express.Router();
|
||||
|
||||
routes.post(
|
||||
"/messages/setread",
|
||||
isAuth,
|
||||
MessangeController.postUpdateMessageStatus
|
||||
);
|
||||
routes.get(
|
||||
"/messages/:contactId",
|
||||
isAuth,
|
||||
MessangeController.getContactMessages
|
||||
);
|
||||
routes.post(
|
||||
"/messages/:contactId",
|
||||
isAuth,
|
||||
MessangeController.postCreateContactMessage
|
||||
);
|
||||
|
||||
module.exports = routes;
|
||||
14
backend/socket.js
Normal file
14
backend/socket.js
Normal file
@@ -0,0 +1,14 @@
|
||||
let io;
|
||||
|
||||
module.exports = {
|
||||
init: httpServer => {
|
||||
io = require("socket.io")(httpServer);
|
||||
return io;
|
||||
},
|
||||
getIO: () => {
|
||||
if (!io) {
|
||||
throw new Error("Socket IO not initialized");
|
||||
}
|
||||
return io;
|
||||
},
|
||||
};
|
||||
9
backend/util/database.js
Normal file
9
backend/util/database.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const Sequelize = require("sequelize");
|
||||
|
||||
const sequelize = new Sequelize("econo_whatsbot", "root", "nodecomplete", {
|
||||
dialect: "mysql",
|
||||
host: "localhost",
|
||||
logging: false,
|
||||
});
|
||||
|
||||
module.exports = sequelize;
|
||||
Reference in New Issue
Block a user