mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2026-01-14 07:42:27 -06:00
Merge pull request #395 from jaison-x/import-messages-chatwoot
feat(chatwoot): import history messages to chatwoot on whatsapp connection
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import ChatwootClient, { ChatwootAPIConfig, contact, conversation, inbox } from '@figuro/chatwoot-sdk';
|
||||
import ChatwootClient, { ChatwootAPIConfig, contact, conversation, generic_id, inbox } from '@figuro/chatwoot-sdk';
|
||||
import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request';
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
@@ -7,14 +7,15 @@ import Jimp from 'jimp';
|
||||
import mimeTypes from 'mime-types';
|
||||
import path from 'path';
|
||||
|
||||
import { ChatWoot, ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { Chatwoot, ConfigService, HttpServer } from '../../config/env.config';
|
||||
import { Logger } from '../../config/logger.config';
|
||||
import { chatwootImport } from '../../utils/chatwoot-import-helper';
|
||||
import i18next from '../../utils/i18n';
|
||||
import { ICache } from '../abstract/abstract.cache';
|
||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||
import { InstanceDto } from '../dto/instance.dto';
|
||||
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
|
||||
import { ChatwootRaw, MessageRaw } from '../models';
|
||||
import { ChatwootRaw, ContactRaw, MessageRaw } from '../models';
|
||||
import { RepositoryBroker } from '../repository/repository.manager';
|
||||
import { Events } from '../types/wa.types';
|
||||
import { WAMonitoringService } from './monitor.service';
|
||||
@@ -773,6 +774,43 @@ export class ChatwootService {
|
||||
return message;
|
||||
}
|
||||
|
||||
public async getOpenConversationByContact(
|
||||
instance: InstanceDto,
|
||||
inbox: inbox,
|
||||
contact: generic_id & contact,
|
||||
): Promise<conversation> {
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
|
||||
const client = await this.clientCw(instance);
|
||||
|
||||
if (!client) {
|
||||
this.logger.warn('client not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const payload = [
|
||||
['inbox_id', inbox.id.toString()],
|
||||
['contact_id', contact.id.toString()],
|
||||
['status', 'open'],
|
||||
];
|
||||
|
||||
return (
|
||||
(
|
||||
(await client.conversations.filter({
|
||||
accountId: this.provider.account_id,
|
||||
payload: payload.map((item, i, payload) => {
|
||||
return {
|
||||
attribute_key: item[0],
|
||||
filter_operator: 'equal_to',
|
||||
values: [item[1]],
|
||||
query_operator: i < payload.length - 1 ? 'AND' : null,
|
||||
};
|
||||
}),
|
||||
})) as { payload: conversation[] }
|
||||
).payload[0] || undefined
|
||||
);
|
||||
}
|
||||
|
||||
public async createBotMessage(
|
||||
instance: InstanceDto,
|
||||
content: string,
|
||||
@@ -808,21 +846,7 @@ export class ChatwootService {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
const findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
|
||||
if (!findConversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation by contact id');
|
||||
const conversation = findConversation.data.payload.find(
|
||||
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
);
|
||||
const conversation = await this.getOpenConversationByContact(instance, filterInbox, contact);
|
||||
|
||||
if (!conversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
@@ -945,21 +969,7 @@ export class ChatwootService {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation in chatwoot');
|
||||
const findConversation = await client.conversations.list({
|
||||
accountId: this.provider.account_id,
|
||||
inboxId: filterInbox.id,
|
||||
});
|
||||
|
||||
if (!findConversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
this.logger.verbose('find conversation by contact id');
|
||||
const conversation = findConversation.data.payload.find(
|
||||
(conversation) => conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||
);
|
||||
const conversation = await this.getOpenConversationByContact(instance, filterInbox, contact);
|
||||
|
||||
if (!conversation) {
|
||||
this.logger.warn('conversation not found');
|
||||
@@ -1658,7 +1668,7 @@ export class ChatwootService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private getConversationMessage(msg: any) {
|
||||
public getConversationMessage(msg: any) {
|
||||
this.logger.verbose('get conversation message');
|
||||
|
||||
const types = this.getTypeMessage(msg);
|
||||
@@ -1989,7 +1999,7 @@ export class ChatwootService {
|
||||
}
|
||||
|
||||
if (event === Events.MESSAGES_DELETE) {
|
||||
const chatwootDelete = this.configService.get<ChatWoot>('CHATWOOT').MESSAGE_DELETE;
|
||||
const chatwootDelete = this.configService.get<Chatwoot>('CHATWOOT').MESSAGE_DELETE;
|
||||
if (chatwootDelete === true) {
|
||||
this.logger.verbose('deleting message from instance: ' + instance.instanceName);
|
||||
|
||||
@@ -2084,6 +2094,7 @@ export class ChatwootService {
|
||||
this.logger.verbose('send message to chatwoot');
|
||||
await this.createBotMessage(instance, msgConnection, 'incoming');
|
||||
this.waMonitor.waInstances[instance.instanceName].qrCode.count = 0;
|
||||
chatwootImport.clearAll(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2134,4 +2145,113 @@ export class ChatwootService {
|
||||
public getNumberFromRemoteJid(remoteJid: string) {
|
||||
return remoteJid.replace(/:\d+/, '').split('@')[0];
|
||||
}
|
||||
|
||||
public startImportHistoryMessages(instance: InstanceDto) {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.createBotMessage(instance, `💬 Starting to import messages. Please wait...`, 'incoming');
|
||||
}
|
||||
|
||||
public isImportHistoryAvailable() {
|
||||
const uri = this.configService.get<Chatwoot>('CHATWOOT').IMPORT.DATABASE.CONNECTION.URI;
|
||||
|
||||
return uri && uri !== 'postgres://user:password@hostname:port/dbname';
|
||||
}
|
||||
|
||||
/* We can't proccess messages exactly in batch because Chatwoot use message id to order
|
||||
messages in frontend and we are receiving the messages mixed between the batches.
|
||||
Because this, we need to put all batches together and order after */
|
||||
public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageRaw[]) {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatwootImport.addHistoryMessages(instance, messagesRaw);
|
||||
}
|
||||
|
||||
public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactRaw[]) {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return chatwootImport.addHistoryContacts(instance, contactsRaw);
|
||||
}
|
||||
|
||||
public async importHistoryMessages(instance: InstanceDto) {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.createBotMessage(instance, '💬 Importing messages. More one moment...', 'incoming');
|
||||
|
||||
const totalMessagesImported = await chatwootImport.importHistoryMessages(
|
||||
instance,
|
||||
this,
|
||||
await this.getInbox(instance),
|
||||
this.provider,
|
||||
);
|
||||
this.updateContactAvatarInRecentConversations(instance);
|
||||
|
||||
const msg = Number.isInteger(totalMessagesImported)
|
||||
? `${totalMessagesImported} messages imported. Refresh page to see the new messages`
|
||||
: `Something went wrong in importing messages`;
|
||||
|
||||
this.createBotMessage(instance, `💬 ${msg}`, 'incoming');
|
||||
|
||||
return totalMessagesImported;
|
||||
}
|
||||
|
||||
public async updateContactAvatarInRecentConversations(instance: InstanceDto, limitContacts = 100) {
|
||||
try {
|
||||
if (!this.isImportHistoryAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = await this.clientCw(instance);
|
||||
if (!client) {
|
||||
this.logger.warn('client not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const inbox = await this.getInbox(instance);
|
||||
if (!inbox) {
|
||||
this.logger.warn('inbox not found');
|
||||
return null;
|
||||
}
|
||||
|
||||
const recentContacts = await chatwootImport.getContactsOrderByRecentConversations(
|
||||
inbox,
|
||||
this.provider,
|
||||
limitContacts,
|
||||
);
|
||||
|
||||
const contactsWithProfilePicture = (
|
||||
await this.repository.contact.find({
|
||||
where: {
|
||||
owner: instance.instanceName,
|
||||
id: {
|
||||
$in: recentContacts.map((contact) => contact.identifier),
|
||||
},
|
||||
profilePictureUrl: { $ne: null },
|
||||
},
|
||||
} as any)
|
||||
).reduce((acc: Map<string, ContactRaw>, contact: ContactRaw) => acc.set(contact.id, contact), new Map());
|
||||
|
||||
recentContacts.forEach(async (contact) => {
|
||||
if (contactsWithProfilePicture.has(contact.identifier)) {
|
||||
client.contacts.update({
|
||||
accountId: this.provider.account_id,
|
||||
id: contact.id,
|
||||
data: {
|
||||
avatar_url: contactsWithProfilePicture.get(contact.identifier).profilePictureUrl || null,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(`Error on update avatar in recent conversations: ${error.toString()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user