mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-19 12:19:16 +00:00
feat: added users page
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-validator": "^6.5.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"multer": "^1.4.2",
|
||||
"mysql2": "^2.1.0",
|
||||
@@ -30,7 +29,8 @@
|
||||
"sequelize": "^6.3.4",
|
||||
"socket.io": "^2.3.0",
|
||||
"whatsapp-web.js": "^1.8.0",
|
||||
"youch": "^2.0.10"
|
||||
"youch": "^2.0.10",
|
||||
"yup": "^0.29.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.4",
|
||||
|
||||
@@ -82,6 +82,5 @@ app.use(async (err, req, res, next) => {
|
||||
console.log(err);
|
||||
return res.status(500).json(errors);
|
||||
}
|
||||
console.log(err);
|
||||
return res.status(500).json({ error: "Internal server error" });
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ const { getIO } = require("../libs/socket");
|
||||
const { getWbot } = require("../libs/wbot");
|
||||
|
||||
exports.index = async (req, res) => {
|
||||
const { searchParam = "", pageNumber = 1, rowsPerPage = 10 } = req.query;
|
||||
const { searchParam = "", pageNumber = 1 } = req.query;
|
||||
|
||||
const whereCondition = {
|
||||
[Op.or]: [
|
||||
@@ -23,7 +23,7 @@ exports.index = async (req, res) => {
|
||||
],
|
||||
};
|
||||
|
||||
let limit = +rowsPerPage;
|
||||
let limit = 20;
|
||||
let offset = limit * (pageNumber - 1);
|
||||
|
||||
const { count, rows: contacts } = await Contact.findAndCountAll({
|
||||
@@ -33,7 +33,9 @@ exports.index = async (req, res) => {
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
|
||||
return res.json({ contacts, count });
|
||||
const hasMore = count > offset + contacts.length;
|
||||
|
||||
return res.json({ contacts, count, hasMore });
|
||||
};
|
||||
|
||||
exports.store = async (req, res) => {
|
||||
|
||||
@@ -16,7 +16,7 @@ exports.index = async (req, res) => {
|
||||
showAll,
|
||||
} = req.query;
|
||||
|
||||
const userId = req.userId;
|
||||
const userId = req.user.id;
|
||||
|
||||
const limit = 20;
|
||||
const offset = limit * (pageNumber - 1);
|
||||
|
||||
@@ -1,34 +1,101 @@
|
||||
const { validationResult } = require("express-validator");
|
||||
const Sequelize = require("sequelize");
|
||||
const Yup = require("yup");
|
||||
const { Op } = require("sequelize");
|
||||
|
||||
const User = require("../models/User");
|
||||
|
||||
const { getIO } = require("../libs/socket");
|
||||
|
||||
exports.index = async (req, res) => {
|
||||
// const { searchParam = "", pageNumber = 1 } = req.query;
|
||||
const { searchParam = "", pageNumber = 1, rowsPerPage = 10 } = req.query;
|
||||
|
||||
const users = await User.findAll({ attributes: ["name", "id", "email"] });
|
||||
const whereCondition = {
|
||||
[Op.or]: [
|
||||
{
|
||||
name: Sequelize.where(
|
||||
Sequelize.fn("LOWER", Sequelize.col("name")),
|
||||
"LIKE",
|
||||
"%" + searchParam.toLowerCase() + "%"
|
||||
),
|
||||
},
|
||||
{ email: { [Op.like]: `%${searchParam.toLowerCase()}%` } },
|
||||
],
|
||||
};
|
||||
|
||||
return res.status(200).json(users);
|
||||
let limit = +rowsPerPage;
|
||||
let offset = limit * (pageNumber - 1);
|
||||
|
||||
const { count, rows: users } = await User.findAndCountAll({
|
||||
attributes: ["name", "id", "email", "profile"],
|
||||
where: whereCondition,
|
||||
limit,
|
||||
offset,
|
||||
order: [["createdAt", "DESC"]],
|
||||
});
|
||||
|
||||
return res.status(200).json({ users, count });
|
||||
};
|
||||
|
||||
exports.store = async (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
const schema = Yup.object().shape({
|
||||
name: Yup.string().required().min(2),
|
||||
email: Yup.string()
|
||||
.email()
|
||||
.required()
|
||||
.test(
|
||||
"Check-email",
|
||||
"An user with this email already exists",
|
||||
async value => {
|
||||
const userFound = await User.findOne({ where: { email: value } });
|
||||
return !Boolean(userFound);
|
||||
}
|
||||
),
|
||||
password: Yup.string().required().min(5),
|
||||
});
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Validation failed", data: errors.array() });
|
||||
}
|
||||
await schema.validate(req.body);
|
||||
|
||||
const { name, id, email } = await User.create(req.body);
|
||||
const io = getIO();
|
||||
|
||||
res.status(201).json({ message: "User created!", userId: id });
|
||||
const { name, id, email, profile } = await User.create(req.body);
|
||||
|
||||
io.emit("user", {
|
||||
action: "create",
|
||||
user: { name, id, email, profile },
|
||||
});
|
||||
|
||||
return res.status(201).json({ message: "User created!", userId: id });
|
||||
};
|
||||
|
||||
exports.show = async (req, res) => {
|
||||
const { userId } = req.params;
|
||||
|
||||
const { id, name, email, profile } = await User.findByPk(userId);
|
||||
|
||||
return res.status(200).json({
|
||||
id,
|
||||
name,
|
||||
email,
|
||||
profile,
|
||||
});
|
||||
};
|
||||
|
||||
exports.update = async (req, res) => {
|
||||
const schema = Yup.object().shape({
|
||||
name: Yup.string().min(2),
|
||||
email: Yup.string().email(),
|
||||
password: Yup.string(),
|
||||
});
|
||||
|
||||
console.log("cai aqui");
|
||||
|
||||
await schema.validate(req.body);
|
||||
|
||||
const io = getIO();
|
||||
const { userId } = req.params;
|
||||
|
||||
const user = await User.findByPk(userId, {
|
||||
attributes: ["name", "id", "email"],
|
||||
attributes: ["name", "id", "email", "profile"],
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
@@ -37,12 +104,16 @@ exports.update = async (req, res) => {
|
||||
|
||||
await user.update(req.body);
|
||||
|
||||
//todo, send socket IO to users channel.
|
||||
io.emit("user", {
|
||||
action: "update",
|
||||
user: user,
|
||||
});
|
||||
|
||||
res.status(200).json(user);
|
||||
return res.status(200).json(user);
|
||||
};
|
||||
|
||||
exports.delete = async (req, res) => {
|
||||
const io = getIO();
|
||||
const { userId } = req.params;
|
||||
|
||||
const user = await User.findByPk(userId);
|
||||
@@ -53,5 +124,10 @@ exports.delete = async (req, res) => {
|
||||
|
||||
await user.destroy();
|
||||
|
||||
res.status(200).json({ message: "User deleted" });
|
||||
io.emit("user", {
|
||||
action: "delete",
|
||||
userId: userId,
|
||||
});
|
||||
|
||||
return res.status(200).json({ message: "User deleted" });
|
||||
};
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface, Sequelize) => {
|
||||
return queryInterface.addColumn("Users", "profile", {
|
||||
type: Sequelize.STRING,
|
||||
allowNull: false,
|
||||
defaultValue: "admin",
|
||||
});
|
||||
},
|
||||
|
||||
down: queryInterface => {
|
||||
return queryInterface.removeColumn("Users", "profile");
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
const jwt = require("jsonwebtoken");
|
||||
const util = require("util");
|
||||
|
||||
const User = require("../models/User");
|
||||
const authConfig = require("../config/auth");
|
||||
|
||||
module.exports = async (req, res, next) => {
|
||||
@@ -11,12 +13,24 @@ module.exports = async (req, res, next) => {
|
||||
|
||||
const [, token] = authHeader.split(" ");
|
||||
|
||||
jwt.verify(token, authConfig.secret, (error, result) => {
|
||||
if (error) {
|
||||
return res.status(401).json({ error: "Invalid token" });
|
||||
try {
|
||||
const decoded = await util.promisify(jwt.verify)(token, authConfig.secret);
|
||||
|
||||
const user = await User.findByPk(decoded.userId, {
|
||||
attributes: ["id", "name", "profile", "email"],
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res
|
||||
.status(401)
|
||||
.json({ error: "The token corresponding user does not exists." });
|
||||
}
|
||||
req.userId = result.userId;
|
||||
// todo >> find user in DB and store in req.user to use latter, or throw an error if user not exists anymore
|
||||
next();
|
||||
});
|
||||
|
||||
req.user = user;
|
||||
|
||||
return next();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return res.status(401).json({ error: "Invalid Token" });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ class User extends Sequelize.Model {
|
||||
{
|
||||
name: { type: Sequelize.STRING },
|
||||
password: { type: Sequelize.VIRTUAL },
|
||||
profile: { type: Sequelize.STRING, defaultValue: "admin" },
|
||||
passwordHash: { type: Sequelize.STRING },
|
||||
email: { type: Sequelize.STRING },
|
||||
},
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
const express = require("express");
|
||||
const SessionController = require("../controllers/SessionController");
|
||||
const UserController = require("../controllers/UserController");
|
||||
const isAuth = require("../middleware/is-auth");
|
||||
|
||||
const routes = express.Router();
|
||||
|
||||
routes.post("/signup", UserController.store);
|
||||
|
||||
routes.post("/login", SessionController.store);
|
||||
|
||||
routes.get("/check", isAuth, (req, res) => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const express = require("express");
|
||||
const { body } = require("express-validator");
|
||||
const User = require("../models/User");
|
||||
|
||||
const isAuth = require("../middleware/is-auth");
|
||||
@@ -9,28 +8,12 @@ const routes = express.Router();
|
||||
|
||||
routes.get("/users", isAuth, UserController.index);
|
||||
|
||||
routes.post(
|
||||
"/users",
|
||||
[
|
||||
body("email")
|
||||
.isEmail()
|
||||
.withMessage("Email inválido")
|
||||
.custom((value, { req }) => {
|
||||
return User.findOne({ where: { email: value } }).then(user => {
|
||||
if (user) {
|
||||
return Promise.reject("An user with this email already exists!");
|
||||
}
|
||||
});
|
||||
})
|
||||
.normalizeEmail(),
|
||||
body("password").trim().isLength({ min: 5 }),
|
||||
body("name").trim().not().isEmpty(),
|
||||
],
|
||||
UserController.store
|
||||
);
|
||||
routes.post("/users", isAuth, UserController.store);
|
||||
|
||||
routes.put("/users/:userId", isAuth, UserController.update);
|
||||
|
||||
routes.get("/users/:userId", isAuth, UserController.show);
|
||||
|
||||
routes.delete("/users/:userId", isAuth, UserController.delete);
|
||||
|
||||
module.exports = routes;
|
||||
|
||||
@@ -137,7 +137,7 @@ const wbotMessageListener = () => {
|
||||
const io = getIO();
|
||||
|
||||
wbot.on("message_create", async msg => {
|
||||
// console.log(msg);
|
||||
console.log(msg);
|
||||
if (
|
||||
msg.from === "status@broadcast" ||
|
||||
msg.type === "location" ||
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/runtime@^7.10.5":
|
||||
version "7.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@pedroslopez/moduleraid@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@pedroslopez/moduleraid/-/moduleraid-4.1.0.tgz#468f7195fddc9f367e672ace9269f0698cf4c404"
|
||||
@@ -854,14 +861,6 @@ express-async-errors@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41"
|
||||
integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==
|
||||
|
||||
express-validator@^6.5.0:
|
||||
version "6.6.1"
|
||||
resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.6.1.tgz#c53046f615d27fcb78be786e018dcd60bd9c6c5c"
|
||||
integrity sha512-+MrZKJ3eGYXkNF9p9Zf7MS7NkPJFg9MDYATU5c80Cf4F62JdLBIjWxy6481tRC0y1NnC9cgOw8FuN364bWaGhA==
|
||||
dependencies:
|
||||
lodash "^4.17.19"
|
||||
validator "^13.1.1"
|
||||
|
||||
express@^4.17.1:
|
||||
version "4.17.1"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
|
||||
@@ -950,6 +949,11 @@ find-up@^3.0.0:
|
||||
dependencies:
|
||||
locate-path "^3.0.0"
|
||||
|
||||
fn-name@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c"
|
||||
integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA==
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
@@ -1382,6 +1386,11 @@ locate-path@^3.0.0:
|
||||
p-locate "^3.0.0"
|
||||
path-exists "^3.0.0"
|
||||
|
||||
lodash-es@^4.17.11:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
|
||||
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
|
||||
|
||||
lodash.includes@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
|
||||
@@ -1417,7 +1426,7 @@ lodash.once@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
|
||||
|
||||
lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.5:
|
||||
lodash@^4.17.15, lodash@^4.17.5:
|
||||
version "4.17.20"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
||||
@@ -1801,6 +1810,11 @@ progress@^2.0.1:
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||
|
||||
property-expr@^2.0.2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.4.tgz#37b925478e58965031bb612ec5b3260f8241e910"
|
||||
integrity sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
@@ -1941,6 +1955,11 @@ redeyed@~2.1.0:
|
||||
dependencies:
|
||||
esprima "~4.0.0"
|
||||
|
||||
regenerator-runtime@^0.13.4:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
|
||||
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
|
||||
|
||||
registry-auth-token@^4.0.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.0.tgz#1d37dffda72bbecd0f581e4715540213a65eb7da"
|
||||
@@ -2266,6 +2285,11 @@ supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
synchronous-promise@^2.0.13:
|
||||
version "2.0.13"
|
||||
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702"
|
||||
integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==
|
||||
|
||||
tar-fs@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.0.tgz#d1cdd121ab465ee0eb9ccde2d35049d3f3daf0d5"
|
||||
@@ -2332,6 +2356,11 @@ toposort-class@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
|
||||
integrity sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=
|
||||
|
||||
toposort@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
|
||||
integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
|
||||
|
||||
touch@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
|
||||
@@ -2464,11 +2493,6 @@ validator@^10.11.0:
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
|
||||
integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
|
||||
|
||||
validator@^13.1.1:
|
||||
version "13.1.1"
|
||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.1.1.tgz#f8811368473d2173a9d8611572b58c5783f223bf"
|
||||
integrity sha512-8GfPiwzzRoWTg7OV1zva1KvrSemuMkv07MA9TTl91hfhe+wKrsrgVN4H2QSFd/U/FhiU3iWPYVgvbsOGwhyFWw==
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
@@ -2614,3 +2638,16 @@ youch@^2.0.10:
|
||||
cookie "^0.3.1"
|
||||
mustache "^3.0.0"
|
||||
stack-trace "0.0.10"
|
||||
|
||||
yup@^0.29.3:
|
||||
version "0.29.3"
|
||||
resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.3.tgz#69a30fd3f1c19f5d9e31b1cf1c2b851ce8045fea"
|
||||
integrity sha512-RNUGiZ/sQ37CkhzKFoedkeMfJM0vNQyaz+wRZJzxdKE7VfDeVKH8bb4rr7XhRLbHJz5hSjoDNwMEIaKhuMZ8gQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.5"
|
||||
fn-name "~3.0.0"
|
||||
lodash "^4.17.15"
|
||||
lodash-es "^4.17.11"
|
||||
property-expr "^2.0.2"
|
||||
synchronous-promise "^2.0.13"
|
||||
toposort "^2.0.2"
|
||||
|
||||
Reference in New Issue
Block a user