feat: Implement solution for searching by message content and fix bug when closing ticket
parent
beb4fd64c4
commit
e71150ff75
|
@ -0,0 +1,23 @@
|
||||||
|
const monthsAgo = (months: number) => {
|
||||||
|
const { subMonths, startOfMonth, format } = require("date-fns");
|
||||||
|
|
||||||
|
// Get the current date
|
||||||
|
const currentDate = new Date();
|
||||||
|
|
||||||
|
// Subtract 4 months from the current date
|
||||||
|
const monthsAgo = subMonths(currentDate, months);
|
||||||
|
|
||||||
|
// Get the start of the month for the current date and four months ago
|
||||||
|
// const startOfCurrentMonth = startOfMonth(currentDate);
|
||||||
|
const startMonthsAgo = startOfMonth(monthsAgo);
|
||||||
|
|
||||||
|
// Format the dates in YYYY-MM-DD format
|
||||||
|
// const formattedCurrentMonth = format(startOfCurrentMonth, "yyyy-MM-dd");
|
||||||
|
const formattedMonthsAgo = format(startMonthsAgo, "yyyy-MM-dd");
|
||||||
|
|
||||||
|
// console.log("Current Month:", formattedCurrentMonth);
|
||||||
|
// console.log("Months Ago:", formattedMonthsAgo);
|
||||||
|
return formattedMonthsAgo;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default monthsAgo;
|
|
@ -29,7 +29,7 @@ export async function getSimple(key: string) {
|
||||||
|
|
||||||
export async function get({ key, value, parse }: getData) {
|
export async function get({ key, value, parse }: getData) {
|
||||||
if (key.includes("*")) {
|
if (key.includes("*")) {
|
||||||
const keys = await redis.keys(key);
|
const keys = await redis.keys(key);
|
||||||
if (keys.length > 0) {
|
if (keys.length > 0) {
|
||||||
if (value) {
|
if (value) {
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
|
@ -70,7 +70,7 @@ export async function clearAllKeys(...keys: string[]) {
|
||||||
|
|
||||||
// If there are keys, delete them
|
// If there are keys, delete them
|
||||||
if (del_keys.length > 0) {
|
if (del_keys.length > 0) {
|
||||||
console.log("del_keys: ", del_keys);
|
// console.log("del_keys: ", del_keys);
|
||||||
await redis.del(...del_keys);
|
await redis.del(...del_keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,3 +220,5 @@ export async function getHashesWithPattern(
|
||||||
|
|
||||||
return hashes;
|
return hashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,18 @@ import { StartAllWhatsAppsSessions } from "./services/WbotServices/StartAllWhats
|
||||||
import User from "./models/User";
|
import User from "./models/User";
|
||||||
import Whatsapp from "./models/Whatsapp";
|
import Whatsapp from "./models/Whatsapp";
|
||||||
import endPointQuery from "./helpers/EndPointQuery";
|
import endPointQuery from "./helpers/EndPointQuery";
|
||||||
import { cacheSize, flushCache, loadTicketsCache } from "./helpers/TicketCache";
|
import {
|
||||||
|
cacheSize,
|
||||||
|
flushCache,
|
||||||
|
loadTicketsCache,
|
||||||
|
} from "./helpers/TicketCache";
|
||||||
|
|
||||||
import "./helpers/CloseBotTickets";
|
import "./helpers/CloseBotTickets";
|
||||||
import { loadContactsCache } from "./helpers/ContactsCache";
|
import { loadContactsCache } from "./helpers/ContactsCache";
|
||||||
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
import { loadSchedulesCache } from "./helpers/SchedulingNotifyCache";
|
||||||
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
import { delRestoreControllFile } from "./helpers/RestoreControll";
|
||||||
import "./helpers/AutoCloseTickets";
|
import "./helpers/AutoCloseTickets";
|
||||||
import "./helpers/AutoRemoteTickets"
|
import "./helpers/AutoRemoteTickets";
|
||||||
|
|
||||||
import "./helpers/SchedulingNotifySendMessage";
|
import "./helpers/SchedulingNotifySendMessage";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
@ -30,6 +34,7 @@ import { json } from "sequelize";
|
||||||
import { setBotInfo } from "./helpers/SetBotInfo";
|
import { setBotInfo } from "./helpers/SetBotInfo";
|
||||||
import Queue from "./models/Queue";
|
import Queue from "./models/Queue";
|
||||||
import StatusChatEnd from "./models/StatusChatEnd";
|
import StatusChatEnd from "./models/StatusChatEnd";
|
||||||
|
import Message from "./models/Message";
|
||||||
|
|
||||||
const server = app.listen(process.env.PORT, () => {
|
const server = app.listen(process.env.PORT, () => {
|
||||||
logger.info(`Server started on port: ${process.env.PORT}`);
|
logger.info(`Server started on port: ${process.env.PORT}`);
|
||||||
|
@ -50,7 +55,21 @@ gracefulShutdown(server);
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log("os.tmpdir(): ", os.tmpdir());
|
console.log("os.tmpdir(): ", os.tmpdir());
|
||||||
|
|
||||||
await clearAllKeys("user:*", "whatsapp:*", "queue:*", "statusChatEnd:*");
|
await clearAllKeys(
|
||||||
|
"user:*",
|
||||||
|
"whatsapp:*",
|
||||||
|
"queue:*",
|
||||||
|
"statusChatEnd:*",
|
||||||
|
);
|
||||||
|
|
||||||
|
// let messages: any = await Message.findAll({
|
||||||
|
// attributes: ["id", "ticketId", "body"]
|
||||||
|
// });
|
||||||
|
|
||||||
|
// for (const message of messages) {
|
||||||
|
// const { id, body, ticketId } = message;
|
||||||
|
// await set(`message:ticketId:${ticketId}:id:${id}`, body);
|
||||||
|
// }
|
||||||
|
|
||||||
const statusChatEnds = await StatusChatEnd.findAll();
|
const statusChatEnds = await StatusChatEnd.findAll();
|
||||||
|
|
||||||
|
@ -90,17 +109,17 @@ gracefulShutdown(server);
|
||||||
try {
|
try {
|
||||||
const { phoneNumberId, id, greetingMessage } = whatsapps[i];
|
const { phoneNumberId, id, greetingMessage } = whatsapps[i];
|
||||||
|
|
||||||
if (phoneNumberId) {
|
// if (phoneNumberId) {
|
||||||
// await set(
|
// await set(
|
||||||
// `whatsapp:${whatsapps[i].dataValues.id}`,
|
// `whatsapp:${whatsapps[i].dataValues.id}`,
|
||||||
// JSON.stringify({
|
// JSON.stringify({
|
||||||
// number: whatsapps[i].dataValues.number,
|
// number: whatsapps[i].dataValues.number,
|
||||||
// id,
|
// id,
|
||||||
// greetingMessage,
|
// greetingMessage,
|
||||||
// phoneNumberId
|
// phoneNumberId
|
||||||
// })
|
// })
|
||||||
// );
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
await set(
|
await set(
|
||||||
`whatsapp:${whatsapps[i].dataValues.id}`,
|
`whatsapp:${whatsapps[i].dataValues.id}`,
|
||||||
|
|
|
@ -15,12 +15,10 @@ const dateToday = splitDateTime(
|
||||||
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
new Date(format(new Date(), "yyyy-MM-dd HH:mm:ss", { locale: ptBR }))
|
||||||
);
|
);
|
||||||
|
|
||||||
import ListTicketServiceCache from "./ListTicketServiceCache";
|
|
||||||
|
|
||||||
import { searchTicketCache, loadTicketsCache } from "../../helpers/TicketCache";
|
|
||||||
import { getWbot } from "../../libs/wbot";
|
import { getWbot } from "../../libs/wbot";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
import { get } from "../../helpers/RedisClient";
|
import { get } from "../../helpers/RedisClient";
|
||||||
|
import monthsAgo from "../../helpers/MonthsAgo";
|
||||||
|
|
||||||
interface Request {
|
interface Request {
|
||||||
searchParam?: string;
|
searchParam?: string;
|
||||||
|
@ -54,7 +52,12 @@ const ListTicketsService = async ({
|
||||||
unlimited = "false",
|
unlimited = "false",
|
||||||
searchParamContent = ""
|
searchParamContent = ""
|
||||||
}: Request): Promise<Response> => {
|
}: Request): Promise<Response> => {
|
||||||
console.log("----------> searchParamContent: ", searchParamContent);
|
console.log(
|
||||||
|
"----------> searchParamContent: ",
|
||||||
|
searchParamContent,
|
||||||
|
" | searchParam: ",
|
||||||
|
searchParam
|
||||||
|
);
|
||||||
|
|
||||||
let whereCondition: Filterable["where"] = {
|
let whereCondition: Filterable["where"] = {
|
||||||
[Op.or]: [{ userId }, { status: "pending" }],
|
[Op.or]: [{ userId }, { status: "pending" }],
|
||||||
|
@ -67,46 +70,46 @@ const ListTicketsService = async ({
|
||||||
pageNumber = "1";
|
pageNumber = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
// if (searchParam && searchParam.trim().length > 0 && process.env.CACHE) {
|
||||||
try {
|
// try {
|
||||||
const offset = 40 * (+pageNumber - 1);
|
// const offset = 40 * (+pageNumber - 1);
|
||||||
|
|
||||||
searchParam = searchParam.replace(/\s+/g, " ").trim().toLowerCase();
|
// searchParam = searchParam.replace(/\s+/g, " ").trim().toLowerCase();
|
||||||
|
|
||||||
console.log("QUERY TICKET SEARCH PARAM FROM CACHE: ", searchParam);
|
// console.log("QUERY TICKET SEARCH PARAM FROM CACHE: ", searchParam);
|
||||||
|
|
||||||
let tickets: any = await searchTicketCache(searchParam, offset, 40);
|
// let tickets: any = await searchTicketCache(searchParam, offset, 40);
|
||||||
|
|
||||||
if (tickets) {
|
// if (tickets) {
|
||||||
console.log(
|
// console.log(
|
||||||
"QUERY TICKET SEARCH PARAM FROM CACHE LENGTH...: ",
|
// "QUERY TICKET SEARCH PARAM FROM CACHE LENGTH...: ",
|
||||||
tickets.length
|
// tickets.length
|
||||||
);
|
// );
|
||||||
|
|
||||||
tickets.map((t: any) => {
|
// tickets.map((t: any) => {
|
||||||
t["contact.number"] = t["contact_number"];
|
// t["contact.number"] = t["contact_number"];
|
||||||
delete t["contact_number"];
|
// delete t["contact_number"];
|
||||||
|
|
||||||
return { ...["contact_number"] };
|
// return { ...["contact_number"] };
|
||||||
});
|
// });
|
||||||
|
|
||||||
tickets = tickets.map((e: any) => unflatten(e));
|
// tickets = tickets.map((e: any) => unflatten(e));
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
tickets,
|
// tickets,
|
||||||
count: tickets.length,
|
// count: tickets.length,
|
||||||
hasMore: tickets.length > 0 ? true : false
|
// hasMore: tickets.length > 0 ? true : false
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
} catch (error) {
|
// } catch (error) {
|
||||||
console.log(
|
// console.log(
|
||||||
"There was an error on search ListTicketservice.ts search cache: ",
|
// "There was an error on search ListTicketservice.ts search cache: ",
|
||||||
error
|
// error
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log("QUERY TICKETS FROM DATABASE...");
|
// console.log("QUERY TICKETS FROM DATABASE...");
|
||||||
}
|
// }
|
||||||
|
|
||||||
let includeCondition: Includeable[];
|
let includeCondition: Includeable[];
|
||||||
|
|
||||||
|
@ -143,38 +146,32 @@ const ListTicketsService = async ({
|
||||||
|
|
||||||
if (searchParam) {
|
if (searchParam) {
|
||||||
const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
|
const sanitizedSearchParam = searchParam.toLocaleLowerCase().trim();
|
||||||
const sanitizedSearchParamContent = searchParamContent
|
|
||||||
.toLocaleLowerCase()
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
if (searchParamContent.length > 0) {
|
includeCondition = [
|
||||||
includeCondition = [
|
...includeCondition,
|
||||||
...includeCondition,
|
{
|
||||||
{
|
model: Message,
|
||||||
model: Message,
|
as: "messages",
|
||||||
as: "messages",
|
attributes: ["id", "body"],
|
||||||
attributes: ["id", "body"],
|
where: {
|
||||||
where: {
|
body: where(
|
||||||
body: where(
|
fn("LOWER", col("body")),
|
||||||
fn("LOWER", col("body")),
|
"LIKE",
|
||||||
"LIKE",
|
`%${sanitizedSearchParam}%`
|
||||||
`%${sanitizedSearchParamContent}%`
|
)
|
||||||
)
|
},
|
||||||
},
|
required: false,
|
||||||
required: false,
|
duplicating: false
|
||||||
duplicating: false
|
}
|
||||||
}
|
];
|
||||||
];
|
|
||||||
|
|
||||||
whereCondition = {
|
whereCondition = {
|
||||||
...whereCondition,
|
...whereCondition,
|
||||||
"$message.body$": where(
|
createdAt: {
|
||||||
fn("LOWER", col("body")),
|
[Op.gte]: monthsAgo(4) + " 00:00:00.000000",
|
||||||
"LIKE",
|
[Op.lte]: dateToday.fullDate + " 23:59:59.999999"
|
||||||
`%${sanitizedSearchParamContent}%`
|
}
|
||||||
)
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
whereCondition = {
|
whereCondition = {
|
||||||
...whereCondition,
|
...whereCondition,
|
||||||
|
@ -186,11 +183,65 @@ const ListTicketsService = async ({
|
||||||
`%${sanitizedSearchParam}%`
|
`%${sanitizedSearchParam}%`
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{ "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } },
|
||||||
{ "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } }
|
{
|
||||||
|
"$message.body$": where(
|
||||||
|
fn("LOWER", col("body")),
|
||||||
|
"LIKE",
|
||||||
|
`%${sanitizedSearchParam}%`
|
||||||
|
)
|
||||||
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const sanitizedSearchParamContent = searchParamContent
|
||||||
|
// .toLocaleLowerCase()
|
||||||
|
// .trim();
|
||||||
|
|
||||||
|
// if (searchParamContent.length > 0) {
|
||||||
|
// includeCondition = [
|
||||||
|
// ...includeCondition,
|
||||||
|
// {
|
||||||
|
// model: Message,
|
||||||
|
// as: "messages",
|
||||||
|
// attributes: ["id", "body"],
|
||||||
|
// where: {
|
||||||
|
// body: where(
|
||||||
|
// fn("LOWER", col("body")),
|
||||||
|
// "LIKE",
|
||||||
|
// `%${sanitizedSearchParamContent}%`
|
||||||
|
// )
|
||||||
|
// },
|
||||||
|
// required: false,
|
||||||
|
// duplicating: false
|
||||||
|
// }
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// whereCondition = {
|
||||||
|
// ...whereCondition,
|
||||||
|
// "$message.body$": where(
|
||||||
|
// fn("LOWER", col("body")),
|
||||||
|
// "LIKE",
|
||||||
|
// `%${sanitizedSearchParamContent}%`
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// whereCondition = {
|
||||||
|
// ...whereCondition,
|
||||||
|
// [Op.or]: [
|
||||||
|
// {
|
||||||
|
// "$contact.name$": where(
|
||||||
|
// fn("LOWER", col("contact.name")),
|
||||||
|
// "LIKE",
|
||||||
|
// `%${sanitizedSearchParam}%`
|
||||||
|
// )
|
||||||
|
// },
|
||||||
|
|
||||||
|
// { "$contact.number$": { [Op.like]: `%${sanitizedSearchParam}%` } }
|
||||||
|
// ]
|
||||||
|
// };
|
||||||
|
|
||||||
const userProfile: any = await User.findByPk(userId);
|
const userProfile: any = await User.findByPk(userId);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -243,8 +294,8 @@ const ListTicketsService = async ({
|
||||||
|
|
||||||
const hasMore = count > offset + tickets.length;
|
const hasMore = count > offset + tickets.length;
|
||||||
|
|
||||||
const ticketIds = await get({ key: `remote:controll`, parse: true });
|
const ticketIds = await get({ key: `remote:controll`, parse: true });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tickets,
|
tickets,
|
||||||
count,
|
count,
|
||||||
|
|
|
@ -75,16 +75,19 @@ const UpdateTicketService = async ({
|
||||||
del(`remote:ticketId:${ticket.id}`);
|
del(`remote:ticketId:${ticket.id}`);
|
||||||
|
|
||||||
let ticketsIds = await get({ key: `remote:controll`, parse: true });
|
let ticketsIds = await get({ key: `remote:controll`, parse: true });
|
||||||
const index = ticketsIds.findIndex((t: any) => t == ticket.id);
|
|
||||||
|
|
||||||
console.log("ticketsIds 1: ", ticketsIds);
|
if (ticketsIds) {
|
||||||
|
const index = ticketsIds.findIndex((t: any) => t == ticket.id);
|
||||||
|
|
||||||
if (index != -1) {
|
console.log("ticketsIds 1: ", ticketsIds);
|
||||||
ticketsIds.splice(index, 1);
|
|
||||||
|
|
||||||
console.log("ticketsIds 2: ", ticketsIds);
|
if (index != -1) {
|
||||||
|
ticketsIds.splice(index, 1);
|
||||||
|
|
||||||
set(`remote:controll`, JSON.stringify(ticketsIds));
|
console.log("ticketsIds 2: ", ticketsIds);
|
||||||
|
|
||||||
|
set(`remote:controll`, JSON.stringify(ticketsIds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,7 @@ const TicketsManager = () => {
|
||||||
{/* <IconButton onClick={() => setShowContentSearch(prev => !prev)}>
|
{/* <IconButton onClick={() => setShowContentSearch(prev => !prev)}>
|
||||||
<MenuIcon className={classes.menuSearch} />
|
<MenuIcon className={classes.menuSearch} />
|
||||||
</IconButton> */}
|
</IconButton> */}
|
||||||
<Tooltip
|
{/* <Tooltip
|
||||||
open={openTooltipSearch}
|
open={openTooltipSearch}
|
||||||
onOpen={() => handleOpenTooltipSearch()}
|
onOpen={() => handleOpenTooltipSearch()}
|
||||||
onClose={() => handleCloseTooltipSearch()}
|
onClose={() => handleCloseTooltipSearch()}
|
||||||
|
@ -360,22 +360,22 @@ const TicketsManager = () => {
|
||||||
<MenuIcon className={classes.menuSearch} />
|
<MenuIcon className={classes.menuSearch} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip> */}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
// showContentSearch ?
|
// showContentSearch ?
|
||||||
(showContentSearch && searchParam.searchParam.length >= 4) ?
|
// (showContentSearch /*&& searchParam.searchParam.length >= 4*/) ?
|
||||||
(<div className={classes.searchContentInput}>
|
// (<div className={classes.searchContentInput}>
|
||||||
<FindInPageIcon className={classes.searchIcon} />
|
// <FindInPageIcon className={classes.searchIcon} />
|
||||||
<InputBase
|
// <InputBase
|
||||||
className={classes.searchInput}
|
// className={classes.searchInput}
|
||||||
inputRef={searchContentInputRef}
|
// inputRef={searchContentInputRef}
|
||||||
placeholder={i18n.t("Busca por conteúdo")}
|
// placeholder={i18n.t("Busca por conteúdo")}
|
||||||
type="search"
|
// type="search"
|
||||||
value={inputContentSearch}
|
// value={inputContentSearch}
|
||||||
onChange={(e) => handleContentSearch(e)}
|
// onChange={(e) => handleContentSearch(e)}
|
||||||
/>
|
// />
|
||||||
</div>) : null
|
// </div>) : null
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
Loading…
Reference in New Issue