feat: chatwoot integration completed

This commit is contained in:
Davidson Gomes 2023-07-13 00:27:18 -03:00
parent 3eda2a1f2a
commit 0fc3b47c88
9 changed files with 126 additions and 22 deletions

View File

@ -866,7 +866,8 @@ export const chatwootSchema: JSONSchema7 = {
account_id: { type: 'string' }, account_id: { type: 'string' },
token: { type: 'string' }, token: { type: 'string' },
url: { type: 'string' }, url: { type: 'string' },
sign_msg: { type: 'boolean', enum: [true, false] },
}, },
required: ['enabled', 'account_id', 'token', 'url'], required: ['enabled', 'account_id', 'token', 'url', 'sign_msg'],
...isNotEmpty('account_id', 'token', 'url'), ...isNotEmpty('account_id', 'token', 'url', 'sign_msg'),
}; };

View File

@ -4,6 +4,7 @@ import { InstanceDto } from '../dto/instance.dto';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { ChatwootService } from '../services/chatwoot.service'; import { ChatwootService } from '../services/chatwoot.service';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { waMonitor } from '../whatsapp.module';
const logger = new Logger('ChatwootController'); const logger = new Logger('ChatwootController');
@ -27,6 +28,10 @@ export class ChatwootController {
if (!data.token) { if (!data.token) {
throw new BadRequestException('token is required'); throw new BadRequestException('token is required');
} }
if (!data.sign_msg) {
throw new BadRequestException('sign_msg is required');
}
} }
if (!data.enabled) { if (!data.enabled) {
@ -34,22 +39,39 @@ export class ChatwootController {
data.account_id = ''; data.account_id = '';
data.token = ''; data.token = '';
data.url = ''; data.url = '';
data.sign_msg = false;
} }
data.name_inbox = instance.instanceName; data.name_inbox = instance.instanceName;
return this.chatwootService.create(instance, data); const result = this.chatwootService.create(instance, data);
const response = {
...result,
webhook_url: `/chatwoot/webhook/${instance.instanceName}`,
};
return response;
} }
public async findChatwoot(instance: InstanceDto) { public async findChatwoot(instance: InstanceDto) {
logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance'); logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance');
return this.chatwootService.find(instance); const result = this.chatwootService.find(instance);
const response = {
...result,
webhook_url: `/chatwoot/webhook/${instance.instanceName}`,
};
return response;
} }
public async receiveWebhook(instance: InstanceDto, data: any) { public async receiveWebhook(instance: InstanceDto, data: any) {
logger.verbose( logger.verbose(
'requested receiveWebhook from ' + instance.instanceName + ' instance', 'requested receiveWebhook from ' + instance.instanceName + ' instance',
); );
return this.chatwootService.receiveWebhook(instance, data); const chatwootService = new ChatwootService(waMonitor);
return chatwootService.receiveWebhook(instance, data);
} }
} }

View File

@ -37,6 +37,7 @@ export class InstanceController {
chatwoot_account_id, chatwoot_account_id,
chatwoot_token, chatwoot_token,
chatwoot_url, chatwoot_url,
chatwoot_sign_msg,
}: InstanceDto) { }: InstanceDto) {
this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
@ -78,7 +79,12 @@ export class InstanceController {
this.logger.verbose('hash: ' + hash + ' generated'); this.logger.verbose('hash: ' + hash + ' generated');
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { if (
!chatwoot_account_id ||
!chatwoot_token ||
!chatwoot_url ||
!chatwoot_sign_msg
) {
let getEvents: string[]; let getEvents: string[];
if (webhook) { if (webhook) {
@ -131,12 +137,17 @@ export class InstanceController {
throw new BadRequestException('url is required'); throw new BadRequestException('url is required');
} }
if (!chatwoot_sign_msg) {
throw new BadRequestException('sign_msg is required');
}
try { try {
this.chatwootService.create(instance, { this.chatwootService.create(instance, {
enabled: true, enabled: true,
account_id: chatwoot_account_id, account_id: chatwoot_account_id,
token: chatwoot_token, token: chatwoot_token,
url: chatwoot_url, url: chatwoot_url,
sign_msg: chatwoot_sign_msg,
name_inbox: instance.instanceName, name_inbox: instance.instanceName,
}); });
} catch (error) { } catch (error) {
@ -154,7 +165,9 @@ export class InstanceController {
account_id: chatwoot_account_id, account_id: chatwoot_account_id,
token: chatwoot_token, token: chatwoot_token,
url: chatwoot_url, url: chatwoot_url,
sign_msg: chatwoot_sign_msg,
name_inbox: instance.instanceName, name_inbox: instance.instanceName,
webhook_url: `/chatwoot/webhook/${instance.instanceName}`,
}, },
}; };
} else { } else {
@ -187,7 +200,12 @@ export class InstanceController {
this.logger.verbose('hash: ' + hash + ' generated'); this.logger.verbose('hash: ' + hash + ' generated');
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { if (
!chatwoot_account_id ||
!chatwoot_token ||
!chatwoot_url ||
!chatwoot_sign_msg
) {
let getEvents: string[]; let getEvents: string[];
if (webhook) { if (webhook) {
@ -253,12 +271,17 @@ export class InstanceController {
throw new BadRequestException('url is required'); throw new BadRequestException('url is required');
} }
if (!chatwoot_sign_msg) {
throw new BadRequestException('sign_msg is required');
}
try { try {
this.chatwootService.create(instance, { this.chatwootService.create(instance, {
enabled: true, enabled: true,
account_id: chatwoot_account_id, account_id: chatwoot_account_id,
token: chatwoot_token, token: chatwoot_token,
url: chatwoot_url, url: chatwoot_url,
sign_msg: chatwoot_sign_msg,
name_inbox: instance.instanceName, name_inbox: instance.instanceName,
}); });
} catch (error) { } catch (error) {
@ -276,7 +299,9 @@ export class InstanceController {
account_id: chatwoot_account_id, account_id: chatwoot_account_id,
token: chatwoot_token, token: chatwoot_token,
url: chatwoot_url, url: chatwoot_url,
sign_msg: chatwoot_sign_msg,
name_inbox: instance.instanceName, name_inbox: instance.instanceName,
webhook_url: `/chatwoot/webhook/${instance.instanceName}`,
}, },
}; };
} }

View File

@ -4,4 +4,5 @@ export class ChatwootDto {
token?: string; token?: string;
url?: string; url?: string;
name_inbox?: string; name_inbox?: string;
sign_msg?: boolean;
} }

View File

@ -8,4 +8,5 @@ export class InstanceDto {
chatwoot_account_id?: string; chatwoot_account_id?: string;
chatwoot_token?: string; chatwoot_token?: string;
chatwoot_url?: string; chatwoot_url?: string;
chatwoot_sign_msg?: boolean;
} }

View File

@ -8,6 +8,7 @@ export class ChatwootRaw {
token?: string; token?: string;
url?: string; url?: string;
name_inbox?: string; name_inbox?: string;
sign_msg?: boolean;
} }
const chatwootSchema = new Schema<ChatwootRaw>({ const chatwootSchema = new Schema<ChatwootRaw>({
@ -17,6 +18,7 @@ const chatwootSchema = new Schema<ChatwootRaw>({
token: { type: String, required: true }, token: { type: String, required: true },
url: { type: String, required: true }, url: { type: String, required: true },
name_inbox: { type: String, required: true }, name_inbox: { type: String, required: true },
sign_msg: { type: Boolean, required: true },
}); });
export const ChatwootModel = dbserver?.model( export const ChatwootModel = dbserver?.model(

View File

@ -4,21 +4,43 @@ 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, writeFileSync } from 'fs'; import { createReadStream, readFileSync, 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 { SendTextDto } from '../dto/sendMessage.dto';
import mimeTypes from 'mime-types'; import mimeTypes from 'mime-types';
import { SendAudioDto } from '../dto/sendMessage.dto'; import { SendAudioDto } from '../dto/sendMessage.dto';
import { SendMediaDto } from '../dto/sendMessage.dto'; import { SendMediaDto } from '../dto/sendMessage.dto';
import NodeCache from 'node-cache';
import { ROOT_DIR } from '../../config/path.config';
export class ChatwootService { export class ChatwootService {
constructor(private readonly waMonitor: WAMonitoringService) {} private messageCacheFile: string;
private messageCache: Set<string>;
private readonly logger = new Logger(ChatwootService.name); private readonly logger = new Logger(ChatwootService.name);
private provider: any; private provider: any;
constructor(private readonly waMonitor: WAMonitoringService) {
this.messageCache = new Set();
}
private loadMessageCache(): Set<string> {
try {
const cacheData = readFileSync(this.messageCacheFile, 'utf-8');
const cacheArray = cacheData.split('\n');
return new Set(cacheArray);
} catch (error) {
return new Set();
}
}
private saveMessageCache() {
const cacheData = Array.from(this.messageCache).join('\n');
writeFileSync(this.messageCacheFile, cacheData, 'utf-8');
}
private async getProvider(instance: InstanceDto) { private async getProvider(instance: InstanceDto) {
const provider = await this.waMonitor.waInstances[ const provider = await this.waMonitor.waInstances[
instance.instanceName instance.instanceName
@ -436,12 +458,13 @@ export class ChatwootService {
public async receiveWebhook(instance: InstanceDto, body: any) { public async receiveWebhook(instance: InstanceDto, body: any) {
try { try {
const client = await this.clientCw(instance);
if (!body?.conversation || body.private) return { message: 'bot' }; if (!body?.conversation || body.private) return { message: 'bot' };
const chatId = body.conversation.meta.sender.phone_number.replace('+', ''); const chatId = body.conversation.meta.sender.phone_number.replace('+', '');
const messageReceived = body.content; const messageReceived = body.content;
const senderName = body?.sender?.name; const senderName = body?.sender?.name;
const accountId = body.account.id as number;
const waInstance = this.waMonitor.waInstances[instance.instanceName]; const waInstance = this.waMonitor.waInstances[instance.instanceName];
if (chatId === '123456' && body.message_type === 'outgoing') { if (chatId === '123456' && body.message_type === 'outgoing') {
@ -495,27 +518,31 @@ export class ChatwootService {
body?.conversation?.messages?.length && body?.conversation?.messages?.length &&
chatId !== '123456' chatId !== '123456'
) { ) {
// if (IMPORT_MESSAGES_SENT && messages_sent.includes(body.id)) { this.messageCacheFile = path.join(
// console.log(`🚨 Não importar mensagens enviadas, ficaria duplicado.`); ROOT_DIR,
'store',
'chatwoot',
`${instance.instanceName}_cache.txt`,
);
// const indexMessage = messages_sent.indexOf(body.id); this.messageCache = this.loadMessageCache();
// messages_sent.splice(indexMessage, 1);
// return { message: 'bot' }; if (this.messageCache.has(body.id.toString())) {
// } return { message: 'bot' };
}
let formatText: string; let formatText: string;
if (senderName === null || senderName === undefined) { if (senderName === null || senderName === undefined) {
formatText = messageReceived; formatText = messageReceived;
} else { } else {
// formatText = TOSIGN ? `*${senderName}*: ${messageReceived}` : messageReceived; formatText = this.provider.sign_msg
formatText = `*${senderName}*: ${messageReceived}`; ? `*${senderName}*: ${messageReceived}`
: messageReceived;
} }
for (const message of body.conversation.messages) { for (const message of body.conversation.messages) {
if (message.attachments && message.attachments.length > 0) { if (message.attachments && message.attachments.length > 0) {
for (const attachment of message.attachments) { for (const attachment of message.attachments) {
console.log(attachment);
if (!messageReceived) { if (!messageReceived) {
formatText = null; formatText = null;
} }
@ -609,7 +636,6 @@ export class ChatwootService {
// } // }
if (body.key.remoteJid === 'status@broadcast') { if (body.key.remoteJid === 'status@broadcast') {
console.log(`🚨 Ignorando status do whatsapp.`);
return; return;
} }
@ -617,7 +643,6 @@ export class ChatwootService {
const messageType = body.key.fromMe ? 'outgoing' : 'incoming'; const messageType = body.key.fromMe ? 'outgoing' : 'incoming';
if (!getConversion) { if (!getConversion) {
console.log('🚨 Erro ao criar conversa');
return; return;
} }
@ -637,7 +662,11 @@ export class ChatwootService {
const fileData = Buffer.from(downloadBase64.base64, 'base64'); const fileData = Buffer.from(downloadBase64.base64, 'base64');
const fileName = `${path.join(waInstance?.storePath, 'temp', `${nameFile}`)}`; const fileName = `${path.join(
waInstance?.storePath,
'chatwoot',
`${nameFile}`,
)}`;
writeFileSync(fileName, fileData, 'utf8'); writeFileSync(fileName, fileData, 'utf8');
@ -651,6 +680,19 @@ export class ChatwootService {
messageType, messageType,
); );
this.messageCacheFile = path.join(
ROOT_DIR,
'store',
'chatwoot',
`${instance.instanceName}_cache.txt`,
);
this.messageCache = this.loadMessageCache();
this.messageCache.add(send.id.toString());
this.saveMessageCache();
return send; return send;
} }

View File

@ -300,6 +300,12 @@ export class WAStartupService {
this.localChatwoot.url = data?.url; this.localChatwoot.url = data?.url;
this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`); this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`);
this.localChatwoot.name_inbox = data?.name_inbox;
this.logger.verbose(`Chatwoot inbox name: ${this.localChatwoot.name_inbox}`);
this.localChatwoot.sign_msg = data?.sign_msg;
this.logger.verbose(`Chatwoot sign msg: ${this.localChatwoot.sign_msg}`);
this.logger.verbose('Chatwoot loaded'); this.logger.verbose('Chatwoot loaded');
} }
@ -310,6 +316,7 @@ export class WAStartupService {
this.logger.verbose(`Chatwoot token: ${data.token}`); this.logger.verbose(`Chatwoot token: ${data.token}`);
this.logger.verbose(`Chatwoot url: ${data.url}`); this.logger.verbose(`Chatwoot url: ${data.url}`);
this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`);
this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`);
Object.assign(this.localChatwoot, data); Object.assign(this.localChatwoot, data);
this.logger.verbose('Chatwoot set'); this.logger.verbose('Chatwoot set');
@ -328,6 +335,8 @@ export class WAStartupService {
this.logger.verbose(`Chatwoot token: ${data.token}`); this.logger.verbose(`Chatwoot token: ${data.token}`);
this.logger.verbose(`Chatwoot url: ${data.url}`); this.logger.verbose(`Chatwoot url: ${data.url}`);
this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`);
this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`);
return data; return data;
} }

View File

@ -47,6 +47,7 @@ export declare namespace wa {
token?: string; token?: string;
url?: string; url?: string;
name_inbox?: string; name_inbox?: string;
sign_msg?: boolean;
}; };
export type StateConnection = { export type StateConnection = {