mirror of
https://github.com/cheveguerra/whaticket-community.git
synced 2026-04-19 04:09:26 +00:00
improvement: moved vcard parse logic to backend
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { QueryInterface, DataTypes } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.addColumn("Messages", "contactId", {
|
||||
type: DataTypes.INTEGER,
|
||||
references: { model: "Contacts", key: "id" },
|
||||
onUpdate: "CASCADE",
|
||||
onDelete: "CASCADE"
|
||||
});
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.removeColumn("Messages", "contactId");
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { QueryInterface, DataTypes } from "sequelize";
|
||||
|
||||
module.exports = {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.addColumn("Messages", "vcardContactId", {
|
||||
type: DataTypes.INTEGER,
|
||||
references: { model: "Contacts", key: "id" },
|
||||
onUpdate: "CASCADE",
|
||||
onDelete: "CASCADE"
|
||||
});
|
||||
},
|
||||
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return queryInterface.removeColumn("Messages", "vcardContactId");
|
||||
}
|
||||
};
|
||||
59
backend/src/helpers/ParseVcardToJson.ts
Normal file
59
backend/src/helpers/ParseVcardToJson.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
interface JCard {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface Meta {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
const ParseVcardToJson = (input: string): JCard => {
|
||||
const Re1 = /^(version|fn|title|org):(.+)$/i;
|
||||
const Re2 = /^([^:;]+);([^:]+):(.+)$/;
|
||||
const ReKey = /item\d{1,2}\./;
|
||||
const fields = {} as JCard;
|
||||
|
||||
input.split(/\r\n|\r|\n/).forEach(line => {
|
||||
let results;
|
||||
let key;
|
||||
|
||||
if (Re1.test(line)) {
|
||||
results = line.match(Re1);
|
||||
if (results) {
|
||||
key = results[1].toLowerCase();
|
||||
const [, , res] = results;
|
||||
fields[key] = res;
|
||||
}
|
||||
} else if (Re2.test(line)) {
|
||||
results = line.match(Re2);
|
||||
if (results) {
|
||||
key = results[1].replace(ReKey, "").toLowerCase();
|
||||
|
||||
const meta = {} as Meta;
|
||||
results[2]
|
||||
.split(";")
|
||||
.map((p, i) => {
|
||||
const match = p.match(/([a-z]+)=(.*)/i);
|
||||
if (match) {
|
||||
return [match[1], match[2]];
|
||||
}
|
||||
return [`TYPE${i === 0 ? "" : i}`, p];
|
||||
})
|
||||
.forEach(p => {
|
||||
const [, m] = p;
|
||||
meta[p[0]] = m;
|
||||
});
|
||||
|
||||
if (!fields[key]) fields[key] = [];
|
||||
|
||||
fields[key].push({
|
||||
meta,
|
||||
value: results[3].split(";")
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return fields;
|
||||
};
|
||||
|
||||
export default ParseVcardToJson;
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
BelongsTo,
|
||||
ForeignKey
|
||||
} from "sequelize-typescript";
|
||||
import Contact from "./Contact";
|
||||
import Ticket from "./Ticket";
|
||||
|
||||
@Table
|
||||
@@ -64,6 +65,20 @@ class Message extends Model<Message> {
|
||||
|
||||
@BelongsTo(() => Ticket)
|
||||
ticket: Ticket;
|
||||
|
||||
@ForeignKey(() => Contact)
|
||||
@Column
|
||||
contactId: number;
|
||||
|
||||
@BelongsTo(() => Contact, "contactId")
|
||||
contact: Contact;
|
||||
|
||||
@ForeignKey(() => Contact)
|
||||
@Column
|
||||
vcardContactId: number;
|
||||
|
||||
@BelongsTo(() => Contact, "vcardContactId")
|
||||
vcardContact: Contact;
|
||||
}
|
||||
|
||||
export default Message;
|
||||
|
||||
@@ -44,6 +44,7 @@ const ListMessagesService = async ({
|
||||
const { count, rows: messages } = await Message.findAndCountAll({
|
||||
where: whereCondition,
|
||||
limit,
|
||||
include: ["contact", "vcardContact"],
|
||||
offset,
|
||||
order: [["createdAt", "DESC"]]
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ import { getIO } from "../../libs/socket";
|
||||
import { getWbot } from "../../libs/wbot";
|
||||
import AppError from "../../errors/AppError";
|
||||
import ShowTicketService from "../TicketServices/ShowTicketService";
|
||||
import ParseVcardToJson from "../../helpers/ParseVcardToJson";
|
||||
|
||||
const writeFileAsync = promisify(writeFile);
|
||||
|
||||
@@ -161,9 +162,8 @@ const handlMedia = async (
|
||||
|
||||
const newMessage: Message = await ticket.$create("message", {
|
||||
id: msg.id.id,
|
||||
body: msg.fromMe
|
||||
? `${msg.body ? msg.body : media.filename}`
|
||||
: `${contact.name}: ${msg.body ? msg.body : media.filename}`,
|
||||
contactId: msg.fromMe ? null : contact.id,
|
||||
body: msg.body || media.filename,
|
||||
fromMe: msg.fromMe,
|
||||
mediaUrl: media.filename,
|
||||
mediaType: media.mimetype.split("/")[0]
|
||||
@@ -175,21 +175,28 @@ const handlMedia = async (
|
||||
const handleMessage = async (
|
||||
msg: WbotMessage,
|
||||
ticket: Ticket,
|
||||
contact: Contact
|
||||
contact: Contact,
|
||||
vcardContact?: Contact
|
||||
) => {
|
||||
let newMessage: Message;
|
||||
let newMessage: Message | null;
|
||||
|
||||
if (msg.hasMedia) {
|
||||
newMessage = await handlMedia(msg, ticket, contact);
|
||||
} else {
|
||||
newMessage = await ticket.$create("message", {
|
||||
const { id } = await ticket.$create("message", {
|
||||
id: msg.id.id,
|
||||
body: msg.fromMe ? msg.body : `${contact.name}: ${msg.body}`,
|
||||
contactId: msg.fromMe ? null : contact.id,
|
||||
vcardContactId: vcardContact ? vcardContact.id : null,
|
||||
body: msg.body,
|
||||
fromMe: msg.fromMe,
|
||||
mediaType: msg.type,
|
||||
read: msg.fromMe
|
||||
});
|
||||
await ticket.update({ lastMessage: msg.body });
|
||||
|
||||
newMessage = await Message.findByPk(id, {
|
||||
include: ["contact", "vcardContact"]
|
||||
});
|
||||
}
|
||||
|
||||
const io = getIO();
|
||||
@@ -234,13 +241,15 @@ const wbotMessageListener = (whatsapp: Whatsapp): void => {
|
||||
try {
|
||||
let msgContact: WbotContact;
|
||||
let groupContact: Contact | undefined;
|
||||
let vcardContact: Contact | undefined;
|
||||
|
||||
if (msg.fromMe) {
|
||||
msgContact = await wbot.getContactById(msg.to);
|
||||
|
||||
// return if it's a media message, it will be handled by media_uploaded event
|
||||
|
||||
if (msg.hasMedia || msg.type !== "chat") return;
|
||||
if (msg.hasMedia || (msg.type !== "chat" && msg.type !== "vcard"))
|
||||
return;
|
||||
} else {
|
||||
msgContact = await msg.getContact();
|
||||
}
|
||||
@@ -252,11 +261,20 @@ const wbotMessageListener = (whatsapp: Whatsapp): void => {
|
||||
groupContact = await verifyGroup(msgGroupContact);
|
||||
}
|
||||
|
||||
if (msg.type === "vcard") {
|
||||
const { tel } = ParseVcardToJson(msg.body);
|
||||
const vcardWaid = tel[0]?.meta?.waid;
|
||||
const vcardMsgContact = await wbot.getContactById(`${vcardWaid}@c.us`);
|
||||
const profilePicUrl = await vcardMsgContact.getProfilePicUrl();
|
||||
|
||||
vcardContact = await verifyContact(vcardMsgContact, profilePicUrl);
|
||||
}
|
||||
|
||||
const profilePicUrl = await msgContact.getProfilePicUrl();
|
||||
const contact = await verifyContact(msgContact, profilePicUrl);
|
||||
const ticket = await verifyTicket(contact, whatsappId, groupContact);
|
||||
|
||||
await handleMessage(msg, ticket, contact);
|
||||
await handleMessage(msg, ticket, contact, vcardContact);
|
||||
} catch (err) {
|
||||
Sentry.captureException(err);
|
||||
console.log(err);
|
||||
|
||||
Reference in New Issue
Block a user