mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-14 09:51:24 -06:00
feat: chatwoot integration completed
This commit is contained in:
parent
3eda2a1f2a
commit
0fc3b47c88
@ -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'),
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@ export class ChatwootDto {
|
|||||||
token?: string;
|
token?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
name_inbox?: string;
|
name_inbox?: string;
|
||||||
|
sign_msg?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = {
|
||||||
|
Loading…
Reference in New Issue
Block a user