Merge branch 'EvolutionAPI:main' into main

This commit is contained in:
Unilógica 2023-08-18 18:02:53 -03:00 committed by GitHub
commit 001849eeaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 162 additions and 27 deletions

View File

@ -1,4 +1,4 @@
# 1.5.0 (homolog)
# 1.5.0 (2023-08-18 12:47)
### Feature
@ -10,6 +10,7 @@
* Added rabbitmq to send events
* Added Typebot integration
* Added proxy endpoint
* Added send and date_time in webhook data
### Fixed
@ -19,6 +20,7 @@
* Update Dockerfile
* If you pass empty events in create instance and set webhook it is understood as all
* Fixed issue that did not output base64 averages
* Messages sent by the api now arrive in chatwoot
### Integrations

View File

@ -24,7 +24,11 @@ export const initAMQP = () => {
const exchangeName = 'evolution_exchange';
channel.assertExchange(exchangeName, 'topic', { durable: false });
channel.assertExchange(exchangeName, 'topic', {
durable: true,
autoDelete: false,
});
amqpChannel = channel;
logger.info('AMQP initialized');

View File

@ -27,7 +27,9 @@ function bootstrap() {
cors({
origin(requestOrigin, callback) {
const { ORIGIN } = configService.get<Cors>('CORS');
!requestOrigin ? (requestOrigin = '*') : undefined;
if (ORIGIN.includes('*')) {
return callback(null, true);
}
if (ORIGIN.indexOf(requestOrigin) !== -1) {
return callback(null, true);
}

View File

@ -1001,6 +1001,18 @@ export const typebotStatusSchema: JSONSchema7 = {
...isNotEmpty('remoteJid', 'status'),
};
export const typebotStartSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
url: { type: 'string' },
typebot: { type: 'string' },
},
required: ['remoteJid', 'url', 'typebot'],
...isNotEmpty('remoteJid', 'url', 'typebot'),
};
export const proxySchema: JSONSchema7 = {
$id: v4(),
type: 'object',

View File

@ -38,4 +38,9 @@ export class TypebotController {
logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance');
return this.typebotService.changeStatus(instance, data);
}
public async startTypebot(instance: InstanceDto, data: any) {
logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.startTypebot(instance, data);
}
}

View File

@ -1,7 +1,12 @@
import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config';
import { instanceNameSchema, typebotSchema, typebotStatusSchema } from '../../validate/validate.schema';
import {
instanceNameSchema,
typebotSchema,
typebotStartSchema,
typebotStatusSchema,
} from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto';
import { TypebotDto } from '../dto/typebot.dto';
@ -47,7 +52,7 @@ export class TypebotRouter extends RouterBroker {
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('changeStatus'), ...guards, async (req, res) => {
logger.verbose('request received in findTypebot');
logger.verbose('request received in changeStatusTypebot');
logger.verbose('request body: ');
logger.verbose(req.body);
@ -60,6 +65,22 @@ export class TypebotRouter extends RouterBroker {
execute: (instance, data) => typebotController.changeStatus(instance, data),
});
res.status(HttpStatus.OK).json(response);
})
.post(this.routerPath('start'), ...guards, async (req, res) => {
logger.verbose('request received in startTypebot');
logger.verbose('request body: ');
logger.verbose(req.body);
logger.verbose('request query: ');
logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({
request: req,
schema: typebotStartSchema,
ClassRef: InstanceDto,
execute: (instance, data) => typebotController.startTypebot(instance, data),
});
res.status(HttpStatus.OK).json(response);
});
}

View File

@ -84,6 +84,48 @@ export class TypebotService {
return { typebot: { ...instance, typebot: typebotData } };
}
public async startTypebot(instance: InstanceDto, data: any) {
const remoteJid = data.remoteJid;
const url = data.url;
const typebot = data.typebot;
const id = Math.floor(Math.random() * 10000000000).toString();
const reqData = {
sessionId: id,
startParams: {
typebot: data.typebot,
prefilledVariables: {
remoteJid: data.remoteJid,
pushName: data.pushName,
instanceName: instance.instanceName,
},
},
};
console.log(reqData);
const request = await axios.post(data.url + '/api/v1/sendMessage', reqData);
await this.sendWAMessage(
instance,
remoteJid,
request.data.messages,
request.data.input,
request.data.clientSideActions,
);
return {
typebot: {
...instance,
typebot: {
url: url,
remoteJid: remoteJid,
typebot: typebot,
},
},
};
}
private getTypeMessage(msg: any) {
this.logger.verbose('get type message');
@ -162,13 +204,34 @@ export class TypebotService {
return request.data;
}
public async sendWAMessage(instance: InstanceDto, remoteJid: string, messages: any[], input: any[]) {
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input).catch((err) => {
console.error('Erro ao processar mensagens:', err);
});
public async sendWAMessage(
instance: InstanceDto,
remoteJid: string,
messages: any[],
input: any[],
clientSideActions: any[],
) {
processMessages(this.waMonitor.waInstances[instance.instanceName], messages, input, clientSideActions).catch(
(err) => {
console.error('Erro ao processar mensagens:', err);
},
);
async function processMessages(instance, messages, input) {
function findItemAndGetSecondsToWait(array, targetId) {
if (!array) return null;
for (const item of array) {
if (item.lastBubbleBlockId === targetId) {
return item.wait?.secondsToWaitFor;
}
}
return null;
}
async function processMessages(instance, messages, input, clientSideActions) {
for (const message of messages) {
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
if (message.type === 'text') {
let formattedText = '';
@ -209,7 +272,7 @@ export class TypebotService {
await instance.textMessage({
number: remoteJid.split('@')[0],
options: {
delay: instance.localTypebot.delay_message || 1000,
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
presence: 'composing',
linkPreview: linkPreview,
},
@ -223,7 +286,7 @@ export class TypebotService {
await instance.mediaMessage({
number: remoteJid.split('@')[0],
options: {
delay: instance.localTypebot.delay_message || 1000,
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
presence: 'composing',
},
mediaMessage: {
@ -237,7 +300,7 @@ export class TypebotService {
await instance.mediaMessage({
number: remoteJid.split('@')[0],
options: {
delay: instance.localTypebot.delay_message || 1000,
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
presence: 'composing',
},
mediaMessage: {
@ -251,7 +314,7 @@ export class TypebotService {
await instance.audioWhatsapp({
number: remoteJid.split('@')[0],
options: {
delay: instance.localTypebot.delay_message || 1000,
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
presence: 'recording',
encoding: true,
},
@ -323,7 +386,7 @@ export class TypebotService {
pushName: msg.pushName,
});
await this.sendWAMessage(instance, remoteJid, data.messages, data.input);
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
return;
}
@ -346,7 +409,7 @@ export class TypebotService {
pushName: msg.pushName,
});
await this.sendWAMessage(instance, remoteJid, data.messages, data.input);
await this.sendWAMessage(instance, remoteJid, data.messages, data.input, data.clientSideActions);
return;
}
@ -414,7 +477,13 @@ export class TypebotService {
const request = await axios.post(url + '/api/v1/sendMessage', reqData);
await this.sendWAMessage(instance, remoteJid, request.data.messages, request.data.input);
await this.sendWAMessage(
instance,
remoteJid,
request.data.messages,
request.data.input,
request.data.clientSideActions,
);
return;
}

View File

@ -588,6 +588,9 @@ export class WAStartupService {
const serverUrl = this.configService.get<HttpServer>('SERVER').URL;
const we = event.replace(/[.-]/gm, '_').toUpperCase();
const transformedWe = we.replace(/_/gm, '-').toLowerCase();
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
const localISOTime = new Date(Date.now() - tzoffset).toISOString();
const now = localISOTime;
const expose = this.configService.get<Auth>('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES;
const tokenStore = await this.repository.auth.find(this.instanceName);
@ -598,13 +601,22 @@ export class WAStartupService {
if (amqp) {
if (Array.isArray(rabbitmqLocal) && rabbitmqLocal.includes(we)) {
const exchangeName = 'evolution_exchange';
const exchangeName = this.instanceName ?? 'evolution_exchange';
amqp.assertExchange(exchangeName, 'topic', { durable: false });
amqp.assertExchange(exchangeName, 'topic', {
durable: true,
autoDelete: false,
});
const queueName = `${this.instanceName}.${event}`;
amqp.assertQueue(queueName, { durable: false });
amqp.assertQueue(queueName, {
durable: true,
autoDelete: false,
arguments: {
'x-queue-type': 'quorum',
},
});
amqp.bindQueue(queueName, exchangeName, event);
@ -613,6 +625,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
server_url: serverUrl,
date_time: now,
sender: this.wuid,
};
if (expose && instanceApikey) {
@ -635,6 +649,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
server_url: serverUrl,
date_time: now,
sender: this.wuid,
};
if (expose && instanceApikey) {
@ -667,6 +683,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
destination: this.localWebhook.url,
date_time: now,
sender: this.wuid,
server_url: serverUrl,
apikey: (expose && instanceApikey) || null,
};
@ -686,6 +704,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
destination: this.localWebhook.url,
date_time: now,
sender: this.wuid,
server_url: serverUrl,
};
@ -735,6 +755,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
destination: localUrl,
date_time: now,
sender: this.wuid,
server_url: serverUrl,
};
@ -753,6 +775,8 @@ export class WAStartupService {
instance: this.instance.name,
data,
destination: localUrl,
date_time: now,
sender: this.wuid,
server_url: serverUrl,
};
@ -1976,13 +2000,9 @@ export class WAStartupService {
this.logger.verbose('Sending data to webhook in event SEND_MESSAGE');
await this.sendDataWebhook(Events.SEND_MESSAGE, messageRaw);
// if (this.localChatwoot.enabled) {
// this.chatwootService.eventWhatsapp(
// Events.SEND_MESSAGE,
// { instanceName: this.instance.name },
// messageRaw,
// );
// }
if (this.localChatwoot.enabled) {
this.chatwootService.eventWhatsapp(Events.SEND_MESSAGE, { instanceName: this.instance.name }, messageRaw);
}
this.logger.verbose('Inserting message in database');
await this.repository.message.insert(