Compare commits

..

19 Commits
1.7.0 ... 1.7.1

Author SHA1 Message Date
Davidson Gomes
5975117636 Merge branch 'release/1.7.1' 2024-04-03 10:45:51 -03:00
Davidson Gomes
51b285f665 v 1.7.1 2024-04-03 10:45:29 -03:00
Davidson Gomes
b3958d4735 Merge tag '1.7.1' into develop
v
2024-04-03 10:20:14 -03:00
Davidson Gomes
128119d494 Merge branch 'release/1.7.1' 2024-04-03 10:20:09 -03:00
Davidson Gomes
324dc01699 v 1.7.1 2024-04-03 10:19:59 -03:00
Davidson Gomes
f11d468e31 ajustes wa business 2024-04-03 08:14:56 -03:00
Davidson Gomes
aa5ed13752 ajustes wa business 2024-04-03 07:36:51 -03:00
Davidson Gomes
10ce7da18d changelog 2024-04-03 07:15:23 -03:00
Davidson Gomes
73bd55dfac changelog 2024-04-03 07:06:41 -03:00
Davidson Gomes
db10f81d53 Merge pull request #507 from Azzybot/patch-7
Reconhecer tipos de mensagens
2024-04-03 07:06:23 -03:00
Davidson Gomes
717aac4438 Merge pull request #506 from Azzybot/patch-6
Recurso para coletar tipo de mensagem
2024-04-03 07:06:01 -03:00
Davidson Gomes
077a464481 Merge pull request #505 from Azzybot/patch-5
Removido obrigatoriedade de descrição dos rows do sendList
2024-04-03 07:05:09 -03:00
Davidson Gomes
9bf18592fc ajustes wa oficial 2024-04-03 07:01:35 -03:00
Luis-Fernando
677e196c96 Ajuste Metodo getMessage 2024-04-02 20:43:58 -03:00
Luis-Fernando
19e6896f0d Reconhecer tipos de mensagens
Adicionado metodos para capturar diferentes tipos de mensagens alem do tipo texto.

Incluido:
AUDIO, VIDEO, IMAGEM, DOCUMENTOS E VISUALIZAÇÃO ÚNICA, Etc...
2024-04-02 18:59:08 -03:00
Luis-Fernando
ba537baab2 Recurso para coletar tipo de mensagem
Variável {{messageType}} adicionada para ser usada dentro do fluxo e a partir disso usar condições para fluxo seguir de acordo com o tipo de mensagem recebida:

Exemplo:
if {{messageTyp}} = audioMessage
if {{messageTyp}} = videoMessage
if {{messageTyp}} = imageMessage
if {{messageTyp}} = document
if {{messageTyp}} = conversation

Entre outras...

Exemplo:

![VideoCapture_20240402-144703](https://github.com/EvolutionAPI/evolution-api/assets/136400011/60b74721-9f14-4d60-99f2-369c42cd60de)
![VideoCapture_20240402-144739](https://github.com/EvolutionAPI/evolution-api/assets/136400011/f4febd4b-c42e-4678-bfd4-f1aa076c92f5)
![VideoCapture_20240402-144724](https://github.com/EvolutionAPI/evolution-api/assets/136400011/7eb0ba56-a05a-4015-8863-76e29e0613f6)
2024-04-02 18:37:00 -03:00
Luis-Fernando
2b8b6b086b Removido obrigatoriedade de descrição dos rows do sendList
Removida a obrigatoriedade da descrição do rows para ser algo opcional.

Isso permite os "circulos" das opções ficarem mais alinhados com os titulos sem a necessidade de adicionar espaço em branco caso não queira adicionar a descrição.

{
"number": "559999999999 (Recipient number with Country Code)",
"options": {
"delay": 1200,
"presence": "composing"
},
"listMessage": {
"title": "List Title",
"description": "List description",
"buttonText": "Click Here",
"footerText": "footer list\nhttps://examplelink.com.br",
"sections": [
{
"title": "Row tilte 01",
"rows": [
{
"title": "Title row 01",
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,",
"rowId": "rowId 001"
},
{
"title": "Title row 02",
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,",
"rowId": "rowId 002"
}
]
}
}

Depois:

{
"number": "559999999999 (Recipient number with Country Code)",
"options": {
"delay": 1200,
"presence": "composing"
},
"listMessage": {
"title": "List Title",
"description": "List description",
"buttonText": "Click Here",
"footerText": "footer list\nhttps://examplelink.com.br",
"sections": [
{
"title": "Row tilte 01",
"rows": [
{
"title": "Title row 01",
// "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,", //podendo remover por completo como foi feito no Title row 02 abaixo ou apenas comentar a descrição
"rowId": "rowId 001"
},
{
"title": "Title row 02",
"rowId": "rowId 002"
}
]
}
}
2024-04-02 17:59:54 -03:00
Davidson Gomes
cf3ec2b601 ajustes 2024-04-02 16:05:14 -03:00
Davidson Gomes
35eaa7852c Merge tag '1.7.0' into develop
v
2024-03-27 16:36:29 -03:00
8 changed files with 228 additions and 31 deletions

View File

@@ -1,3 +1,14 @@
# 1.7.1 (2024-04-03 10:19)
### Fixed
* Correction when sending files with captions on Whatsapp Business
* Correction in receiving messages with response on WhatsApp Business
* Correction when sending a reaction to a message on WhatsApp Business
* Correction of receiving reactions on WhatsApp business
* Removed mandatory description of rows from sendList
* Feature to collect message type in typebot
# 1.7.0 (2024-03-11 18:23) # 1.7.0 (2024-03-11 18:23)
### Feature ### Feature

View File

@@ -1,6 +1,6 @@
FROM node:20.7.0-alpine AS builder FROM node:20.7.0-alpine AS builder
LABEL version="1.7.0" description="Api to control whatsapp features through http requests." LABEL version="1.7.1" description="Api to control whatsapp features through http requests."
LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes" LABEL maintainer="Davidson Gomes" git="https://github.com/DavidsonGomes"
LABEL contact="contato@agenciadgcode.com" LABEL contact="contato@agenciadgcode.com"

View File

@@ -1,6 +1,6 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "1.7.0", "version": "1.7.1",
"description": "Rest api for communication with WhatsApp", "description": "Rest api for communication with WhatsApp",
"main": "./dist/src/main.js", "main": "./dist/src/main.js",
"scripts": { "scripts": {

View File

@@ -25,7 +25,7 @@ info:
</font> </font>
[![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/26869335-5546d063-156b-4529-915f-909dd628c090?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D26869335-5546d063-156b-4529-915f-909dd628c090%26entityType%3Dcollection%26workspaceId%3D339a4ee7-378b-45c9-b5b8-fd2c0a9c2442) [![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/26869335-5546d063-156b-4529-915f-909dd628c090?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D26869335-5546d063-156b-4529-915f-909dd628c090%26entityType%3Dcollection%26workspaceId%3D339a4ee7-378b-45c9-b5b8-fd2c0a9c2442)
version: 1.7.0 version: 1.7.1
contact: contact:
name: DavidsonGomes name: DavidsonGomes
email: contato@agenciadgcode.com email: contato@agenciadgcode.com

View File

@@ -406,7 +406,7 @@ export const listMessageSchema: JSONSchema7 = {
description: { type: 'string' }, description: { type: 'string' },
rowId: { type: 'string' }, rowId: { type: 'string' },
}, },
required: ['title', 'description', 'rowId'], required: ['title', 'rowId'],
...isNotEmpty('title', 'description', 'rowId'), ...isNotEmpty('title', 'description', 'rowId'),
}, },
}, },

View File

@@ -10,6 +10,7 @@ export class Session {
export class PrefilledVariables { export class PrefilledVariables {
remoteJid?: string; remoteJid?: string;
pushName?: string; pushName?: string;
messageType?: string;
additionalData?: { [key: string]: any }; additionalData?: { [key: string]: any };
} }

View File

@@ -269,19 +269,27 @@ export class TypebotService {
} }
private getTypeMessage(msg: any) { private getTypeMessage(msg: any) {
this.logger.verbose('get type message'); this.logger.verbose('get type message');
const types = {
conversation: msg.conversation,
extendedTextMessage: msg.extendedTextMessage?.text,
audioMessage: msg.audioMessage?.url,
imageMessage: msg.imageMessage?.url,
videoMessage: msg.videoMessage?.url,
documentMessage: msg.documentMessage?.fileName,
contactMessage: msg.contactMessage?.displayName,
locationMessage: msg.locationMessage?.degreesLatitude,
viewOnceMessageV2: msg.viewOnceMessageV2?.message?.imageMessage?.url || msg.viewOnceMessageV2?.message?.videoMessage?.url || msg.viewOnceMessageV2?.message?.audioMessage?.url,
listResponseMessage: msg.listResponseMessage?.singleSelectReply?.selectedRowId,
responseRowId: msg.listResponseMessage?.singleSelectReply?.selectedRowId,
};
const types = { const messageType = Object.keys(types).find(key => types[key] !== undefined) || 'unknown';
conversation: msg.conversation,
extendedTextMessage: msg.extendedTextMessage?.text, this.logger.verbose('Type message: ' + JSON.stringify(types));
responseRowId: msg.listResponseMessage?.singleSelectReply?.selectedRowId, return { ...types, messageType };
};
this.logger.verbose('type message: ' + types);
return types;
} }
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);
@@ -305,6 +313,101 @@ export class TypebotService {
return messageContent; return messageContent;
} }
private getAudioMessageContent(msg: any) {
this.logger.verbose('get audio message content');
const types = this.getTypeMessage(msg);
const audioContent = types.audioMessage;
this.logger.verbose('audio message URL: ' + audioContent);
return audioContent;
}
private getImageMessageContent(msg: any) {
this.logger.verbose('get image message content');
const types = this.getTypeMessage(msg);
const imageContent = types.imageMessage;
this.logger.verbose('image message URL: ' + imageContent);
return imageContent;
}
private getVideoMessageContent(msg: any) {
this.logger.verbose('get video message content');
const types = this.getTypeMessage(msg);
const videoContent = types.videoMessage;
this.logger.verbose('video message URL: ' + videoContent);
return videoContent;
}
private getDocumentMessageContent(msg: any) {
this.logger.verbose('get document message content');
const types = this.getTypeMessage(msg);
const documentContent = types.documentMessage;
this.logger.verbose('document message fileName: ' + documentContent);
return documentContent;
}
private getContactMessageContent(msg: any) {
this.logger.verbose('get contact message content');
const types = this.getTypeMessage(msg);
const contactContent = types.contactMessage;
this.logger.verbose('contact message displayName: ' + contactContent);
return contactContent;
}
private getLocationMessageContent(msg: any) {
this.logger.verbose('get location message content');
const types = this.getTypeMessage(msg);
const locationContent = types.locationMessage;
this.logger.verbose('location message degreesLatitude: ' + locationContent);
return locationContent;
}
private getViewOnceMessageV2Content(msg: any) {
this.logger.verbose('get viewOnceMessageV2 content');
const types = this.getTypeMessage(msg);
const viewOnceContent = types.viewOnceMessageV2;
this.logger.verbose('viewOnceMessageV2 URL: ' + viewOnceContent);
return viewOnceContent;
}
private getListResponseMessageContent(msg: any) {
this.logger.verbose('get listResponseMessage content');
const types = this.getTypeMessage(msg);
const listResponseContent = types.listResponseMessage || types.responseRowId;
this.logger.verbose('listResponseMessage selectedRowId: ' + listResponseContent);
return listResponseContent;
}
public async createNewSession(instance: InstanceDto, data: any) { public async createNewSession(instance: InstanceDto, data: any) {
if (data.remoteJid === 'status@broadcast') return; if (data.remoteJid === 'status@broadcast') return;
const id = Math.floor(Math.random() * 10000000000).toString(); const id = Math.floor(Math.random() * 10000000000).toString();
@@ -565,6 +668,7 @@ export class TypebotService {
const delay_message = findTypebot.delay_message; const delay_message = findTypebot.delay_message;
const unknown_message = findTypebot.unknown_message; const unknown_message = findTypebot.unknown_message;
const listening_from_me = findTypebot.listening_from_me; const listening_from_me = findTypebot.listening_from_me;
const messageType = this.getTypeMessage(msg.message).messageType;
const session = sessions.find((session) => session.remoteJid === remoteJid); const session = sessions.find((session) => session.remoteJid === remoteJid);
@@ -687,6 +791,9 @@ export class TypebotService {
sessions: sessions, sessions: sessions,
remoteJid: remoteJid, remoteJid: remoteJid,
pushName: msg.pushName, pushName: msg.pushName,
prefilledVariables: {
messageType: messageType,
},
}); });
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions); await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);

View File

@@ -183,14 +183,28 @@ export class BusinessStartupService extends WAStartupService {
const message = received.messages[0]; const message = received.messages[0];
let content: any = message.type + 'Message'; let content: any = message.type + 'Message';
content = { [content]: message[message.type] }; content = { [content]: message[message.type] };
message.context ? (content.extendedTextMessage = { contextInfo: { stanzaId: message.context.id } }) : content; message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
return content; return content;
} }
private messageInteractiveJson(received: any) { private messageInteractiveJson(received: any) {
const message = received.messages[0]; const message = received.messages[0];
const content: any = { conversation: message.interactive[message.interactive.type].title }; let content: any = { conversation: message.interactive[message.interactive.type].title };
message.context ? (content.extendedTextMessage = { contextInfo: { stanzaId: message.context.id } }) : content; message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
return content;
}
private messageReactionJson(received: any) {
const message = received.messages[0];
let content: any = {
reactionMessage: {
key: {
id: message.reaction.message_id,
},
text: message.reaction.emoji,
},
};
message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
return content; return content;
} }
@@ -198,18 +212,20 @@ export class BusinessStartupService extends WAStartupService {
let content: any; let content: any;
const message = received.messages[0]; const message = received.messages[0];
if (message.from === received.metadata.phone_number_id) { if (message.from === received.metadata.phone_number_id) {
content = { extendedTextMessage: { text: message.text.body } }; content = {
message.context ? (content.extendedTextMessage.contextInfo = { stanzaId: message.context.id }) : content; extendedTextMessage: { text: message.text.body },
};
message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
} else { } else {
content = { conversation: message.text.body }; content = { conversation: message.text.body };
message.context ? (content.extendedTextMessage = { contextInfo: { stanzaId: message.context.id } }) : content; message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
} }
return content; return content;
} }
private messageContactsJson(received: any) { private messageContactsJson(received: any) {
const message = received.messages[0]; const message = received.messages[0];
const content: any = {}; let content: any = {};
const vcard = (contact: any) => { const vcard = (contact: any) => {
this.logger.verbose('Creating vcard'); this.logger.verbose('Creating vcard');
@@ -264,7 +280,7 @@ export class BusinessStartupService extends WAStartupService {
}), }),
}; };
} }
message.context ? (content.extendedTextMessage = { contextInfo: { stanzaId: message.context.id } }) : content; message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content;
return content; return content;
} }
@@ -287,8 +303,11 @@ export class BusinessStartupService extends WAStartupService {
case 'document': case 'document':
messageType = 'documentMessage'; messageType = 'documentMessage';
break; break;
case 'template':
messageType = 'conversation';
break;
default: default:
messageType = 'imageMessage'; messageType = 'conversation';
break; break;
} }
@@ -339,6 +358,18 @@ export class BusinessStartupService extends WAStartupService {
owner: this.instance.name, owner: this.instance.name,
// source: getDevice(received.key.id), // source: getDevice(received.key.id),
}; };
} else if (received?.messages[0].reaction) {
messageRaw = {
key,
pushName,
message: {
...this.messageReactionJson(received),
},
messageType: 'reactionMessage',
messageTimestamp: received.messages[0].timestamp as number,
owner: this.instance.name,
// source: getDevice(received.key.id),
};
} else if (received?.messages[0].contacts) { } else if (received?.messages[0].contacts) {
messageRaw = { messageRaw = {
key, key,
@@ -374,6 +405,7 @@ export class BusinessStartupService extends WAStartupService {
this.logger.log(messageRaw); this.logger.log(messageRaw);
this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT'); this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT');
this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw);
if (this.localChatwoot.enabled) { if (this.localChatwoot.enabled) {
@@ -540,30 +572,68 @@ export class BusinessStartupService extends WAStartupService {
} }
} }
private convertMessageToRaw(message: any) { private convertMessageToRaw(message: any, content: any) {
let convertMessage: any;
if (message?.conversation) { if (message?.conversation) {
return message; if (content?.context?.message_id) {
convertMessage = {
...message,
contextInfo: { stanzaId: content.context.message_id },
};
return convertMessage;
}
convertMessage = message;
return convertMessage;
} }
if (message?.mediaType === 'image') { if (message?.mediaType === 'image') {
if (content?.context?.message_id) {
convertMessage = {
imageMessage: message,
contextInfo: { stanzaId: content.context.message_id },
};
return convertMessage;
}
return { return {
imageMessage: message, imageMessage: message,
}; };
} }
if (message?.mediaType === 'video') { if (message?.mediaType === 'video') {
if (content?.context?.message_id) {
convertMessage = {
videoMessage: message,
contextInfo: { stanzaId: content.context.message_id },
};
return convertMessage;
}
return { return {
videoMessage: message, videoMessage: message,
}; };
} }
if (message?.mediaType === 'audio') { if (message?.mediaType === 'audio') {
if (content?.context?.message_id) {
convertMessage = {
audioMessage: message,
contextInfo: { stanzaId: content.context.message_id },
};
return convertMessage;
}
return { return {
audioMessage: message, audioMessage: message,
}; };
} }
if (message?.mediaType === 'document') { if (message?.mediaType === 'document') {
if (content?.context?.message_id) {
convertMessage = {
documentMessage: message,
contextInfo: { stanzaId: content.context.message_id },
};
return convertMessage;
}
return { return {
documentMessage: message, documentMessage: message,
}; };
@@ -610,7 +680,6 @@ export class BusinessStartupService extends WAStartupService {
message_id: message['reactionMessage']['key']['id'], message_id: message['reactionMessage']['key']['id'],
emoji: message['reactionMessage']['text'], emoji: message['reactionMessage']['text'],
}, },
context: { message_id: quoted.id },
}; };
quoted ? (content.context = { message_id: quoted.id }) : content; quoted ? (content.context = { message_id: quoted.id }) : content;
return await this.post(content, 'messages'); return await this.post(content, 'messages');
@@ -670,6 +739,7 @@ export class BusinessStartupService extends WAStartupService {
[message['mediaType']]: { [message['mediaType']]: {
[message['type']]: message['id'], [message['type']]: message['id'],
preview_url: linkPreview, preview_url: linkPreview,
caption: message['caption'],
}, },
}; };
quoted ? (content.context = { message_id: quoted.id }) : content; quoted ? (content.context = { message_id: quoted.id }) : content;
@@ -771,10 +841,17 @@ export class BusinessStartupService extends WAStartupService {
} }
})(); })();
if (messageSent?.error?.message) {
this.logger.error(messageSent.error.message);
throw messageSent.error.message.toString();
}
console.log(content);
const messageRaw: MessageRaw = { const messageRaw: MessageRaw = {
key: { fromMe: true, id: messageSent?.messages[0]?.id, remoteJid: this.createJid(number) }, key: { fromMe: true, id: messageSent?.messages[0]?.id, remoteJid: this.createJid(number) },
//pushName: messageSent.pushName, //pushName: messageSent.pushName,
message: this.convertMessageToRaw(message), message: this.convertMessageToRaw(message, content),
messageType: this.renderMessageType(content.type), messageType: this.renderMessageType(content.type),
messageTimestamp: (messageSent?.messages[0]?.timestamp as number) || Math.round(new Date().getTime() / 1000), messageTimestamp: (messageSent?.messages[0]?.timestamp as number) || Math.round(new Date().getTime() / 1000),
owner: this.instance.name, owner: this.instance.name,
@@ -1154,6 +1231,10 @@ export class BusinessStartupService extends WAStartupService {
} }
} }
public async deleteMessage() {
throw new BadRequestException('Method not available on WhatsApp Business API');
}
// methods not available on WhatsApp Business API // methods not available on WhatsApp Business API
public async mediaSticker() { public async mediaSticker() {
throw new BadRequestException('Method not available on WhatsApp Business API'); throw new BadRequestException('Method not available on WhatsApp Business API');
@@ -1176,9 +1257,6 @@ export class BusinessStartupService extends WAStartupService {
public async archiveChat() { public async archiveChat() {
throw new BadRequestException('Method not available on WhatsApp Business API'); throw new BadRequestException('Method not available on WhatsApp Business API');
} }
public async deleteMessage() {
throw new BadRequestException('Method not available on WhatsApp Business API');
}
public async fetchProfile() { public async fetchProfile() {
throw new BadRequestException('Method not available on WhatsApp Business API'); throw new BadRequestException('Method not available on WhatsApp Business API');
} }