Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Improvement] - Send and Update source_id of messages to chatwoot #108

Merged
merged 5 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"dependencies": {
"@adiwajshing/keyed-db": "^0.2.4",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@figuro/chatwoot-sdk": "^1.1.14",
"@figuro/chatwoot-sdk": "^1.1.16",
"@hapi/boom": "^10.0.1",
"@sentry/node": "^7.59.2",
"@whiskeysockets/baileys": "^6.4.1",
Expand Down
8 changes: 8 additions & 0 deletions src/config/env.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export type Websocket = {
ENABLED: boolean;
};

export type Chatwoot = {
USE_REPLY_ID: boolean;
};

export type EventsWebhook = {
APPLICATION_STARTUP: boolean;
QRCODE_UPDATED: boolean;
Expand Down Expand Up @@ -139,6 +143,7 @@ export interface Env {
QRCODE: QrCode;
AUTHENTICATION: Auth;
PRODUCTION?: Production;
CHATWOOT?: Chatwoot;
}

export type Key = keyof Env;
Expand Down Expand Up @@ -297,6 +302,9 @@ export class ConfigService {
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
},
},
CHATWOOT: {
USE_REPLY_ID: process.env?.USE_REPLY_ID === 'true',
},
};
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/dev-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,7 @@ AUTHENTICATION:
JWT:
EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires
SECRET: L=0YWt]b2w[WF>#>:&E`

# Configure to chatwoot
CHATWOOT:
USE_REPLY_ID: false
2 changes: 2 additions & 0 deletions src/whatsapp/models/message.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export class MessageRaw {
messageTimestamp?: number | Long.Long;
owner: string;
source?: 'android' | 'web' | 'ios';
source_id?: string;
source_reply_id?: string;
}

const messageSchema = new Schema<MessageRaw>({
Expand Down
145 changes: 134 additions & 11 deletions src/whatsapp/services/chatwoot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createReadStream, readFileSync, unlinkSync, writeFileSync } from 'fs';
import mimeTypes from 'mime-types';
import path from 'path';

import { ConfigService } from '../../config/env.config';
import { Chatwoot, ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { ROOT_DIR } from '../../config/path.config';
import { ChatwootDto } from '../dto/chatwoot.dto';
Expand Down Expand Up @@ -612,6 +612,8 @@ export class ChatwootService {
conversationId: number,
content: string,
messageType: 'incoming' | 'outgoing' | undefined,
source_id?: string,
source_reply_id?: string,
privateMessage?: boolean,
attachments?: {
content: unknown;
Expand All @@ -637,6 +639,8 @@ export class ChatwootService {
message_type: messageType,
attachments: attachments,
private: privateMessage || false,
source_id: source_id,
source_reply_id: source_reply_id,
},
});

Expand Down Expand Up @@ -732,6 +736,8 @@ export class ChatwootService {
file: string,
messageType: 'incoming' | 'outgoing' | undefined,
content?: string,
source_id?: string,
source_reply_id?: string,
) {
this.logger.verbose('send data to chatwoot');

Expand All @@ -748,6 +754,16 @@ export class ChatwootService {
this.logger.verbose('temp file found');
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);
const config = {
method: 'post',
Expand Down Expand Up @@ -913,10 +929,10 @@ export class ChatwootService {
},
};

await waInstance?.audioWhatsapp(data);
const audioWhatsapp = await waInstance?.audioWhatsapp(data);

this.logger.verbose('audio sent');
return;
return audioWhatsapp;
}

this.logger.verbose('send media to instance: ' + waInstance.instanceName);
Expand All @@ -938,15 +954,48 @@ export class ChatwootService {
data.mediaMessage.caption = caption;
}

await waInstance?.mediaMessage(data);
const mediaMessage = await waInstance?.mediaMessage(data);

this.logger.verbose('media sent');
return;
return mediaMessage;
} catch (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) {
try {
// espera 500ms para evitar duplicidade de mensagens
Expand Down Expand Up @@ -1047,6 +1096,9 @@ export class ChatwootService {
}

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');
if (message.attachments && message.attachments.length > 0) {
this.logger.verbose('message is media');
Expand All @@ -1057,7 +1109,8 @@ export class ChatwootService {
formatText = null;
}

await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
const mediaMessage = await this.sendAttachment(waInstance, chatId, attachment.data_url, formatText);
await this.updateMessage(instance, accountId, conversationId, messageId, mediaMessage?.key?.id);
}
} else {
this.logger.verbose('message is text');
Expand All @@ -1074,7 +1127,8 @@ export class ChatwootService {
},
};

await waInstance?.textMessage(data);
const message = await waInstance?.textMessage(data);
await this.updateMessage(instance, accountId, conversationId, messageId, message?.key?.id);
}
}
}
Expand Down Expand Up @@ -1149,6 +1203,38 @@ export class ChatwootService {
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) {
this.logger.verbose('get message content');
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
Expand Down Expand Up @@ -1248,6 +1334,18 @@ export class ChatwootService {
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) {
this.logger.verbose('event whatsapp to instance: ' + instance.instanceName);
try {
Expand Down Expand Up @@ -1276,6 +1374,8 @@ export class ChatwootService {
this.logger.verbose('get conversation message');
const bodyMessage = await this.getConversationMessage(body.message);

const source_reply_id = this.getContextConversationMessage(body.message);

const isMedia = this.isMediaMessage(body.message);

if (!bodyMessage && !isMedia) {
Expand All @@ -1293,6 +1393,8 @@ export class ChatwootService {

const messageType = body.key.fromMe ? 'outgoing' : 'incoming';

const source_id = body.key?.id;

this.logger.verbose('message type: ' + messageType);

this.logger.verbose('is media: ' + isMedia);
Expand Down Expand Up @@ -1337,7 +1439,7 @@ export class ChatwootService {
}

this.logger.verbose('send data to chatwoot');
const send = await this.sendData(getConversion, fileName, messageType, content);
const send = await this.sendData(getConversion, fileName, messageType, content, source_id, source_reply_id);

if (!send) {
this.logger.warn('message not sent');
Expand All @@ -1358,7 +1460,14 @@ export class ChatwootService {
this.logger.verbose('message is not group');

this.logger.verbose('send data to chatwoot');
const send = await this.sendData(getConversion, fileName, messageType, bodyMessage);
const send = await this.sendData(
getConversion,
fileName,
messageType,
bodyMessage,
source_id,
source_reply_id,
);

if (!send) {
this.logger.warn('message not sent');
Expand Down Expand Up @@ -1394,7 +1503,14 @@ export class ChatwootService {
}

this.logger.verbose('send data to chatwoot');
const send = await this.createMessage(instance, getConversion, content, messageType);
const send = await this.createMessage(
instance,
getConversion,
content,
messageType,
source_id,
source_reply_id,
);

if (!send) {
this.logger.warn('message not sent');
Expand All @@ -1415,7 +1531,14 @@ export class ChatwootService {
this.logger.verbose('message is not group');

this.logger.verbose('send data to chatwoot');
const send = await this.createMessage(instance, getConversion, bodyMessage, messageType);
const send = await this.createMessage(
instance,
getConversion,
bodyMessage,
messageType,
source_id,
source_reply_id,
);

if (!send) {
this.logger.warn('message not sent');
Expand Down