mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-18 13:06:32 -06:00
Added support for messaging with ads on chatwoot
This commit is contained in:
parent
32da15fa8a
commit
707aa22a6d
@ -26,6 +26,7 @@
|
|||||||
* Added Typebot integration
|
* Added Typebot integration
|
||||||
* Added proxy endpoint
|
* Added proxy endpoint
|
||||||
* Added send and date_time in webhook data
|
* Added send and date_time in webhook data
|
||||||
|
* Added support for messaging with ads on chatwoot
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
11
src/main.ts
11
src/main.ts
@ -6,7 +6,7 @@ import cors from 'cors';
|
|||||||
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { configService, Cors, HttpServer, Rabbitmq, Webhook } from './config/env.config';
|
import { Auth, configService, Cors, HttpServer, Rabbitmq, Webhook } from './config/env.config';
|
||||||
import { onUnexpectedError } from './config/error.config';
|
import { onUnexpectedError } from './config/error.config';
|
||||||
import { Logger } from './config/logger.config';
|
import { Logger } from './config/logger.config';
|
||||||
import { ROOT_DIR } from './config/path.config';
|
import { ROOT_DIR } from './config/path.config';
|
||||||
@ -61,6 +61,8 @@ function bootstrap() {
|
|||||||
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
|
||||||
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
|
||||||
const now = localISOTime;
|
const now = localISOTime;
|
||||||
|
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
|
||||||
|
const serverUrl = configService.get<HttpServer>('SERVER').URL;
|
||||||
|
|
||||||
const errorData = {
|
const errorData = {
|
||||||
event: 'error',
|
event: 'error',
|
||||||
@ -73,6 +75,8 @@ function bootstrap() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
date_time: now,
|
date_time: now,
|
||||||
|
api_key: globalApiKey,
|
||||||
|
server_url: serverUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.error(errorData);
|
logger.error(errorData);
|
||||||
@ -83,11 +87,6 @@ function bootstrap() {
|
|||||||
httpService.post('', errorData);
|
httpService.post('', errorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err['message'].includes('No sessions')) {
|
|
||||||
console.log(err['message']);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(err['status'] || 500).json({
|
return res.status(err['status'] || 500).json({
|
||||||
status: err['status'] || 500,
|
status: err['status'] || 500,
|
||||||
error: err['error'] || 'Internal Server Error',
|
error: err['error'] || 'Internal Server Error',
|
||||||
|
@ -6,7 +6,7 @@ import Jimp from 'jimp';
|
|||||||
import mimeTypes from 'mime-types';
|
import mimeTypes from 'mime-types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { Chatwoot, ConfigService } from '../../config/env.config';
|
import { ConfigService } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { ROOT_DIR } from '../../config/path.config';
|
import { ROOT_DIR } from '../../config/path.config';
|
||||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||||
@ -613,8 +613,6 @@ export class ChatwootService {
|
|||||||
conversationId: number,
|
conversationId: number,
|
||||||
content: string,
|
content: string,
|
||||||
messageType: 'incoming' | 'outgoing' | undefined,
|
messageType: 'incoming' | 'outgoing' | undefined,
|
||||||
source_id?: string,
|
|
||||||
source_reply_id?: string,
|
|
||||||
privateMessage?: boolean,
|
privateMessage?: boolean,
|
||||||
attachments?: {
|
attachments?: {
|
||||||
content: unknown;
|
content: unknown;
|
||||||
@ -640,8 +638,6 @@ export class ChatwootService {
|
|||||||
message_type: messageType,
|
message_type: messageType,
|
||||||
attachments: attachments,
|
attachments: attachments,
|
||||||
private: privateMessage || false,
|
private: privateMessage || false,
|
||||||
source_id: source_id,
|
|
||||||
source_reply_id: source_reply_id,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -737,8 +733,6 @@ export class ChatwootService {
|
|||||||
file: string,
|
file: string,
|
||||||
messageType: 'incoming' | 'outgoing' | undefined,
|
messageType: 'incoming' | 'outgoing' | undefined,
|
||||||
content?: string,
|
content?: string,
|
||||||
source_id?: string,
|
|
||||||
source_reply_id?: string,
|
|
||||||
) {
|
) {
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
|
|
||||||
@ -755,16 +749,6 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('temp file found');
|
this.logger.verbose('temp file found');
|
||||||
data.append('attachments[]', createReadStream(file));
|
data.append('attachments[]', createReadStream(file));
|
||||||
|
|
||||||
if (source_id) {
|
|
||||||
this.logger.verbose('source_id found');
|
|
||||||
data.append('source_id', source_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source_reply_id) {
|
|
||||||
this.logger.verbose('source_reply_id found');
|
|
||||||
data.append('source_reply_id', source_reply_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.verbose('get client to instance: ' + this.provider.instanceName);
|
this.logger.verbose('get client to instance: ' + this.provider.instanceName);
|
||||||
const config = {
|
const config = {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -930,10 +914,10 @@ export class ChatwootService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const audioWhatsapp = await waInstance?.audioWhatsapp(data);
|
await waInstance?.audioWhatsapp(data);
|
||||||
|
|
||||||
this.logger.verbose('audio sent');
|
this.logger.verbose('audio sent');
|
||||||
return audioWhatsapp;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send media to instance: ' + waInstance.instanceName);
|
this.logger.verbose('send media to instance: ' + waInstance.instanceName);
|
||||||
@ -955,51 +939,17 @@ export class ChatwootService {
|
|||||||
data.mediaMessage.caption = caption;
|
data.mediaMessage.caption = caption;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mediaMessage = await waInstance?.mediaMessage(data);
|
await waInstance?.mediaMessage(data);
|
||||||
|
|
||||||
this.logger.verbose('media sent');
|
this.logger.verbose('media sent');
|
||||||
return mediaMessage;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(error);
|
this.logger.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateMessage(
|
|
||||||
instance: InstanceDto,
|
|
||||||
accountId: number,
|
|
||||||
conversationId: number,
|
|
||||||
messageId: number,
|
|
||||||
sourceId: string | null,
|
|
||||||
) {
|
|
||||||
// const useReplyId = this.configService.get<DelInstance>('DEL_INSTANCE');
|
|
||||||
const useReplyId = this.configService.get<Chatwoot>('CHATWOOT')?.USE_REPLY_ID;
|
|
||||||
if (useReplyId === true) {
|
|
||||||
this.logger.verbose('update message to chatwoot instance: ' + instance.instanceName);
|
|
||||||
const client = await this.clientCw(instance);
|
|
||||||
|
|
||||||
if (!client) {
|
|
||||||
this.logger.warn('client not found');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
this.logger.verbose('check if sourceId to update');
|
|
||||||
if (sourceId) {
|
|
||||||
this.logger.verbose('update message to chatwoot');
|
|
||||||
const dataUpdated = {
|
|
||||||
source_id: sourceId,
|
|
||||||
};
|
|
||||||
await client.messages.update({
|
|
||||||
accountId,
|
|
||||||
conversationId,
|
|
||||||
data: dataUpdated,
|
|
||||||
messageId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async receiveWebhook(instance: InstanceDto, body: any) {
|
public async receiveWebhook(instance: InstanceDto, body: any) {
|
||||||
try {
|
try {
|
||||||
// espera 500ms para evitar duplicidade de mensagens
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
|
||||||
this.logger.verbose('receive webhook to chatwoot instance: ' + instance.instanceName);
|
this.logger.verbose('receive webhook to chatwoot instance: ' + instance.instanceName);
|
||||||
@ -1097,9 +1047,6 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const message of body.conversation.messages) {
|
for (const message of body.conversation.messages) {
|
||||||
const messageId = message?.id;
|
|
||||||
const conversationId = message?.conversation_id;
|
|
||||||
const accountId = message?.account_id;
|
|
||||||
this.logger.verbose('check if message is media');
|
this.logger.verbose('check if message is media');
|
||||||
if (message.attachments && message.attachments.length > 0) {
|
if (message.attachments && message.attachments.length > 0) {
|
||||||
this.logger.verbose('message is media');
|
this.logger.verbose('message is media');
|
||||||
@ -1110,8 +1057,7 @@ export class ChatwootService {
|
|||||||
formatText = null;
|
formatText = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mediaMessage = await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
|
await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
|
||||||
await this.updateMessage(instance, accountId, conversationId, messageId, mediaMessage?.key?.id);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.logger.verbose('message is text');
|
this.logger.verbose('message is text');
|
||||||
@ -1128,8 +1074,7 @@ export class ChatwootService {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const message = await waInstance?.textMessage(data);
|
await waInstance?.textMessage(data);
|
||||||
await this.updateMessage(instance, accountId, conversationId, messageId, message?.key?.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1187,7 +1132,7 @@ export class ChatwootService {
|
|||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
sourceUrl: string;
|
sourceUrl: string;
|
||||||
}
|
}
|
||||||
let adsMessage: AdsMessage | undefined = msg.extendedTextMessage?.contextInfo.externalAdReply;
|
const adsMessage: AdsMessage | undefined = msg.extendedTextMessage?.contextInfo.externalAdReply;
|
||||||
|
|
||||||
this.logger.verbose('Get ads message if it exist');
|
this.logger.verbose('Get ads message if it exist');
|
||||||
adsMessage && this.logger.verbose('Ads message: ' + adsMessage);
|
adsMessage && this.logger.verbose('Ads message: ' + adsMessage);
|
||||||
@ -1218,38 +1163,6 @@ export class ChatwootService {
|
|||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getContextIdTypeMessage(msg: any) {
|
|
||||||
this.logger.verbose('get type message');
|
|
||||||
|
|
||||||
const types = {
|
|
||||||
conversation: msg.conversation?.contextInfo?.stanzaId,
|
|
||||||
imageMessage: msg.imageMessage?.contextInfo?.stanzaId,
|
|
||||||
videoMessage: msg.videoMessage?.contextInfo?.stanzaId,
|
|
||||||
extendedTextMessage: msg.extendedTextMessage?.contextInfo?.stanzaId,
|
|
||||||
messageContextInfo: msg.messageContextInfo?.stanzaId,
|
|
||||||
stickerMessage: undefined,
|
|
||||||
documentMessage: msg.documentMessage?.contextInfo?.stanzaId,
|
|
||||||
documentWithCaptionMessage: msg.documentWithCaptionMessage?.message?.documentMessage?.contextInfo?.stanzaId,
|
|
||||||
audioMessage: msg.audioMessage?.contextInfo?.stanzaId,
|
|
||||||
contactMessage: msg.contactMessage?.contextInfo?.stanzaId,
|
|
||||||
contactsArrayMessage: msg.contactsArrayMessage?.contextInfo?.stanzaId,
|
|
||||||
locationMessage: msg.locationMessage?.contextInfo?.stanzaId,
|
|
||||||
liveLocationMessage: msg.liveLocationMessage?.contextInfo?.stanzaId,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.logger.verbose('type message: ' + types);
|
|
||||||
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getContextMessageContent(types: any) {
|
|
||||||
this.logger.verbose('get message context content');
|
|
||||||
const typeKey = Object.keys(types).find((key) => types[key] !== undefined && types[key] !== '');
|
|
||||||
|
|
||||||
const result = typeKey ? types[typeKey] : undefined;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getMessageContent(types: any) {
|
private getMessageContent(types: any) {
|
||||||
this.logger.verbose('get message content');
|
this.logger.verbose('get message content');
|
||||||
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||||
@ -1349,18 +1262,6 @@ export class ChatwootService {
|
|||||||
return messageContent;
|
return messageContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getContextConversationMessage(msg: any) {
|
|
||||||
this.logger.verbose('get context conversation message');
|
|
||||||
|
|
||||||
const types = this.getContextIdTypeMessage(msg);
|
|
||||||
|
|
||||||
const messageContext = this.getContextMessageContent(types);
|
|
||||||
|
|
||||||
this.logger.verbose('context conversation message: ' + messageContext);
|
|
||||||
|
|
||||||
return messageContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async eventWhatsapp(event: string, instance: InstanceDto, body: any) {
|
public async eventWhatsapp(event: string, instance: InstanceDto, body: any) {
|
||||||
this.logger.verbose('event whatsapp to instance: ' + instance.instanceName);
|
this.logger.verbose('event whatsapp to instance: ' + instance.instanceName);
|
||||||
try {
|
try {
|
||||||
@ -1389,8 +1290,6 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('get conversation message');
|
this.logger.verbose('get conversation message');
|
||||||
const bodyMessage = await this.getConversationMessage(body.message);
|
const bodyMessage = await this.getConversationMessage(body.message);
|
||||||
|
|
||||||
const source_reply_id = this.getContextConversationMessage(body.message);
|
|
||||||
|
|
||||||
const isMedia = this.isMediaMessage(body.message);
|
const isMedia = this.isMediaMessage(body.message);
|
||||||
|
|
||||||
const adsMessage = this.getAdsMessage(body.message);
|
const adsMessage = this.getAdsMessage(body.message);
|
||||||
@ -1410,8 +1309,6 @@ export class ChatwootService {
|
|||||||
|
|
||||||
const messageType = body.key.fromMe ? 'outgoing' : 'incoming';
|
const messageType = body.key.fromMe ? 'outgoing' : 'incoming';
|
||||||
|
|
||||||
const source_id = body.key?.id;
|
|
||||||
|
|
||||||
this.logger.verbose('message type: ' + messageType);
|
this.logger.verbose('message type: ' + messageType);
|
||||||
|
|
||||||
this.logger.verbose('is media: ' + isMedia);
|
this.logger.verbose('is media: ' + isMedia);
|
||||||
@ -1456,7 +1353,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.sendData(getConversation, fileName, messageType, content, source_id, source_reply_id);
|
const send = await this.sendData(getConversation, fileName, messageType, content);
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
@ -1477,14 +1374,7 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('message is not group');
|
this.logger.verbose('message is not group');
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.sendData(
|
const send = await this.sendData(getConversation, fileName, messageType, bodyMessage);
|
||||||
getConversation,
|
|
||||||
fileName,
|
|
||||||
messageType,
|
|
||||||
bodyMessage,
|
|
||||||
source_id,
|
|
||||||
source_reply_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
@ -1581,14 +1471,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.createMessage(
|
const send = await this.createMessage(instance, getConversation, content, messageType);
|
||||||
instance,
|
|
||||||
getConversation,
|
|
||||||
content,
|
|
||||||
messageType,
|
|
||||||
source_id,
|
|
||||||
source_reply_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
@ -1609,14 +1492,7 @@ export class ChatwootService {
|
|||||||
this.logger.verbose('message is not group');
|
this.logger.verbose('message is not group');
|
||||||
|
|
||||||
this.logger.verbose('send data to chatwoot');
|
this.logger.verbose('send data to chatwoot');
|
||||||
const send = await this.createMessage(
|
const send = await this.createMessage(instance, getConversation, bodyMessage, messageType);
|
||||||
instance,
|
|
||||||
getConversation,
|
|
||||||
bodyMessage,
|
|
||||||
messageType,
|
|
||||||
source_id,
|
|
||||||
source_reply_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!send) {
|
if (!send) {
|
||||||
this.logger.warn('message not sent');
|
this.logger.warn('message not sent');
|
||||||
|
@ -1434,8 +1434,9 @@ export class WAStartupService {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
type !== 'notify' ||
|
type !== 'notify' ||
|
||||||
!received.message ||
|
!received?.message ||
|
||||||
received.message?.protocolMessage ||
|
received.message?.protocolMessage ||
|
||||||
|
received.message.senderKeyDistributionMessage ||
|
||||||
received.message?.pollUpdateMessage
|
received.message?.pollUpdateMessage
|
||||||
) {
|
) {
|
||||||
this.logger.verbose('message rejected');
|
this.logger.verbose('message rejected');
|
||||||
|
Loading…
Reference in New Issue
Block a user