feat: added user association to queues

This commit is contained in:
canove
2021-01-08 20:18:11 -03:00
parent 9f99245dc4
commit 3c6d0660d1
15 changed files with 145 additions and 41 deletions

View File

@@ -1,6 +1,6 @@
export default { export default {
secret: process.env.JWT_SECRET || "mysecret", secret: process.env.JWT_SECRET || "mysecret",
expiresIn: "15m", expiresIn: "15d",
refreshSecret: process.env.JWT_REFRESH_SECRET || "myanothersecret", refreshSecret: process.env.JWT_REFRESH_SECRET || "myanothersecret",
refreshExpiresIn: "7d" refreshExpiresIn: "7d"
}; };

View File

@@ -27,7 +27,7 @@ export const index = async (req: Request, res: Response): Promise<Response> => {
}; };
export const store = async (req: Request, res: Response): Promise<Response> => { export const store = async (req: Request, res: Response): Promise<Response> => {
const { email, password, name, profile } = req.body; const { email, password, name, profile, queueIds } = req.body;
if ( if (
req.url === "/signup" && req.url === "/signup" &&
@@ -42,7 +42,8 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
email, email,
password, password,
name, name,
profile profile,
queueIds
}); });
const io = getIO(); const io = getIO();

View File

@@ -8,6 +8,7 @@ import ContactCustomField from "../models/ContactCustomField";
import Message from "../models/Message"; import Message from "../models/Message";
import Queue from "../models/Queue"; import Queue from "../models/Queue";
import WhatsappQueue from "../models/WhatsappQueue"; import WhatsappQueue from "../models/WhatsappQueue";
import UserQueue from "../models/UserQueue";
// eslint-disable-next-line // eslint-disable-next-line
const dbConfig = require("../config/database"); const dbConfig = require("../config/database");
@@ -24,7 +25,8 @@ const models = [
ContactCustomField, ContactCustomField,
Setting, Setting,
Queue, Queue,
WhatsappQueue WhatsappQueue,
UserQueue
]; ];
sequelize.addModels(models); sequelize.addModels(models);

View File

@@ -0,0 +1,28 @@
import { QueryInterface, DataTypes } from "sequelize";
module.exports = {
up: (queryInterface: QueryInterface) => {
return queryInterface.createTable("UserQueues", {
userId: {
type: DataTypes.INTEGER,
primaryKey: true
},
queueId: {
type: DataTypes.INTEGER,
primaryKey: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: false
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false
}
});
},
down: (queryInterface: QueryInterface) => {
return queryInterface.dropTable("UserQueues");
}
};

View File

@@ -10,6 +10,8 @@ import {
Unique, Unique,
BelongsToMany BelongsToMany
} from "sequelize-typescript"; } from "sequelize-typescript";
import User from "./User";
import UserQueue from "./UserQueue";
import Whatsapp from "./Whatsapp"; import Whatsapp from "./Whatsapp";
import WhatsappQueue from "./WhatsappQueue"; import WhatsappQueue from "./WhatsappQueue";
@@ -39,6 +41,9 @@ class Queue extends Model<Queue> {
@BelongsToMany(() => Whatsapp, () => WhatsappQueue) @BelongsToMany(() => Whatsapp, () => WhatsappQueue)
whatsapps: Array<Whatsapp & { WhatsappQueue: WhatsappQueue }>; whatsapps: Array<Whatsapp & { WhatsappQueue: WhatsappQueue }>;
@BelongsToMany(() => User, () => UserQueue)
users: Array<User & { UserQueue: UserQueue }>;
} }
export default Queue; export default Queue;

View File

@@ -14,6 +14,7 @@ import {
import Contact from "./Contact"; import Contact from "./Contact";
import Message from "./Message"; import Message from "./Message";
import Queue from "./Queue";
import User from "./User"; import User from "./User";
import Whatsapp from "./Whatsapp"; import Whatsapp from "./Whatsapp";
@@ -64,6 +65,13 @@ class Ticket extends Model<Ticket> {
@BelongsTo(() => Whatsapp) @BelongsTo(() => Whatsapp)
whatsapp: Whatsapp; whatsapp: Whatsapp;
@ForeignKey(() => Queue)
@Column
queueId: number;
@BelongsTo(() => Queue)
queue: Queue;
@HasMany(() => Message) @HasMany(() => Message)
messages: Message[]; messages: Message[];
} }

View File

@@ -10,10 +10,13 @@ import {
PrimaryKey, PrimaryKey,
AutoIncrement, AutoIncrement,
Default, Default,
HasMany HasMany,
BelongsToMany
} from "sequelize-typescript"; } from "sequelize-typescript";
import { hash, compare } from "bcryptjs"; import { hash, compare } from "bcryptjs";
import Ticket from "./Ticket"; import Ticket from "./Ticket";
import Queue from "./Queue";
import UserQueue from "./UserQueue";
@Table @Table
class User extends Model<User> { class User extends Model<User> {
@@ -51,6 +54,9 @@ class User extends Model<User> {
@HasMany(() => Ticket) @HasMany(() => Ticket)
tickets: Ticket[]; tickets: Ticket[];
@BelongsToMany(() => Queue, () => UserQueue)
queues: Queue[];
@BeforeUpdate @BeforeUpdate
@BeforeCreate @BeforeCreate
static hashPassword = async (instance: User): Promise<void> => { static hashPassword = async (instance: User): Promise<void> => {

View File

@@ -0,0 +1,29 @@
import {
Table,
Column,
CreatedAt,
UpdatedAt,
Model,
ForeignKey
} from "sequelize-typescript";
import Queue from "./Queue";
import User from "./User";
@Table
class UserQueue extends Model<UserQueue> {
@ForeignKey(() => User)
@Column
userId: number;
@ForeignKey(() => Queue)
@Column
queueId: number;
@CreatedAt
createdAt: Date;
@UpdatedAt
updatedAt: Date;
}
export default UserQueue;

View File

@@ -7,6 +7,7 @@ interface Request {
email: string; email: string;
password: string; password: string;
name: string; name: string;
queueIds?: number[];
profile?: string; profile?: string;
} }
@@ -21,6 +22,7 @@ const CreateUserService = async ({
email, email,
password, password,
name, name,
queueIds = [],
profile = "admin" profile = "admin"
}: Request): Promise<Response> => { }: Request): Promise<Response> => {
const schema = Yup.object().shape({ const schema = Yup.object().shape({
@@ -47,18 +49,26 @@ const CreateUserService = async ({
throw new AppError(err.message); throw new AppError(err.message);
} }
const user = await User.create({ const user = await User.create(
email, {
password, email,
name, password,
profile name,
}); profile
},
{ include: ["queues"] }
);
await user.$set("queues", queueIds);
await user.reload();
const serializedUser = { const serializedUser = {
id: user.id, id: user.id,
name: user.name, name: user.name,
email: user.email, email: user.email,
profile: user.profile profile: user.profile,
queues: user.queues
}; };
return serializedUser; return serializedUser;

View File

@@ -1,4 +1,5 @@
import { Sequelize, Op } from "sequelize"; import { Sequelize, Op } from "sequelize";
import Queue from "../../models/Queue";
import User from "../../models/User"; import User from "../../models/User";
interface Request { interface Request {
@@ -19,8 +20,8 @@ const ListUsersService = async ({
const whereCondition = { const whereCondition = {
[Op.or]: [ [Op.or]: [
{ {
name: Sequelize.where( "$User.name$": Sequelize.where(
Sequelize.fn("LOWER", Sequelize.col("name")), Sequelize.fn("LOWER", Sequelize.col("User.name")),
"LIKE", "LIKE",
`%${searchParam.toLowerCase()}%` `%${searchParam.toLowerCase()}%`
) )
@@ -33,10 +34,13 @@ const ListUsersService = async ({
const { count, rows: users } = await User.findAndCountAll({ const { count, rows: users } = await User.findAndCountAll({
where: whereCondition, where: whereCondition,
attributes: ["name", "id", "email", "profile"], attributes: ["name", "id", "email", "profile", "createdAt"],
limit, limit,
offset, offset,
order: [["createdAt", "DESC"]] order: [["createdAt", "DESC"]],
include: [
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
]
}); });
const hasMore = count > offset + users.length; const hasMore = count > offset + users.length;

View File

@@ -1,9 +1,13 @@
import User from "../../models/User"; import User from "../../models/User";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import Queue from "../../models/Queue";
const ShowUserService = async (id: string | number): Promise<User> => { const ShowUserService = async (id: string | number): Promise<User> => {
const user = await User.findByPk(id, { const user = await User.findByPk(id, {
attributes: ["name", "id", "email", "profile", "tokenVersion"] attributes: ["name", "id", "email", "profile", "tokenVersion"],
include: [
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
]
}); });
if (!user) { if (!user) {

View File

@@ -1,13 +1,14 @@
import * as Yup from "yup"; import * as Yup from "yup";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import User from "../../models/User"; import ShowUserService from "./ShowUserService";
interface UserData { interface UserData {
email?: string; email?: string;
password?: string; password?: string;
name?: string; name?: string;
profile?: string; profile?: string;
queueIds?: number[];
} }
interface Request { interface Request {
@@ -26,14 +27,7 @@ const UpdateUserService = async ({
userData, userData,
userId userId
}: Request): Promise<Response | undefined> => { }: Request): Promise<Response | undefined> => {
const user = await User.findOne({ const user = await ShowUserService(userId);
where: { id: userId },
attributes: ["name", "id", "email", "profile"]
});
if (!user) {
throw new AppError("ERR_NO_USER_FOUND", 404);
}
const schema = Yup.object().shape({ const schema = Yup.object().shape({
name: Yup.string().min(2), name: Yup.string().min(2),
@@ -42,7 +36,7 @@ const UpdateUserService = async ({
password: Yup.string() password: Yup.string()
}); });
const { email, password, profile, name } = userData; const { email, password, profile, name, queueIds = [] } = userData;
try { try {
await schema.validate({ email, password, profile, name }); await schema.validate({ email, password, profile, name });
@@ -57,11 +51,16 @@ const UpdateUserService = async ({
name name
}); });
await user.$set("queues", queueIds);
await user.reload();
const serializedUser = { const serializedUser = {
id: user.id, id: user.id,
name: user.name, name: user.name,
email: user.email, email: user.email,
profile: user.profile profile: user.profile,
queues: user.queues
}; };
return serializedUser; return serializedUser;

View File

@@ -18,7 +18,7 @@ interface Response {
const CreateWhatsAppService = async ({ const CreateWhatsAppService = async ({
name, name,
status = "OPENING", status = "OPENING",
queueIds, queueIds = [],
isDefault = false isDefault = false
}: Request): Promise<Response> => { }: Request): Promise<Response> => {
const schema = Yup.object().shape({ const schema = Yup.object().shape({
@@ -64,14 +64,19 @@ const CreateWhatsAppService = async ({
} }
} }
const whatsapp = await Whatsapp.create({ const whatsapp = await Whatsapp.create(
name, {
status, name,
isDefault status,
}); isDefault
},
{ include: ["queues"] }
);
await whatsapp.$set("queues", queueIds); await whatsapp.$set("queues", queueIds);
await whatsapp.reload();
return { whatsapp, oldDefaultWhatsapp }; return { whatsapp, oldDefaultWhatsapp };
}; };

View File

@@ -1,8 +1,13 @@
import Whatsapp from "../../models/Whatsapp"; import Whatsapp from "../../models/Whatsapp";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import Queue from "../../models/Queue";
const ShowWhatsAppService = async (id: string | number): Promise<Whatsapp> => { const ShowWhatsAppService = async (id: string | number): Promise<Whatsapp> => {
const whatsapp = await Whatsapp.findByPk(id); const whatsapp = await Whatsapp.findByPk(id, {
include: [
{ model: Queue, as: "queues", attributes: ["id", "name", "color"] }
]
});
if (!whatsapp) { if (!whatsapp) {
throw new AppError("ERR_NO_WAPP_FOUND", 404); throw new AppError("ERR_NO_WAPP_FOUND", 404);

View File

@@ -3,6 +3,7 @@ import { Op } from "sequelize";
import AppError from "../../errors/AppError"; import AppError from "../../errors/AppError";
import Whatsapp from "../../models/Whatsapp"; import Whatsapp from "../../models/Whatsapp";
import ShowWhatsAppService from "./ShowWhatsAppService";
interface WhatsappData { interface WhatsappData {
name?: string; name?: string;
@@ -50,13 +51,8 @@ const UpdateWhatsAppService = async ({
} }
} }
const whatsapp = await Whatsapp.findOne({ const whatsapp = await ShowWhatsAppService(whatsappId);
where: { id: whatsappId }
});
if (!whatsapp) {
throw new AppError("ERR_NO_WAPP_FOUND", 404);
}
await whatsapp.update({ await whatsapp.update({
name, name,
status, status,
@@ -66,6 +62,8 @@ const UpdateWhatsAppService = async ({
await whatsapp.$set("queues", queueIds); await whatsapp.$set("queues", queueIds);
await whatsapp.reload();
return { whatsapp, oldDefaultWhatsapp }; return { whatsapp, oldDefaultWhatsapp };
}; };