feat: Support IVR(ura) for bot interactions, optimize botqueue user checks, and allow supervisor to view all tickets

pull/22/head
adriano 2024-02-05 12:29:49 -03:00
parent dfa4be6253
commit ad89d3ccdb
14 changed files with 767 additions and 69 deletions

View File

@ -5,6 +5,9 @@ import DeleteQueueService from "../services/QueueService/DeleteQueueService";
import ListQueuesService from "../services/QueueService/ListQueuesService";
import ShowQueueService from "../services/QueueService/ShowQueueService";
import UpdateQueueService from "../services/QueueService/UpdateQueueService";
import Queue from "../models/Queue"
import AppError from "../errors/AppError"
import { get, set } from "../helpers/RedisClient";
@ -28,6 +31,106 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
return res.status(200).json(queue);
};
export const customization = async (
req: Request,
res: Response
): Promise<Response> => {
const { ura } = req.body;
if (!ura) throw new AppError("BAD REQUEST", 400);
let new_queues: any;
if (ura.length > 0) {
new_queues = ura
.filter(
(u: any) =>
u.idmaster === ura[1].id &&
u?.queueName &&
u?.color &&
u?.greetingMessage
)
.map((u: any) => {
const { queueName, color, greetingMessage } = u;
return {
queueName: queueName?.trim()?.replace(/\s+/g, " "),
color,
greetingMessage
};
});
if (new_queues && new_queues.length > 0) {
const db_queues: any = await Queue.findAll();
for (const i in new_queues) {
let { queueName: name, color, greetingMessage } = new_queues[i];
name = name?.trim()?.replace(/\s+/g, " ");
const update = db_queues.find(
(q: any) => q.name?.trim()?.replace(/\s+/g, " ") == name
);
if (update) {
const { id } = update;
// UPDATE
// const queue = await UpdateQueueService(id, {
// name,
// color,
// greetingMessage
// });
// const io = getIO();
// io.emit("queue", {
// action: "update",
// queue
// });
} else {
// CREATE
// const queue = await CreateQueueService({
// name,
// color,
// greetingMessage
// });
// const io = getIO();
// io.emit("queue", {
// action: "update",
// queue
// });
}
}
let remove_queues = db_queues.filter(
(q: any) =>
!new_queues
.map((nq: any) => nq.queueName)
.includes(q.name?.trim()?.replace(/\s+/g, " "))
);
for (const i in remove_queues) {
const { id, name } = remove_queues[i];
// await DeleteQueueService(id);
// const io = getIO();
// io.emit("queue", {
// action: "delete",
// queueId: +id
// });
}
// await set("ura", ura);
}
}
await set("ura", ura);
const _ura = await get("ura");
console.log("_URA: ", _ura);
return res.status(200).json({ new_queues });
};
export const show = async (req: Request, res: Response): Promise<Response> => {
const { queueId } = req.params;

View File

@ -110,11 +110,13 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
const { contactId, status, userId, msg, queueId, whatsappId }: TicketData =
req.body;
const botInfo = await BotIsOnQueue("botqueue");
let ticket = await Ticket.findOne({
where: {
[Op.or]: [
{ contactId, status: "queueChoice" }
// { contactId, status: "open", userId: botInfo.userIdBot }
{ contactId, status: "queueChoice" },
{ contactId, status: "open", userId: botInfo.userIdBot }
]
}
});

View File

@ -12,6 +12,7 @@ import DeleteUserService from "../services/UserServices/DeleteUserService";
import ListUser from "../services/UserServices/ListUserParamiterService";
import User from "../models/User";
import { get, set } from "../helpers/RedisClient";
import {
startWhoIsOnlineMonitor,
@ -134,7 +135,8 @@ export const all = async (req: Request, res: Response): Promise<Response> => {
};
export const store = async (req: Request, res: Response): Promise<Response> => {
const { email, password, name, profile, positionCompany, queueIds } = req.body;
const { email, password, name, profile, positionCompany, queueIds } =
req.body;
console.log("===========> req.url: ", req.url);
@ -149,13 +151,10 @@ export const store = async (req: Request, res: Response): Promise<Response> => {
getSettingValue("userCreation")?.value == "disabled"
) {
throw new AppError("ERR_USER_CREATION_DISABLED", 403);
} else if (
req.user.profile !== "master"
) {
} else if (req.user.profile !== "master") {
throw new AppError("ERR_NO_PERMISSION", 403);
}
const user = await CreateUserService({
email,
password,
@ -266,12 +265,38 @@ export const update = async (
}
}
// console.log('userQueuesAttendance: ', userQueuesAttendance)
// return res.status(200).json({});
let user: any = await UpdateUserService({ userData, userId });
if (user?.name?.trim() == "botqueue") {
let botInfo;
if (
user?.queues?.length > 0 &&
user.queues[0]?.name?.trim() == "botqueue"
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: user.queues[0].id,
botIsOnQueue: true
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
} else if (
user?.queues?.length == 0 ||
user.queues[0]?.name?.trim() != "botqueue"
) {
botInfo = JSON.stringify({
userId: user.id,
queueId: 0,
botIsOnQueue: false
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
}
}
const io = getIO();
io.emit("user", {
action: "update",

View File

@ -1,37 +1,26 @@
const fsPromises = require("fs/promises");
const fs = require('fs')
const fs = require("fs");
import ListUsersService from "../services/UserServices/ListUsersService"
import ListUsersService from "../services/UserServices/ListUsersService";
import { get } from "./RedisClient";
const _botIsOnQueue = async (botName: string) => {
const { users, count, hasMore } = await ListUsersService({searchParam:`${botName}`,pageNumber:1});
let botIsOnQueue = false
let userIdBot = null
let queueId = null
if(users.length > 0){
try {
console.log('----------------- bot queue id: ', Object(users)[0]["queues"][0].id)
queueId = Object(users)[0]["queues"][0].id;
userIdBot = Object(users)[0].id
botIsOnQueue = true
}catch(err){
console.log('O usuário botqueue não está em nenhuma fila err: ',err)
}
}
else{
console.log('Usuário botqueue não existe!')
}
return { userIdBot: userIdBot, botQueueId: queueId, isOnQueue: botIsOnQueue }
const botInfo = await get("botInfo");
if (
botInfo &&
botInfo?.userId &&
botInfo?.queueId &&
botInfo?.botIsOnQueue == true
) {
return {
userIdBot: botInfo.userId,
botQueueId: botInfo.queueId,
isOnQueue: botInfo.botIsOnQueue
};
}
return { userIdBot: null, botQueueId: null, isOnQueue: false };
};
export default _botIsOnQueue;
export default _botIsOnQueue;

View File

@ -0,0 +1,54 @@
import ListTicketTimeLife from "../services/TicketServices/ListTicketTimeLife";
import UpdateTicketService from "../services/TicketServices/UpdateTicketService";
import BotIsOnQueue from "./BotIsOnQueue";
const fsPromises = require("fs/promises");
const fs = require('fs')
let timer: any
const CloseBotTickets = async () => {
try {
const botInfo = await BotIsOnQueue('botqueue')
if (!botInfo.userIdBot) return
let tickets: any = await ListTicketTimeLife({ timeseconds: 60, status: 'open', userId: botInfo.userIdBot })
console.log('tickets: ', tickets)
for (let i = 0; i < tickets.length; i++) {
await UpdateTicketService({
ticketData: { 'status': 'closed', 'userId': botInfo.userIdBot, 'statusChatEnd': 'FINALIZADO' },
ticketId: tickets[i].ticket_id
});
}
} catch (error) {
console.log('There was an error on try close the bot tickets: ', error)
}
}
const schedule = async () => {
try {
clearInterval(timer);
await CloseBotTickets()
} catch (error) {
console.log('error on schedule: ', error)
}
finally {
timer = setInterval(schedule, 60000);
}
}
timer = setInterval(schedule, 60000);
export default schedule;

View File

@ -0,0 +1,130 @@
const Redis = require("ioredis");
const redis = new Redis(process.env.REDIS_URI);
type WhatsappData = {
whatsappId: string;
contactId: string;
identifier: string;
value?: string;
};
export async function set(key: string, value: string) {
await redis.set(key, JSON.stringify(value));
}
export async function get(key: string) {
const value: any = await redis.get(key);
return JSON.parse(value);
}
export async function createObject({
whatsappId,
contactId,
identifier,
value
}: WhatsappData) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
const result = await redis.hmset(
key,
"whatsappId",
whatsappId,
"contactId",
contactId,
"identifier",
identifier,
"value",
value
);
await redis.expire(key, 300);
}
export async function updateObject({
whatsappId,
contactId,
identifier,
value
}: WhatsappData) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
await redis.hset(key, "value", value);
}
export async function findObject(
whatsappId: string,
contactId: string,
identifier: string
) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
const result = await redis.hmget(
key,
"whatsappId",
"contactId",
"identifier",
"value"
);
return result;
}
export async function deleteObject(
whatsappId: string,
contactId: string,
identifier: string
) {
const key = `whatsappId:${whatsappId}:contactId:${contactId}:identifier:${identifier}`;
const deletedCount = await redis.del(key);
}
export async function deleteKeysWithPattern(
whatsappId: string,
contactId: string
) {
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
let cursor = "0";
do {
const [newCursor, keys] = await redis.scan(
cursor,
"MATCH",
pattern,
"COUNT",
"100"
);
for (const key of keys) {
await redis.del(key);
}
cursor = newCursor;
} while (cursor !== "0");
}
export async function getHashesWithPattern(
whatsappId: string,
contactId: string
) {
const pattern = `whatsappId:${whatsappId}:contactId:${contactId}:*`;
let cursor = "0";
const hashes = [];
do {
const [newCursor, keys] = await redis.scan(
cursor,
"MATCH",
pattern,
"COUNT",
"100"
);
for (const key of keys) {
const hash = await redis.hgetall(key);
hashes.push(hash);
}
cursor = newCursor;
} while (cursor !== "0");
return hashes;
}

View File

@ -9,6 +9,8 @@ queueRoutes.get("/queue", isAuth, QueueController.index);
queueRoutes.post("/queue", isAuth, QueueController.store);
queueRoutes.post("/queue/customization", QueueController.customization);
queueRoutes.get("/queue/:queueId", isAuth, QueueController.show);
queueRoutes.put("/queue/:queueId", isAuth, QueueController.update);

View File

@ -7,6 +7,8 @@ import User from "./models/User";
import Whatsapp from "./models/Whatsapp";
import endPointQuery from "./helpers/EndPointQuery";
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
import "./helpers/CloseBotTickets";
import { loadContactsCache } from "./helpers/ContactsCache";
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
import { delRestoreControllFile } from "./helpers/RestoreControll";

View File

@ -0,0 +1,147 @@
import { subHours, subMinutes, subSeconds } from "date-fns";
import { Op } from "sequelize";
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
import Contact from "../../models/Contact";
import Ticket from "../../models/Ticket";
import ShowWhatsAppService from "../WhatsappService/ShowWhatsAppService";
import ShowTicketService from "./ShowTicketService";
import AppError from "../../errors/AppError";
import { userInfo } from "os";
import ShowQueueService from "../QueueService/ShowQueueService";
import UpdateTicketService from "./UpdateTicketService";
const FindOrCreateTicketServiceBot = async (
contact: Contact,
whatsappId: number,
unreadMessages: number,
groupContact?: Contact
): Promise<any> => {
try {
let ticket = await Ticket.findOne({
where: {
status: {
[Op.or]: ["open", "pending", "queueChoice"]
},
contactId: groupContact ? groupContact.id : contact.id
}
});
const { queues, greetingMessage } = await ShowWhatsAppService(whatsappId);
//Habilitar esse caso queira usar o bot
const botInfo = await BotIsOnQueue('botqueue')
// const botInfo = { isOnQueue: false }
if (ticket) {
await ticket.update({ unreadMessages });
}
// if (!ticket && groupContact) {
// ticket = await Ticket.findOne({
// where: {
// contactId: groupContact.id
// },
// order: [["updatedAt", "DESC"]]
// });
// if (ticket) {
// await ticket.update({
// status: "pending",
// userId: null,
// unreadMessages
// });
// }
// }
if (!ticket && !groupContact) {
console.log('BOT CREATING OR REOPENING THE TICKET')
ticket = await Ticket.findOne({
where: {
contactId: contact.id,
userId: botInfo.userIdBot
},
order: [["updatedAt", "DESC"]]
});
if (ticket) {
await ticket.update({
status: "open",
userId: botInfo.userIdBot,
unreadMessages
});
console.log('lxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
await dialogFlowStartContext(contact, ticket, botInfo);
}
}
let created = false
if (!ticket) {
created = true
let status = "open"
if (queues.length > 1 && !botInfo.isOnQueue) {
status = "queueChoice"
}
ticket = await Ticket.create({
contactId: groupContact ? groupContact.id : contact.id,
status: status,
userId: botInfo.userIdBot,
isGroup: !!groupContact,
unreadMessages,
whatsappId
});
console.log('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
await dialogFlowStartContext(contact, ticket, botInfo);
}
ticket = await ShowTicketService(ticket.id);
return { ticket, created };
} catch (error: any) {
console.error('===> Error on FindOrCreateTicketServiceBot.ts file: \n', error)
throw new AppError(error.message);
}
};
export default FindOrCreateTicketServiceBot;
async function dialogFlowStartContext(contact: Contact, ticket: Ticket, botInfo: any) {
let msg: any = { type: 'chat', from: `${contact.number}@c.us`, body: '0' };
let queue = await ShowQueueService(botInfo.botQueueId);
await UpdateTicketService({
ticketData: { queueId: queue.id },
ticketId: ticket.id
});
ticket = await ShowTicketService(ticket.id);
// await sendDialogflowAnswer(ticket.whatsappId, ticket, msg, contact, false);
}

View File

@ -9,6 +9,8 @@ import ShowTicketService from "./ShowTicketService";
import { createOrUpdateTicketCache } from "../../helpers/TicketCache";
import AppError from "../../errors/AppError";
import sendWhatsAppMessageSocket from "../../helpers/SendWhatsappMessageSocket";
import BotIsOnQueue from "../../helpers/BotIsOnQueue";
import { deleteObject } from "../../helpers/RedisClient"
var flatten = require("flat");
interface TicketData {
@ -49,6 +51,15 @@ const UpdateTicketService = async ({
const ticket = await ShowTicketService(ticketId);
const botInfo = await BotIsOnQueue("botqueue");
if (
status == "closed" ||
(status == "open" && ticket && `${userId}` != `${botInfo.userIdBot}`)
) {
deleteObject(`${ticket.whatsappId}`, `${ticket.contactId}`, "ura");
}
const oldStatus = ticket.status;
const oldUserId = ticket.user?.id;
@ -68,7 +79,6 @@ const UpdateTicketService = async ({
await ticket.reload();
if (msg?.trim().length > 0) {
setTimeout(async () => {
sendWhatsAppMessageSocket(ticket, msg);
}, 2000);

View File

@ -2,7 +2,7 @@ import User from "../../models/User";
import AppError from "../../errors/AppError";
import Ticket from "../../models/Ticket";
import UpdateDeletedUserOpenTicketsStatus from "../../helpers/UpdateDeletedUserOpenTicketsStatus";
import { set } from "../../helpers/RedisClient"
const DeleteUserService = async (id: string | number): Promise<void> => {
const user = await User.findOne({
@ -13,6 +13,17 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
throw new AppError("ERR_NO_USER_FOUND", 404);
}
if (user?.name?.trim() == "botqueue") {
let botInfo = JSON.stringify({
userId: 0,
queueId: 0,
botIsOnQueue: false
});
botInfo = JSON.parse(botInfo);
await set("botInfo", botInfo);
}
const userOpenTickets: Ticket[] = await user.$get("tickets", {
where: { status: "open" }
});
@ -21,9 +32,7 @@ const DeleteUserService = async (id: string | number): Promise<void> => {
UpdateDeletedUserOpenTicketsStatus(userOpenTickets);
}
await user.destroy();
};
export default DeleteUserService;

View File

@ -88,6 +88,7 @@ import { Op } from "sequelize";
import SettingTicket from "../../models/SettingTicket";
import mostRepeatedPhrase from "../../helpers/MostRepeatedPhrase";
import ListWhatsAppsNumber from "../WhatsappService/ListWhatsAppsNumber";
import { createObject, findObject, get } from "../../helpers/RedisClient";
var lst: any[] = getWhatsappIds();
@ -298,8 +299,8 @@ const verifyQueue = async (
let choosenQueue = null;
//Habilitar esse caso queira usar o bot
// const botInfo = await BotIsOnQueue('botqueue')
const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
const botInfo = await BotIsOnQueue("botqueue");
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
if (botInfo.isOnQueue) {
choosenQueue = await ShowQueueService(botInfo.botQueueId);
@ -337,9 +338,17 @@ const verifyQueue = async (
ticketId: ticket.id
});
data_ura.forEach((s, index) => {
botOptions += `*${index + 1}* - ${s.option}\n`;
const data = await get("ura");
await createObject({
whatsappId: `${ticket.whatsappId}`,
contactId: `${ticket.contactId}`,
identifier: "ura",
value: data[1].id
});
botSendMessage(ticket, data[1].value);
return;
}
//
@ -479,12 +488,35 @@ const queuesOutBot = async (wbot: Session, botId: string | number) => {
return { queues, greetingMessage };
};
const botTransferTicket = async (
queues: Queue,
ticket: Ticket,
contact: Contact,
wbot: Session
) => {
const transferTicket = async (queueName: any, wbot: any, ticket: Ticket) => {
const botInfo = await BotIsOnQueue("botqueue");
console.log("kkkkkkkkkkkkkkkkkkkkk queueName: ", queueName);
const queuesWhatsGreetingMessage = await queuesOutBot(
wbot,
botInfo.botQueueId
);
let queue: any;
const queues = queuesWhatsGreetingMessage.queues;
// console.log("queues ---> ", console.log(JSON.stringify(queues, null, 6)));
if (typeof queueName == "string") {
queue = queues.find(
(q: any) => q?.name?.toLowerCase() == queueName.trim().toLowerCase()
);
// await deleteObject(wbot.id, `${ticket.contactId}`, "ura");
} else if (typeof queueName == "number") {
queue = queues[queueName];
}
if (queue) await botTransferTicket(queue, ticket);
};
const botTransferTicket = async (queues: Queue, ticket: Ticket) => {
await ticket.update({ userId: null });
await UpdateTicketService({
@ -683,9 +715,72 @@ const handleMessage = async (
// O bot interage com o cliente e encaminha o atendimento para fila de atendende quando o usuário escolhe a opção falar com atendente
//Habilitar esse caso queira usar o bot
// const botInfo = await BotIsOnQueue('botqueue')
const botInfo = await BotIsOnQueue("botqueue");
// const botInfo = { isOnQueue: false, botQueueId: 0, userIdBot: 0 };
if (
botInfo.isOnQueue &&
!msg.fromMe &&
ticket.userId == botInfo.userIdBot
) {
const repet: any = await mostRepeatedPhrase(ticket.id);
console.log("repet.occurrences: ", repet.occurrences);
if (repet.occurrences > 4) {
await transferTicket(0, wbot, ticket);
await SendWhatsAppMessage({
body: `Seu atendimento foi transferido para um agente!\n\nPara voltar ao menu principal digite *0*
`,
ticket,
number: `${contact.number}@c.us`
});
} else {
console.log("MSG body: ", msg.body);
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
console.log("menuMsg: ", menuMsg);
await botSendMessage(ticket, menuMsg.value);
if (
menuMsg?.transferToQueue &&
menuMsg.transferToQueue.trim().length > 0
) {
console.log(
"YYYYYYYYYYYYYYYYYYYY menuMsg.transferToQueue: ",
menuMsg.transferToQueue
);
transferTicket(menuMsg.transferToQueue.trim(), wbot, ticket);
}
}
return;
} else if (
!msg.fromMe &&
msg.body == "0" &&
ticket.status == "pending" &&
ticket.queueId
) {
let choosenQueue = await ShowQueueService(botInfo.botQueueId);
await UpdateTicketService({
ticketData: {
status: "open",
userId: botInfo.userIdBot,
queueId: choosenQueue.id
},
ticketId: ticket.id
});
const menuMsg: any = await menu(msg.body, wbot.id, contact.id);
await botSendMessage(ticket, menuMsg.value);
return;
}
if (msg && !msg.fromMe && ticket.status == "pending") {
await setMessageAsRead(ticket);
}
@ -720,6 +815,133 @@ const handleMessage = async (
}
};
const menu = async (userTyped: string, whatsappId: any, contactId: any) => {
let lastId = await findObject(whatsappId, contactId, "ura");
const data: any = await get("ura");
console.log("lastId[0]: ", lastId[0]);
if (!lastId[0]) {
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: data[1].id
});
}
lastId = await findObject(whatsappId, contactId, "ura");
console.log("LAST ID: ", lastId);
let option: any;
if (
lastId &&
lastId.length == 4 &&
lastId[3] &&
lastId[3].trim().length > 0
) {
option = data.find(
(o: any) =>
o.idmaster == lastId[3] &&
o.value.toLowerCase() == userTyped.toLowerCase()
);
// TEST DEL
console.log("OPTION: ", option);
if (!option && userTyped != "0") {
if (!existSubMenu()) {
const response = await mainOptionsMenu(userTyped);
if (response) return response;
else {
console.log("kkkkkkkkkkkkkkkkkkk");
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: data[1].id
});
return data[1];
}
}
}
//
if (option) {
let response: any = data.find((o: any) => o.idmaster == option.id);
console.log(
"RRRRRRRRRRRRRRRRRRRRRRRRRRRRR response: ",
response,
" | option: ",
option
);
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: response.id
});
return response;
} else if (userTyped == "0") {
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: data[1].id
});
return data[1];
} else {
console.log("INVALID SEARCH");
let response = await existSubMenu();
if (response) return response;
return {
value: data.find((o: any) => o.id == lastId[3])?.value
};
// return {
// value: `Você digitou uma opçao inválida!\n\n${
// data.find((o: any) => o.id == lastId[3])?.value
// }\n\nDigite 0 para voltar ao menu `
// };
}
}
function existSubMenu() {
let existSubMenu = data.find((o: any) => o.idmaster == lastId[3]);
if (existSubMenu) true;
return false;
}
async function mainOptionsMenu(userTyped: any) {
let menuOption = data.find(
(o: any) => o.value.toLowerCase() == userTyped.toLowerCase()
);
console.log("============> menuOption OPTION: ", menuOption);
if (menuOption) {
let response = data.find((o: any) => o.idmaster == menuOption.id);
if (response) {
await createObject({
whatsappId,
contactId,
identifier: "ura",
value: response.id
});
return response;
}
}
}
};
const handleMsgAck = async (
msg_id: any,
ack: any,

View File

@ -161,7 +161,9 @@ const TicketsManager = () => {
let searchContentTimeout;
useEffect(() => {
if (user.profile.toUpperCase() === "ADMIN") {
if (user.profile.toUpperCase() === "ADMIN" ||
user.profile.toUpperCase() === "SUPERVISOR" ||
user.profile.toUpperCase() === "MASTER") {
setShowAllTickets(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps

View File

@ -9,7 +9,8 @@ const rules = {
"user-view:show",
"user-modal:editQueues",
'dashboard-view:show',
'ticket-report:show'
'ticket-report:show',
'tickets-manager:showall'
]
},