feat: chatwoot integration completed

This commit is contained in:
Davidson Gomes 2023-07-12 20:28:51 -03:00
parent 514fb56209
commit 052303cc93
5 changed files with 507 additions and 25 deletions

View File

@ -45,4 +45,11 @@ export class ChatwootController {
logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance'); logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance');
return this.chatwootService.find(instance); return this.chatwootService.find(instance);
} }
public async receiveWebhook(instance: InstanceDto, data: any) {
logger.verbose(
'requested receiveWebhook from ' + instance.instanceName + ' instance',
);
return this.chatwootService.receiveWebhook(instance, data);
}
} }

View File

@ -3,6 +3,7 @@ import { dbserver } from '../../db/db.connect';
export class ChatwootRaw { export class ChatwootRaw {
_id?: string; _id?: string;
enabled?: boolean;
account_id?: string; account_id?: string;
token?: string; token?: string;
url?: string; url?: string;
@ -11,6 +12,7 @@ export class ChatwootRaw {
const chatwootSchema = new Schema<ChatwootRaw>({ const chatwootSchema = new Schema<ChatwootRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true },
account_id: { type: String, required: true }, account_id: { type: String, required: true },
token: { type: String, required: true }, token: { type: String, required: true },
url: { type: String, required: true }, url: { type: String, required: true },

View File

@ -46,11 +46,21 @@ export class ChatwootRouter extends RouterBroker {
res.status(HttpStatus.OK).json(response); res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('webhook'), ...guards, async (req, res) => { .post(this.routerPath('webhook'), async (req, res) => {
const { body } = req; logger.verbose('request received in findChatwoot');
const { instance } = req.query; logger.verbose('request body: ');
logger.verbose(req.body);
res.status(HttpStatus.OK).json({ message: 'bot' }); logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: instanceNameSchema,
ClassRef: InstanceDto,
execute: (instance, data) => chatwootController.receiveWebhook(instance, data),
});
res.status(HttpStatus.OK).json(response);
}); });
} }

View File

@ -1,11 +1,16 @@
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import path from 'path';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { WAMonitoringService } from './monitor.service'; import { WAMonitoringService } from './monitor.service';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import ChatwootClient from '@figuro/chatwoot-sdk'; import ChatwootClient from '@figuro/chatwoot-sdk';
import { createReadStream, unlinkSync } from 'fs'; import { createReadStream, unlinkSync, writeFileSync } from 'fs';
import axios from 'axios'; import axios from 'axios';
import FormData from 'form-data'; import FormData from 'form-data';
import { SendTextDto } from '../dto/sendMessage.dto';
import mimeTypes from 'mime-types';
import { SendAudioDto } from '../dto/sendMessage.dto';
import { SendMediaDto } from '../dto/sendMessage.dto';
export class ChatwootService { export class ChatwootService {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}
@ -71,7 +76,7 @@ export class ChatwootService {
} }
const contact = await client.contact.getContactable({ const contact = await client.contact.getContactable({
accountId: this.provider.accountId, accountId: this.provider.account_id,
id, id,
}); });
@ -92,7 +97,7 @@ export class ChatwootService {
} }
const contact = await client.contacts.create({ const contact = await client.contacts.create({
accountId: this.provider.accountId, accountId: this.provider.account_id,
data: { data: {
inbox_id: inboxId, inbox_id: inboxId,
name: name || phoneNumber, name: name || phoneNumber,
@ -115,7 +120,7 @@ export class ChatwootService {
} }
const contact = await client.contacts.update({ const contact = await client.contacts.update({
accountId: this.provider.accountId, accountId: this.provider.account_id,
id, id,
data, data,
}); });
@ -131,7 +136,7 @@ export class ChatwootService {
} }
const contact = await client.contacts.search({ const contact = await client.contacts.search({
accountId: this.provider.accountId, accountId: this.provider.account_id,
q: `+${phoneNumber}`, q: `+${phoneNumber}`,
}); });
@ -145,8 +150,8 @@ export class ChatwootService {
throw new Error('client not found'); throw new Error('client not found');
} }
const chatId = body.data.key.remoteJid.split('@')[0]; const chatId = body.key.remoteJid.split('@')[0];
const nameContact = !body.data.key.fromMe ? body.data.pushName : chatId; const nameContact = !body.key.fromMe ? body.pushName : chatId;
const filterInbox = await this.getInbox(instance); const filterInbox = await this.getInbox(instance);
@ -156,14 +161,14 @@ export class ChatwootService {
const contactId = contact.id || contact.payload.contact.id; const contactId = contact.id || contact.payload.contact.id;
if (!body.data.key.fromMe && contact.name === chatId && nameContact !== chatId) { if (!body.key.fromMe && contact.name === chatId && nameContact !== chatId) {
await this.updateContact(instance, contactId, { await this.updateContact(instance, contactId, {
name: nameContact, name: nameContact,
}); });
} }
const contactConversations = (await client.contacts.listConversations({ const contactConversations = (await client.contacts.listConversations({
accountId: this.provider.accountId, accountId: this.provider.account_id,
id: contactId, id: contactId,
})) as any; })) as any;
@ -178,7 +183,7 @@ export class ChatwootService {
} }
const conversation = await client.conversations.create({ const conversation = await client.conversations.create({
accountId: this.provider.accountId, accountId: this.provider.account_id,
data: { data: {
contact_id: `${contactId}`, contact_id: `${contactId}`,
inbox_id: `${filterInbox.id}`, inbox_id: `${filterInbox.id}`,
@ -196,9 +201,12 @@ export class ChatwootService {
} }
const inbox = (await client.inboxes.list({ const inbox = (await client.inboxes.list({
accountId: this.provider.accountId, accountId: this.provider.account_id,
})) as any; })) as any;
const findByName = inbox.payload.find((inbox) => inbox.name === instance);
const findByName = inbox.payload.find(
(inbox) => inbox.name === instance.instanceName,
);
return findByName; return findByName;
} }
@ -216,7 +224,7 @@ export class ChatwootService {
const client = await this.clientCw(instance); const client = await this.clientCw(instance);
const message = await client.messages.create({ const message = await client.messages.create({
accountId: this.provider.accountId, accountId: this.provider.account_id,
conversationId: conversationId, conversationId: conversationId,
data: { data: {
content: content, content: content,
@ -245,16 +253,17 @@ export class ChatwootService {
const filterInbox = await this.getInbox(instance); const filterInbox = await this.getInbox(instance);
const findConversation = await client.conversations.list({ const findConversation = await client.conversations.list({
accountId: this.provider.accountId, accountId: this.provider.account_id,
inboxId: filterInbox.id, inboxId: filterInbox.id,
}); });
const conversation = findConversation.data.payload.find( const conversation = findConversation.data.payload.find(
(conversation) => (conversation) =>
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open', conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
); );
const message = await client.messages.create({ const message = await client.messages.create({
accountId: this.provider.accountId, accountId: this.provider.account_id,
conversationId: conversation.id, conversationId: conversation.id,
data: { data: {
content: content, content: content,
@ -285,7 +294,7 @@ export class ChatwootService {
const config = { const config = {
method: 'post', method: 'post',
maxBodyLength: Infinity, maxBodyLength: Infinity,
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversationId}/messages`, url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversationId}/messages`,
headers: { headers: {
api_access_token: this.provider.token, api_access_token: this.provider.token,
...data.getHeaders(), ...data.getHeaders(),
@ -315,7 +324,7 @@ export class ChatwootService {
const filterInbox = await this.getInbox(instance); const filterInbox = await this.getInbox(instance);
const findConversation = await client.conversations.list({ const findConversation = await client.conversations.list({
accountId: this.provider.accountId, accountId: this.provider.account_id,
inboxId: filterInbox.id, inboxId: filterInbox.id,
}); });
const conversation = findConversation.data.payload.find( const conversation = findConversation.data.payload.find(
@ -338,7 +347,7 @@ export class ChatwootService {
const config = { const config = {
method: 'post', method: 'post',
maxBodyLength: Infinity, maxBodyLength: Infinity,
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversation.id}/messages`, url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversation.id}/messages`,
headers: { headers: {
api_access_token: this.provider.token, api_access_token: this.provider.token,
...data.getHeaders(), ...data.getHeaders(),
@ -355,7 +364,360 @@ export class ChatwootService {
} }
} }
public async chatwootWebhook(instance: InstanceDto, body: any) { public async sendAttachment(
return true; waInstance: any,
number: string,
media: any,
caption?: string,
) {
try {
const parts = media.split('/');
const fileName = decodeURIComponent(parts[parts.length - 1]);
const mimeType = mimeTypes.lookup(fileName).toString();
let type = 'document';
switch (mimeType.split('/')[0]) {
case 'image':
type = 'image';
break;
case 'video':
type = 'video';
break;
case 'audio':
type = 'audio';
break;
default:
type = 'document';
break;
}
if (type === 'audio') {
const data: SendAudioDto = {
number: number,
audioMessage: {
audio: media,
},
options: {
delay: 1200,
presence: 'recording',
},
};
await waInstance?.audioWhatsapp(data);
return;
}
const data: SendMediaDto = {
number: number,
mediaMessage: {
mediatype: type as any,
fileName: fileName,
media: media,
},
options: {
delay: 1200,
presence: 'composing',
},
};
if (caption && type !== 'audio') {
data.mediaMessage.caption = caption;
}
await waInstance?.mediaMessage(data);
return;
} catch (error) {
throw new Error(error);
}
}
public async receiveWebhook(instance: InstanceDto, body: any) {
try {
if (!body?.conversation || body.private) return { message: 'bot' };
const chatId = body.conversation.meta.sender.phone_number.replace('+', '');
const messageReceived = body.content;
const senderName = body?.sender?.name;
const accountId = body.account.id as number;
const waInstance = this.waMonitor.waInstances[instance.instanceName];
if (chatId === '123456' && body.message_type === 'outgoing') {
const command = messageReceived.replace('/', '');
if (command === 'iniciar') {
const state = waInstance?.connectionStatus?.state;
if (state !== 'open') {
await waInstance.connectToWhatsapp();
} else {
await this.createBotMessage(
instance,
`🚨 Instância ${body.inbox.name} já está conectada.`,
'incoming',
);
}
}
if (command === 'status') {
const state = waInstance?.connectionStatus?.state;
if (!state) {
await this.createBotMessage(
instance,
`⚠️ Instância ${body.inbox.name} não existe.`,
'incoming',
);
}
if (state) {
await this.createBotMessage(
instance,
`⚠️ Status da instância ${body.inbox.name}: *${state}*`,
'incoming',
);
}
}
if (command === 'desconectar') {
const msgLogout = `🚨 Desconectando Whatsapp da caixa de entrada *${body.inbox.name}*: `;
await this.createBotMessage(instance, msgLogout, 'incoming');
await waInstance?.client?.logout('Log out instance: ' + instance.instanceName);
await waInstance?.client?.ws?.close();
}
}
if (
body.message_type === 'outgoing' &&
body?.conversation?.messages?.length &&
chatId !== '123456'
) {
// if (IMPORT_MESSAGES_SENT && messages_sent.includes(body.id)) {
// console.log(`🚨 Não importar mensagens enviadas, ficaria duplicado.`);
// const indexMessage = messages_sent.indexOf(body.id);
// messages_sent.splice(indexMessage, 1);
// return { message: 'bot' };
// }
let formatText: string;
if (senderName === null || senderName === undefined) {
formatText = messageReceived;
} else {
// formatText = TOSIGN ? `*${senderName}*: ${messageReceived}` : messageReceived;
formatText = `*${senderName}*: ${messageReceived}`;
}
for (const message of body.conversation.messages) {
if (message.attachments && message.attachments.length > 0) {
for (const attachment of message.attachments) {
console.log(attachment);
if (!messageReceived) {
formatText = null;
}
await this.sendAttachment(
waInstance,
chatId,
attachment.data_url,
formatText,
);
}
} else {
const data: SendTextDto = {
number: chatId,
textMessage: {
text: formatText,
},
options: {
delay: 1200,
presence: 'composing',
},
};
await waInstance?.textMessage(data);
}
}
}
return { message: 'bot' };
} catch (error) {
console.log(error);
return { message: 'bot' };
}
}
private isMediaMessage(message: any) {
const media = [
'imageMessage',
'documentMessage',
'audioMessage',
'videoMessage',
'stickerMessage',
];
const messageKeys = Object.keys(message);
return messageKeys.some((key) => media.includes(key));
}
private getTypeMessage(msg: any) {
const types = {
conversation: msg.conversation,
imageMessage: msg.imageMessage?.caption,
videoMessage: msg.videoMessage?.caption,
extendedTextMessage: msg.extendedTextMessage?.text,
messageContextInfo: msg.messageContextInfo?.stanzaId,
stickerMessage: msg.stickerMessage?.fileSha256.toString('base64'),
documentMessage: msg.documentMessage?.caption,
audioMessage: msg.audioMessage?.caption,
};
return types;
}
private getMessageContent(types: any) {
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
return typeKey ? types[typeKey] : undefined;
}
private getConversationMessage(msg: any) {
const types = this.getTypeMessage(msg);
const messageContent = this.getMessageContent(types);
return messageContent;
}
public async eventWhatsapp(event: string, instance: InstanceDto, body: any) {
try {
const client = await this.clientCw(instance);
if (!client) {
throw new Error('client not found');
}
const waInstance = this.waMonitor.waInstances[instance.instanceName];
if (event === 'messages.upsert') {
// if (body.key.fromMe && !IMPORT_MESSAGES_SENT) {
// return;
// }
if (body.key.remoteJid === 'status@broadcast') {
console.log(`🚨 Ignorando status do whatsapp.`);
return;
}
const getConversion = await this.createConversation(instance, body);
const messageType = body.key.fromMe ? 'outgoing' : 'incoming';
if (!getConversion) {
console.log('🚨 Erro ao criar conversa');
return;
}
const isMedia = this.isMediaMessage(body.message);
const bodyMessage = await this.getConversationMessage(body.message);
if (isMedia) {
const downloadBase64 = await waInstance?.getBase64FromMediaMessage({
message: {
...body,
},
});
const random = Math.random().toString(36).substring(7);
const nameFile = `${random}.${mimeTypes.extension(downloadBase64.mimetype)}`;
const fileData = Buffer.from(downloadBase64.base64, 'base64');
const fileName = `${path.join(waInstance?.storePath, 'temp', `${nameFile}`)}`;
writeFileSync(fileName, fileData, 'utf8');
return await this.sendData(getConversion, fileName, messageType, bodyMessage);
}
const send = await this.createMessage(
instance,
getConversion,
bodyMessage,
messageType,
);
return send;
}
if (event === 'status.instance') {
const data = body;
const inbox = await this.getInbox(instance);
const msgStatus = `⚡️ Status da instância ${inbox.name}: ${data.status}`;
await this.createBotMessage(instance, msgStatus, 'incoming');
}
if (event === 'connection.update') {
if (body.state === 'open') {
const msgConnection = `🚀 Conexão realizada com sucesso!`;
await this.createBotMessage(instance, msgConnection, 'incoming');
}
}
if (event === 'contacts.update') {
const data = body;
if (data.length) {
for (const item of data) {
const number = item.id.split('@')[0];
const photo = item.profilePictureUrl || null;
const find = await this.findContact(instance, number);
if (find) {
await this.updateContact(instance, find.id, {
avatar_url: photo,
});
}
}
}
}
if (event === 'qrcode.updated') {
if (body.statusCode === 500) {
const erroQRcode = `🚨 Limite de geração de QRCode atingido, para gerar um novo QRCode, envie a mensagem /iniciar novamente.`;
return await this.createBotMessage(instance, erroQRcode, 'incoming');
} else {
const fileData = Buffer.from(
body?.qrcode.base64.replace('data:image/png;base64,', ''),
'base64',
);
const fileName = `${path.join(
waInstance?.storePath,
'temp',
`${`${instance}.png`}`,
)}`;
writeFileSync(fileName, fileData, 'utf8');
await this.createBotQr(
instance,
'QRCode gerado com sucesso!',
'incoming',
fileName,
);
const msgQrCode = `⚡️ QRCode gerado com sucesso!\n\nDigitalize este código QR nos próximos 40 segundos:`;
await this.createBotMessage(instance, msgQrCode, 'incoming');
}
}
} catch (error) {
console.log(error);
}
} }
} }

View File

@ -122,6 +122,8 @@ import sharp from 'sharp';
import { RedisCache } from '../../db/redis.client'; import { RedisCache } from '../../db/redis.client';
import { Log } from '../../config/env.config'; import { Log } from '../../config/env.config';
import ProxyAgent from 'proxy-agent'; import ProxyAgent from 'proxy-agent';
import { ChatwootService } from './chatwoot.service';
import { waMonitor } from '../whatsapp.module';
export class WAStartupService { export class WAStartupService {
constructor( constructor(
@ -141,12 +143,14 @@ export class WAStartupService {
private readonly localWebhook: wa.LocalWebHook = {}; private readonly localWebhook: wa.LocalWebHook = {};
private readonly localChatwoot: wa.LocalChatwoot = {}; private readonly localChatwoot: wa.LocalChatwoot = {};
private stateConnection: wa.StateConnection = { state: 'close' }; private stateConnection: wa.StateConnection = { state: 'close' };
private readonly storePath = join(ROOT_DIR, 'store'); public readonly storePath = join(ROOT_DIR, 'store');
private readonly msgRetryCounterCache: CacheStore = new NodeCache(); private readonly msgRetryCounterCache: CacheStore = new NodeCache();
private readonly userDevicesCache: CacheStore = new NodeCache(); private readonly userDevicesCache: CacheStore = new NodeCache();
private endSession = false; private endSession = false;
private logBaileys = this.configService.get<Log>('LOG').BAILEYS; private logBaileys = this.configService.get<Log>('LOG').BAILEYS;
private chatwootService = new ChatwootService(waMonitor);
public set instanceName(name: string) { public set instanceName(name: string) {
this.logger.verbose(`Initializing instance '${name}'`); this.logger.verbose(`Initializing instance '${name}'`);
if (!name) { if (!name) {
@ -161,6 +165,17 @@ export class WAStartupService {
instance: this.instance.name, instance: this.instance.name,
status: 'created', status: 'created',
}); });
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(
Events.STATUS_INSTANCE,
{ instanceName: this.instance.name },
{
instance: this.instance.name,
status: 'created',
},
);
}
} }
public get instanceName() { public get instanceName() {
@ -270,6 +285,24 @@ export class WAStartupService {
return data; return data;
} }
private async loadChatwoot() {
this.logger.verbose('Loading chatwoot');
const data = await this.repository.chatwoot.find(this.instanceName);
this.localChatwoot.enabled = data?.enabled;
this.logger.verbose(`Chatwoot enabled: ${this.localChatwoot.enabled}`);
this.localChatwoot.account_id = data?.account_id;
this.logger.verbose(`Chatwoot account id: ${this.localChatwoot.account_id}`);
this.localChatwoot.token = data?.token;
this.logger.verbose(`Chatwoot token: ${this.localChatwoot.token}`);
this.localChatwoot.url = data?.url;
this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`);
this.logger.verbose('Chatwoot loaded');
}
public async setChatwoot(data: ChatwootRaw) { public async setChatwoot(data: ChatwootRaw) {
this.logger.verbose('Setting chatwoot'); this.logger.verbose('Setting chatwoot');
await this.repository.chatwoot.create(data, this.instanceName); await this.repository.chatwoot.create(data, this.instanceName);
@ -429,6 +462,17 @@ export class WAStartupService {
statusCode: DisconnectReason.badSession, statusCode: DisconnectReason.badSession,
}); });
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(
Events.QRCODE_UPDATED,
{ instanceName: this.instance.name },
{
message: 'QR code limit reached, please login again',
statusCode: DisconnectReason.badSession,
},
);
}
this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE'); this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE');
this.sendDataWebhook(Events.CONNECTION_UPDATE, { this.sendDataWebhook(Events.CONNECTION_UPDATE, {
instance: this.instance.name, instance: this.instance.name,
@ -442,6 +486,17 @@ export class WAStartupService {
status: 'removed', status: 'removed',
}); });
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(
Events.STATUS_INSTANCE,
{ instanceName: this.instance.name },
{
instance: this.instance.name,
status: 'removed',
},
);
}
this.logger.verbose('endSession defined as true'); this.logger.verbose('endSession defined as true');
this.endSession = true; this.endSession = true;
@ -472,6 +527,16 @@ export class WAStartupService {
this.sendDataWebhook(Events.QRCODE_UPDATED, { this.sendDataWebhook(Events.QRCODE_UPDATED, {
qrcode: { instance: this.instance.name, code: qr, base64 }, qrcode: { instance: this.instance.name, code: qr, base64 },
}); });
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(
Events.QRCODE_UPDATED,
{ instanceName: this.instance.name },
{
qrcode: { instance: this.instance.name, code: qr, base64 },
},
);
}
}); });
this.logger.verbose('Generating QR code in terminal'); this.logger.verbose('Generating QR code in terminal');
@ -512,6 +577,17 @@ export class WAStartupService {
status: 'removed', status: 'removed',
}); });
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(
Events.STATUS_INSTANCE,
{ instanceName: this.instance.name },
{
instance: this.instance.name,
status: 'removed',
},
);
}
this.logger.verbose('Emittin event logout.instance'); this.logger.verbose('Emittin event logout.instance');
this.eventEmitter.emit('logout.instance', this.instance.name, 'inner'); this.eventEmitter.emit('logout.instance', this.instance.name, 'inner');
this.client?.ws?.close(); this.client?.ws?.close();
@ -626,6 +702,7 @@ export class WAStartupService {
this.logger.verbose('Connecting to whatsapp'); this.logger.verbose('Connecting to whatsapp');
try { try {
this.loadWebhook(); this.loadWebhook();
this.loadChatwoot();
this.instance.authState = await this.defineAuthState(); this.instance.authState = await this.defineAuthState();
@ -817,6 +894,14 @@ export class WAStartupService {
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw); await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw);
if (this.localChatwoot.enabled) {
await this.chatwootService.eventWhatsapp(
Events.CONTACTS_UPDATE,
{ instanceName: this.instance.name },
contactsRaw,
);
}
this.logger.verbose('Updating contacts in database'); this.logger.verbose('Updating contacts in database');
await this.repository.contact.update( await this.repository.contact.update(
contactsRaw, contactsRaw,
@ -940,6 +1025,14 @@ export class WAStartupService {
this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT'); this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT');
await this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); await this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw);
if (this.localChatwoot.enabled) {
await this.chatwootService.eventWhatsapp(
Events.MESSAGES_UPSERT,
{ instanceName: this.instance.name },
messageRaw,
);
}
this.logger.verbose('Inserting message in database'); this.logger.verbose('Inserting message in database');
await this.repository.message.insert( await this.repository.message.insert(
[messageRaw], [messageRaw],
@ -978,6 +1071,14 @@ export class WAStartupService {
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw); await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw);
if (this.localChatwoot.enabled) {
await this.chatwootService.eventWhatsapp(
Events.CONTACTS_UPDATE,
{ instanceName: this.instance.name },
contactRaw,
);
}
this.logger.verbose('Updating contact in database'); this.logger.verbose('Updating contact in database');
await this.repository.contact.update( await this.repository.contact.update(
[contactRaw], [contactRaw],