mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-27 02:48:39 -06:00
added: Integration with whatsapp business api
This commit is contained in:
parent
1a2546c52b
commit
1686ef58cf
@ -46,7 +46,7 @@
|
|||||||
"@figuro/chatwoot-sdk": "^1.1.16",
|
"@figuro/chatwoot-sdk": "^1.1.16",
|
||||||
"@hapi/boom": "^10.0.1",
|
"@hapi/boom": "^10.0.1",
|
||||||
"@sentry/node": "^7.59.2",
|
"@sentry/node": "^7.59.2",
|
||||||
"@whiskeysockets/baileys": "^6.5.0",
|
"@whiskeysockets/baileys": "github:PurpShell/Baileys#combined",
|
||||||
"amqplib": "^0.10.3",
|
"amqplib": "^0.10.3",
|
||||||
"aws-sdk": "^2.1499.0",
|
"aws-sdk": "^2.1499.0",
|
||||||
"axios": "^1.3.5",
|
"axios": "^1.3.5",
|
||||||
|
@ -120,6 +120,7 @@ export type EventsWebhook = {
|
|||||||
|
|
||||||
export type ApiKey = { KEY: string };
|
export type ApiKey = { KEY: string };
|
||||||
export type Jwt = { EXPIRIN_IN: number; SECRET: string };
|
export type Jwt = { EXPIRIN_IN: number; SECRET: string };
|
||||||
|
export type WABussiness = { ACESS_TOKEN: string, URL: string, VERSION: string, LANGUAGE: string };
|
||||||
|
|
||||||
export type Auth = {
|
export type Auth = {
|
||||||
API_KEY: ApiKey;
|
API_KEY: ApiKey;
|
||||||
@ -161,6 +162,7 @@ export interface Env {
|
|||||||
TYPEBOT: Typebot;
|
TYPEBOT: Typebot;
|
||||||
AUTHENTICATION: Auth;
|
AUTHENTICATION: Auth;
|
||||||
PRODUCTION?: Production;
|
PRODUCTION?: Production;
|
||||||
|
WABUSSINESS: WABussiness;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Key = keyof Env;
|
export type Key = keyof Env;
|
||||||
@ -337,6 +339,12 @@ export class ConfigService {
|
|||||||
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
|
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
WABUSSINESS: {
|
||||||
|
ACESS_TOKEN: process.env.ACESS_TOKEN,
|
||||||
|
URL: process.env.URL,
|
||||||
|
VERSION: process.env.VERSION,
|
||||||
|
LANGUAGE: process.env.LANGUAGE
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ export class Logger {
|
|||||||
|
|
||||||
function salvarLog(env: any, log: string): void {
|
function salvarLog(env: any, log: string): void {
|
||||||
mkdir(env.LOG_PATH, { recursive: true }, (err) => { if (err) throw err; });
|
mkdir(env.LOG_PATH, { recursive: true }, (err) => { if (err) throw err; });
|
||||||
let file = new Date().toLocaleDateString().replaceAll('/', '');
|
let file = new Date().toLocaleDateString('pt-BR').replaceAll('/', '');
|
||||||
file = env.LOG_PATH + '/' + file + '.txt';
|
file = env.LOG_PATH + '/' + file + '.txt';
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(file)) {
|
if (fs.existsSync(file)) {
|
||||||
@ -176,9 +176,9 @@ function excluirArquivosAntigos(path: string, diasLimite: number): void {
|
|||||||
data.setDate(data.getDate() - diasLimite);
|
data.setDate(data.getDate() - diasLimite);
|
||||||
fs.readdirSync(path).forEach((nomeArquivo) => {
|
fs.readdirSync(path).forEach((nomeArquivo) => {
|
||||||
let Timerfile = new Date(parseInt(nomeArquivo.substring(8, 4)),
|
let Timerfile = new Date(parseInt(nomeArquivo.substring(8, 4)),
|
||||||
parseInt(nomeArquivo.substring(4, 2)), parseInt(nomeArquivo.substring(2, 0)))
|
1-parseInt(nomeArquivo.substring(4, 2)), parseInt(nomeArquivo.substring(2, 0)))
|
||||||
|
|
||||||
if (Timerfile.getTime() < data.getTime()) {
|
if ((Timerfile.getTime() > 0) && (Timerfile.getTime() < data.getTime())) {
|
||||||
fs.unlinkSync(path + '/' + nomeArquivo);
|
fs.unlinkSync(path + '/' + nomeArquivo);
|
||||||
console.log(`Arquivo ${nomeArquivo} excluído.`);
|
console.log(`Arquivo ${nomeArquivo} excluído.`);
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
|
|||||||
const properties = {};
|
const properties = {};
|
||||||
propertyNames.forEach(
|
propertyNames.forEach(
|
||||||
(property) =>
|
(property) =>
|
||||||
(properties[property] = {
|
(properties[property] = {
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
description: `The "${property}" cannot be empty`,
|
description: `The "${property}" cannot be empty`,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
if: {
|
if: {
|
||||||
@ -389,6 +389,25 @@ export const listMessageSchema: JSONSchema7 = {
|
|||||||
required: ['number', 'listMessage'],
|
required: ['number', 'listMessage'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const templateMessageSchema: JSONSchema7 = {
|
||||||
|
$id: v4(),
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { ...numberDefinition },
|
||||||
|
options: { ...optionsSchema },
|
||||||
|
templateMessage: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: { type: 'string' },
|
||||||
|
language: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['name', 'language'],
|
||||||
|
...isNotEmpty('name', 'language'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['templateMessage', 'number'],
|
||||||
|
};
|
||||||
|
|
||||||
export const contactMessageSchema: JSONSchema7 = {
|
export const contactMessageSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -601,6 +620,28 @@ export const profilePictureSchema: JSONSchema7 = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const profileBusinessSchema: JSONSchema7 = {
|
||||||
|
$id: v4(),
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { type: 'string' },
|
||||||
|
about: { type: 'string' },
|
||||||
|
address: { type: 'string' },
|
||||||
|
description: { type: 'string' },
|
||||||
|
vertical: { type: 'string' },
|
||||||
|
email: { type: 'string' },
|
||||||
|
profile_picture_handle: { type: 'string' },
|
||||||
|
websites: {
|
||||||
|
type: 'array',
|
||||||
|
minItems: 1,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const profileSchema: JSONSchema7 = {
|
export const profileSchema: JSONSchema7 = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
ReadMessageDto,
|
ReadMessageDto,
|
||||||
SendPresenceDto,
|
SendPresenceDto,
|
||||||
WhatsAppNumberDto,
|
WhatsAppNumberDto,
|
||||||
|
NumberBusiness,
|
||||||
} from '../dto/chat.dto';
|
} from '../dto/chat.dto';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { ContactQuery } from '../repository/contact.repository';
|
import { ContactQuery } from '../repository/contact.repository';
|
||||||
@ -117,4 +118,9 @@ export class ChatController {
|
|||||||
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
return await this.waMonitor.waInstances[instanceName].removeProfilePicture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setWhatsappBusinessProfile({ instanceName }: InstanceDto, data: NumberBusiness) {
|
||||||
|
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
|
||||||
|
return await this.waMonitor.waInstances[instanceName].setWhatsappBusinessProfile(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { isURL } from 'class-validator';
|
|||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
import { ConfigService, HttpServer, WABussiness } from '../../config/env.config';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
import { BadRequestException, InternalServerErrorException } from '../../exceptions';
|
||||||
import { RedisCache } from '../../libs/redis.client';
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
@ -19,8 +19,8 @@ import { SqsService } from '../services/sqs.service';
|
|||||||
import { TypebotService } from '../services/typebot.service';
|
import { TypebotService } from '../services/typebot.service';
|
||||||
import { WebhookService } from '../services/webhook.service';
|
import { WebhookService } from '../services/webhook.service';
|
||||||
import { WebsocketService } from '../services/websocket.service';
|
import { WebsocketService } from '../services/websocket.service';
|
||||||
import { WAStartupService } from '../services/whatsapp.service';
|
import { Events, wa, Integration } from '../types/wa.types';
|
||||||
import { Events, wa } from '../types/wa.types';
|
import { WAStartupClass } from '../whatsapp.module';
|
||||||
|
|
||||||
export class InstanceController {
|
export class InstanceController {
|
||||||
constructor(
|
constructor(
|
||||||
@ -50,6 +50,7 @@ export class InstanceController {
|
|||||||
events,
|
events,
|
||||||
qrcode,
|
qrcode,
|
||||||
number,
|
number,
|
||||||
|
integration,
|
||||||
token,
|
token,
|
||||||
chatwoot_account_id,
|
chatwoot_account_id,
|
||||||
chatwoot_token,
|
chatwoot_token,
|
||||||
@ -85,9 +86,10 @@ export class InstanceController {
|
|||||||
await this.authService.checkDuplicateToken(token);
|
await this.authService.checkDuplicateToken(token);
|
||||||
|
|
||||||
this.logger.verbose('creating instance');
|
this.logger.verbose('creating instance');
|
||||||
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
const instance = new WAStartupClass[integration](this.configService, this.eventEmitter, this.repository, this.cache);
|
||||||
instance.instanceName = instanceName;
|
instance.instanceName = instanceName;
|
||||||
|
instance.instanceNumber = number;
|
||||||
|
instance.instanceToken = token;
|
||||||
const instanceId = v4();
|
const instanceId = v4();
|
||||||
|
|
||||||
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
|
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
|
||||||
@ -359,20 +361,30 @@ export class InstanceController {
|
|||||||
|
|
||||||
this.settingsService.create(instance, settings);
|
this.settingsService.create(instance, settings);
|
||||||
|
|
||||||
|
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
||||||
|
let webhook_url = '', acess_token = '';
|
||||||
|
if(integration === Integration.WHATSAPP_BUSINESS)
|
||||||
|
{
|
||||||
|
webhook_url = `${urlServer}/webhook/whatsapp/${encodeURIComponent(instance.instanceName)}`;
|
||||||
|
acess_token = this.configService.get<WABussiness>('WABUSSINESS').ACESS_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) {
|
if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) {
|
||||||
let getQrcode: wa.QrCode;
|
let getQrcode: wa.QrCode;
|
||||||
|
|
||||||
|
|
||||||
|
await this.waMonitor.saveInstance({integration, instanceName, token, number});
|
||||||
if (qrcode) {
|
if (qrcode) {
|
||||||
this.logger.verbose('creating qrcode');
|
this.logger.verbose('creating qrcode');
|
||||||
await instance.connectToWhatsapp(number);
|
await instance.connectToWhatsapp(number);
|
||||||
await delay(5000);
|
await delay(5000);
|
||||||
getQrcode = instance.qrCode;
|
getQrcode = instance.qrCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
instance: {
|
instance: {
|
||||||
instanceName: instance.instanceName,
|
instanceName: instance.instanceName,
|
||||||
instanceId: instanceId,
|
instanceId: instanceId,
|
||||||
|
integration: integration,
|
||||||
status: 'created',
|
status: 'created',
|
||||||
},
|
},
|
||||||
hash,
|
hash,
|
||||||
@ -405,6 +417,7 @@ export class InstanceController {
|
|||||||
listening_from_me: typebot_listening_from_me,
|
listening_from_me: typebot_listening_from_me,
|
||||||
},
|
},
|
||||||
settings,
|
settings,
|
||||||
|
webhook_url: webhook_url,
|
||||||
qrcode: getQrcode,
|
qrcode: getQrcode,
|
||||||
proxy,
|
proxy,
|
||||||
};
|
};
|
||||||
@ -423,6 +436,10 @@ export class InstanceController {
|
|||||||
throw new BadRequestException('token is required');
|
throw new BadRequestException('token is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!integration) {
|
||||||
|
throw new BadRequestException('integration is required');
|
||||||
|
}
|
||||||
|
|
||||||
if (!chatwoot_url) {
|
if (!chatwoot_url) {
|
||||||
throw new BadRequestException('url is required');
|
throw new BadRequestException('url is required');
|
||||||
}
|
}
|
||||||
@ -443,8 +460,6 @@ export class InstanceController {
|
|||||||
throw new BadRequestException('conversation_pending is required');
|
throw new BadRequestException('conversation_pending is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.chatwootService.create(instance, {
|
this.chatwootService.create(instance, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -617,7 +632,7 @@ export class InstanceController {
|
|||||||
await this.waMonitor.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
await this.waMonitor.waInstances[instanceName]?.client?.logout('Log out instance: ' + instanceName);
|
||||||
|
|
||||||
this.logger.verbose('close connection instance: ' + instanceName);
|
this.logger.verbose('close connection instance: ' + instanceName);
|
||||||
this.waMonitor.waInstances[instanceName]?.client?.ws?.close();
|
this.waMonitor.waInstances[instanceName]?.closeClient();
|
||||||
|
|
||||||
return { status: 'SUCCESS', error: false, response: { message: 'Instance logged out' } };
|
return { status: 'SUCCESS', error: false, response: { message: 'Instance logged out' } };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
SendStatusDto,
|
SendStatusDto,
|
||||||
SendStickerDto,
|
SendStickerDto,
|
||||||
SendTextDto,
|
SendTextDto,
|
||||||
|
SendTemplateDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
|
|
||||||
@ -86,6 +87,11 @@ export class SendMessageController {
|
|||||||
return await this.waMonitor.waInstances[instanceName].listMessage(data);
|
return await this.waMonitor.waInstances[instanceName].listMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async sendTemplate({ instanceName }: InstanceDto, data: SendTemplateDto) {
|
||||||
|
logger.verbose('requested sendList from ' + instanceName + ' instance');
|
||||||
|
return await this.waMonitor.waInstances[instanceName].templateMessage(data);
|
||||||
|
}
|
||||||
|
|
||||||
public async sendContact({ instanceName }: InstanceDto, data: SendContactDto) {
|
public async sendContact({ instanceName }: InstanceDto, data: SendContactDto) {
|
||||||
logger.verbose('requested sendContact from ' + instanceName + ' instance');
|
logger.verbose('requested sendContact from ' + instanceName + ' instance');
|
||||||
return await this.waMonitor.waInstances[instanceName].contactMessage(data);
|
return await this.waMonitor.waInstances[instanceName].contactMessage(data);
|
||||||
|
@ -5,11 +5,19 @@ import { BadRequestException } from '../../exceptions';
|
|||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { WebhookDto } from '../dto/webhook.dto';
|
import { WebhookDto } from '../dto/webhook.dto';
|
||||||
import { WebhookService } from '../services/webhook.service';
|
import { WebhookService } from '../services/webhook.service';
|
||||||
|
import { ConfigService } from '../../config/env.config';
|
||||||
|
import { RedisCache } from '../../libs/redis.client';
|
||||||
|
import EventEmitter2 from 'eventemitter2';
|
||||||
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
|
|
||||||
const logger = new Logger('WebhookController');
|
const logger = new Logger('WebhookController');
|
||||||
|
|
||||||
export class WebhookController {
|
export class WebhookController {
|
||||||
constructor(private readonly webhookService: WebhookService) {}
|
constructor(
|
||||||
|
private readonly webhookService: WebhookService,
|
||||||
|
private readonly waMonitor: WAMonitoringService,
|
||||||
|
) {}
|
||||||
|
|
||||||
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
|
||||||
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
|
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
|
||||||
@ -61,4 +69,9 @@ export class WebhookController {
|
|||||||
logger.verbose('requested findWebhook from ' + instance.instanceName + ' instance');
|
logger.verbose('requested findWebhook from ' + instance.instanceName + ' instance');
|
||||||
return this.webhookService.find(instance);
|
return this.webhookService.find(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async receiveWebhook(instance: InstanceDto, data: any) {
|
||||||
|
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
|
||||||
|
return await this.waMonitor.waInstances[instance.instanceName].connectToWhatsapp(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,11 @@ export class NumberBusiness {
|
|||||||
message?: string;
|
message?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
website?: string[];
|
websites?: string[];
|
||||||
address?: string;
|
address?: string;
|
||||||
|
about?: string;
|
||||||
|
vertical?: string;
|
||||||
|
profilehandle?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProfileNameDto {
|
export class ProfileNameDto {
|
||||||
|
@ -3,6 +3,7 @@ export class InstanceDto {
|
|||||||
instanceId?: string;
|
instanceId?: string;
|
||||||
qrcode?: boolean;
|
qrcode?: boolean;
|
||||||
number?: string;
|
number?: string;
|
||||||
|
integration?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
webhook?: string;
|
webhook?: string;
|
||||||
webhook_by_events?: boolean;
|
webhook_by_events?: boolean;
|
||||||
|
@ -134,6 +134,15 @@ export class SendListDto extends Metadata {
|
|||||||
listMessage: ListMessage;
|
listMessage: ListMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TemplateMessage {
|
||||||
|
name: string;
|
||||||
|
language: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SendTemplateDto extends Metadata {
|
||||||
|
templateMessage: TemplateMessage;
|
||||||
|
}
|
||||||
|
|
||||||
export class ContactMessage {
|
export class ContactMessage {
|
||||||
fullName: string;
|
fullName: string;
|
||||||
wuid: string;
|
wuid: string;
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
profileStatusSchema,
|
profileStatusSchema,
|
||||||
readMessageSchema,
|
readMessageSchema,
|
||||||
whatsappNumberSchema,
|
whatsappNumberSchema,
|
||||||
|
profileBusinessSchema,
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import {
|
import {
|
||||||
@ -29,6 +30,7 @@ import {
|
|||||||
ReadMessageDto,
|
ReadMessageDto,
|
||||||
SendPresenceDto,
|
SendPresenceDto,
|
||||||
WhatsAppNumberDto,
|
WhatsAppNumberDto,
|
||||||
|
NumberBusiness,
|
||||||
} from '../dto/chat.dto';
|
} from '../dto/chat.dto';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { ContactQuery } from '../repository/contact.repository';
|
import { ContactQuery } from '../repository/contact.repository';
|
||||||
@ -213,6 +215,23 @@ export class ChatRouter extends RouterBroker {
|
|||||||
|
|
||||||
return res.status(HttpStatus.OK).json(response);
|
return res.status(HttpStatus.OK).json(response);
|
||||||
})
|
})
|
||||||
|
.post(this.routerPath('setWhatsappBusinessProfile'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in findStatusMessage');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
|
||||||
|
const response = await this.dataValidate<NumberBusiness>({
|
||||||
|
request: req,
|
||||||
|
schema: messageUpSchema,
|
||||||
|
ClassRef: NumberBusiness,
|
||||||
|
execute: (instance, data) => chatController.setWhatsappBusinessProfile(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
.get(this.routerPath('findChats'), ...guards, async (req, res) => {
|
.get(this.routerPath('findChats'), ...guards, async (req, res) => {
|
||||||
logger.verbose('request received in findChats');
|
logger.verbose('request received in findChats');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
@ -291,7 +310,7 @@ export class ChatRouter extends RouterBroker {
|
|||||||
|
|
||||||
const response = await this.dataValidate<ProfilePictureDto>({
|
const response = await this.dataValidate<ProfilePictureDto>({
|
||||||
request: req,
|
request: req,
|
||||||
schema: profilePictureSchema,
|
schema: profileBusinessSchema,
|
||||||
ClassRef: ProfilePictureDto,
|
ClassRef: ProfilePictureDto,
|
||||||
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
|
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
|
||||||
});
|
});
|
||||||
|
@ -53,7 +53,7 @@ router
|
|||||||
.use('/message', new MessageRouter(...guards).router)
|
.use('/message', new MessageRouter(...guards).router)
|
||||||
.use('/chat', new ChatRouter(...guards).router)
|
.use('/chat', new ChatRouter(...guards).router)
|
||||||
.use('/group', new GroupRouter(...guards).router)
|
.use('/group', new GroupRouter(...guards).router)
|
||||||
.use('/webhook', new WebhookRouter(...guards).router)
|
.use('/webhook', new WebhookRouter(configService, ...guards).router)
|
||||||
.use('/chatwoot', new ChatwootRouter(...guards).router)
|
.use('/chatwoot', new ChatwootRouter(...guards).router)
|
||||||
.use('/settings', new SettingsRouter(...guards).router)
|
.use('/settings', new SettingsRouter(...guards).router)
|
||||||
.use('/websocket', new WebsocketRouter(...guards).router)
|
.use('/websocket', new WebsocketRouter(...guards).router)
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
statusMessageSchema,
|
statusMessageSchema,
|
||||||
stickerMessageSchema,
|
stickerMessageSchema,
|
||||||
textMessageSchema,
|
textMessageSchema,
|
||||||
|
templateMessageSchema,
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
import { RouterBroker } from '../abstract/abstract.router';
|
import { RouterBroker } from '../abstract/abstract.router';
|
||||||
import {
|
import {
|
||||||
@ -27,6 +28,7 @@ import {
|
|||||||
SendStatusDto,
|
SendStatusDto,
|
||||||
SendStickerDto,
|
SendStickerDto,
|
||||||
SendTextDto,
|
SendTextDto,
|
||||||
|
SendTemplateDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { sendMessageController } from '../whatsapp.module';
|
import { sendMessageController } from '../whatsapp.module';
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
@ -133,6 +135,22 @@ export class MessageRouter extends RouterBroker {
|
|||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
})
|
})
|
||||||
|
.post(this.routerPath('sendTemplate'), ...guards, async (req, res) => {
|
||||||
|
logger.verbose('request received in sendTemplate');
|
||||||
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
const response = await this.dataValidate<SendTemplateDto>({
|
||||||
|
request: req,
|
||||||
|
schema: templateMessageSchema,
|
||||||
|
ClassRef: SendTemplateDto,
|
||||||
|
execute: (instance, data) => sendMessageController.sendTemplate(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
|
})
|
||||||
.post(this.routerPath('sendContact'), ...guards, async (req, res) => {
|
.post(this.routerPath('sendContact'), ...guards, async (req, res) => {
|
||||||
logger.verbose('request received in sendContact');
|
logger.verbose('request received in sendContact');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
|
@ -7,11 +7,12 @@ import { InstanceDto } from '../dto/instance.dto';
|
|||||||
import { WebhookDto } from '../dto/webhook.dto';
|
import { WebhookDto } from '../dto/webhook.dto';
|
||||||
import { webhookController } from '../whatsapp.module';
|
import { webhookController } from '../whatsapp.module';
|
||||||
import { HttpStatus } from './index.router';
|
import { HttpStatus } from './index.router';
|
||||||
|
import { WABussiness, ConfigService } from '../../config/env.config';
|
||||||
|
|
||||||
const logger = new Logger('WebhookRouter');
|
const logger = new Logger('WebhookRouter');
|
||||||
|
|
||||||
export class WebhookRouter extends RouterBroker {
|
export class WebhookRouter extends RouterBroker {
|
||||||
constructor(...guards: RequestHandler[]) {
|
constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) {
|
||||||
super();
|
super();
|
||||||
this.router
|
this.router
|
||||||
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
.post(this.routerPath('set'), ...guards, async (req, res) => {
|
||||||
@ -30,6 +31,32 @@ export class WebhookRouter extends RouterBroker {
|
|||||||
|
|
||||||
res.status(HttpStatus.CREATED).json(response);
|
res.status(HttpStatus.CREATED).json(response);
|
||||||
})
|
})
|
||||||
|
.post(this.routerPath('whatsapp'), async (req, res) => {
|
||||||
|
logger.verbose('request received in findChatwoot');
|
||||||
|
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: instanceNameSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance, data) => webhookController.receiveWebhook(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
|
})
|
||||||
|
.get(this.routerPath('whatsapp'), async (req, res) => {
|
||||||
|
logger.verbose('request received in webhook');
|
||||||
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
if (req.query['hub.verify_token'] === this.configService.get<WABussiness>('WABUSSINESS').ACESS_TOKEN)
|
||||||
|
res.send(req.query['hub.challenge']);
|
||||||
|
else
|
||||||
|
res.send('Error, wrong validation token');
|
||||||
|
logger.verbose('Error, wrong validation token');
|
||||||
|
})
|
||||||
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
.get(this.routerPath('find'), ...guards, async (req, res) => {
|
||||||
logger.verbose('request received in findWebhook');
|
logger.verbose('request received in findWebhook');
|
||||||
logger.verbose('request body: ');
|
logger.verbose('request body: ');
|
||||||
|
@ -6,12 +6,12 @@ import Jimp from 'jimp';
|
|||||||
import mimeTypes from 'mime-types';
|
import mimeTypes from 'mime-types';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import { ConfigService, HttpServer } from '../../config/env.config';
|
import { ConfigService, HttpServer, WABussiness } 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';
|
||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
|
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto, SendTemplateDto } from '../dto/sendMessage.dto';
|
||||||
import { MessageRaw } from '../models';
|
import { MessageRaw } from '../models';
|
||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
import { Events } from '../types/wa.types';
|
import { Events } from '../types/wa.types';
|
||||||
@ -457,7 +457,7 @@ export class ChatwootService {
|
|||||||
if (!findParticipant.name || findParticipant.name === chatId) {
|
if (!findParticipant.name || findParticipant.name === chatId) {
|
||||||
await this.updateContact(instance, findParticipant.id, {
|
await this.updateContact(instance, findParticipant.id, {
|
||||||
name: body.pushName,
|
name: body.pushName,
|
||||||
avatar_url: picture_url.profilePictureUrl || null,
|
avatar_url: picture_url?.profilePictureUrl || null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -467,7 +467,7 @@ export class ChatwootService {
|
|||||||
filterInbox.id,
|
filterInbox.id,
|
||||||
false,
|
false,
|
||||||
body.pushName,
|
body.pushName,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url?.profilePictureUrl || null,
|
||||||
body.key.participant,
|
body.key.participant,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -483,7 +483,7 @@ export class ChatwootService {
|
|||||||
if (body.key.fromMe) {
|
if (body.key.fromMe) {
|
||||||
if (findContact) {
|
if (findContact) {
|
||||||
contact = await this.updateContact(instance, findContact.id, {
|
contact = await this.updateContact(instance, findContact.id, {
|
||||||
avatar_url: picture_url.profilePictureUrl || null,
|
avatar_url: picture_url?.profilePictureUrl || null,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const jid = isGroup ? null : body.key.remoteJid;
|
const jid = isGroup ? null : body.key.remoteJid;
|
||||||
@ -493,7 +493,7 @@ export class ChatwootService {
|
|||||||
filterInbox.id,
|
filterInbox.id,
|
||||||
isGroup,
|
isGroup,
|
||||||
nameContact,
|
nameContact,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url?.profilePictureUrl || null,
|
||||||
jid,
|
jid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -502,11 +502,11 @@ export class ChatwootService {
|
|||||||
if (!findContact.name || findContact.name === chatId) {
|
if (!findContact.name || findContact.name === chatId) {
|
||||||
contact = await this.updateContact(instance, findContact.id, {
|
contact = await this.updateContact(instance, findContact.id, {
|
||||||
name: nameContact,
|
name: nameContact,
|
||||||
avatar_url: picture_url.profilePictureUrl || null,
|
avatar_url: picture_url?.profilePictureUrl || null,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
contact = await this.updateContact(instance, findContact.id, {
|
contact = await this.updateContact(instance, findContact.id, {
|
||||||
avatar_url: picture_url.profilePictureUrl || null,
|
avatar_url: picture_url?.profilePictureUrl || null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
@ -520,7 +520,7 @@ export class ChatwootService {
|
|||||||
filterInbox.id,
|
filterInbox.id,
|
||||||
isGroup,
|
isGroup,
|
||||||
nameContact,
|
nameContact,
|
||||||
picture_url.profilePictureUrl || null,
|
picture_url?.profilePictureUrl || null,
|
||||||
jid,
|
jid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -785,9 +785,9 @@ export class ChatwootService {
|
|||||||
const replyToIds = await this.getReplyToIds(messageBody, instance);
|
const replyToIds = await this.getReplyToIds(messageBody, instance);
|
||||||
|
|
||||||
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
|
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
|
||||||
data.append('content_attributes', {
|
data.append('content_attributes',
|
||||||
...replyToIds,
|
JSON.stringify(replyToIds),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1023,10 +1023,10 @@ export class ChatwootService {
|
|||||||
// Chatwoot to Whatsapp
|
// Chatwoot to Whatsapp
|
||||||
const messageReceived = body.content
|
const messageReceived = body.content
|
||||||
? body.content
|
? body.content
|
||||||
.replaceAll(/(?<!\*)\*((?!\s)([^\n*]+?)(?<!\s))\*(?!\*)/g, '_$1_') // Substitui * por _
|
.replaceAll(/(?<!\*)\*((?!\s)([^\n*]+?)(?<!\s))\*(?!\*)/g, '_$1_') // Substitui * por _
|
||||||
.replaceAll(/\*{2}((?!\s)([^\n*]+?)(?<!\s))\*{2}/g, '*$1*') // Substitui ** por *
|
.replaceAll(/\*{2}((?!\s)([^\n*]+?)(?<!\s))\*{2}/g, '*$1*') // Substitui ** por *
|
||||||
.replaceAll(/~{2}((?!\s)([^\n*]+?)(?<!\s))~{2}/g, '~$1~') // Substitui ~~ por ~
|
.replaceAll(/~{2}((?!\s)([^\n*]+?)(?<!\s))~{2}/g, '~$1~') // Substitui ~~ por ~
|
||||||
.replaceAll(/(?<!`)`((?!\s)([^`*]+?)(?<!\s))`(?!`)/g, '```$1```') // Substitui ` por ```
|
.replaceAll(/(?<!`)`((?!\s)([^`*]+?)(?<!\s))`(?!`)/g, '```$1```') // Substitui ` por ```
|
||||||
: body.content;
|
: body.content;
|
||||||
|
|
||||||
const senderName = body?.sender?.available_name || body?.sender?.name;
|
const senderName = body?.sender?.available_name || body?.sender?.name;
|
||||||
@ -1044,7 +1044,7 @@ export class ChatwootService {
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
});
|
});
|
||||||
if (message.length && message[0].key?.id) {
|
if (message.length && message[0].key?.id) {
|
||||||
await waInstance?.client.sendMessage(message[0].key.remoteJid, { delete: message[0].key });
|
await waInstance?.client?.sendMessage(message[0].key.remoteJid, { delete: message[0].key });
|
||||||
}
|
}
|
||||||
return { message: 'bot' };
|
return { message: 'bot' };
|
||||||
}
|
}
|
||||||
@ -1123,6 +1123,36 @@ export class ChatwootService {
|
|||||||
|
|
||||||
this.logger.verbose('Format message to send');
|
this.logger.verbose('Format message to send');
|
||||||
let formatText: string;
|
let formatText: string;
|
||||||
|
const regex = /^▶️.*◀️$/;
|
||||||
|
if (regex.test(messageReceived)) {
|
||||||
|
const data: SendTemplateDto = {
|
||||||
|
number: chatId,
|
||||||
|
templateMessage: {
|
||||||
|
name: messageReceived.replace(/[^\x20-\x7E]/g, ''),
|
||||||
|
language: this.configService.get<WABussiness>('WABUSSINESS').LANGUAGE,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
quoted: await this.getQuotedMessage(body, instance),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const messageSent = await waInstance?.templateMessage(data, true);
|
||||||
|
this.updateChatwootMessageId(
|
||||||
|
{
|
||||||
|
...messageSent,
|
||||||
|
owner: instance.instanceName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
messageId: body.id,
|
||||||
|
inboxId: body.inbox?.id,
|
||||||
|
conversationId: body.conversation?.id,
|
||||||
|
},
|
||||||
|
instance,
|
||||||
|
);
|
||||||
|
return
|
||||||
|
}
|
||||||
if (senderName === null || senderName === undefined) {
|
if (senderName === null || senderName === undefined) {
|
||||||
formatText = messageReceived;
|
formatText = messageReceived;
|
||||||
} else {
|
} else {
|
||||||
@ -1137,7 +1167,7 @@ export class ChatwootService {
|
|||||||
|
|
||||||
for (const message of body.conversation.messages) {
|
for (const message of body.conversation.messages) {
|
||||||
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');
|
||||||
for (const attachment of message.attachments) {
|
for (const attachment of message.attachments) {
|
||||||
this.logger.verbose('send media to whatsapp');
|
this.logger.verbose('send media to whatsapp');
|
||||||
@ -1513,9 +1543,9 @@ export class ChatwootService {
|
|||||||
const originalMessage = await this.getConversationMessage(body.message);
|
const originalMessage = await this.getConversationMessage(body.message);
|
||||||
const bodyMessage = originalMessage
|
const bodyMessage = originalMessage
|
||||||
? originalMessage
|
? originalMessage
|
||||||
.replaceAll(/\*((?!\s)([^\n*]+?)(?<!\s))\*/g, '**$1**')
|
.replaceAll(/\*((?!\s)([^\n*]+?)(?<!\s))\*/g, '**$1**')
|
||||||
.replaceAll(/_((?!\s)([^\n_]+?)(?<!\s))_/g, '*$1*')
|
.replaceAll(/_((?!\s)([^\n_]+?)(?<!\s))_/g, '*$1*')
|
||||||
.replaceAll(/~((?!\s)([^\n~]+?)(?<!\s))~/g, '~~$1~~')
|
.replaceAll(/~((?!\s)([^\n~]+?)(?<!\s))~/g, '~~$1~~')
|
||||||
: originalMessage;
|
: originalMessage;
|
||||||
|
|
||||||
this.logger.verbose('body message: ' + bodyMessage);
|
this.logger.verbose('body message: ' + bodyMessage);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import EventEmitter2 from 'eventemitter2';
|
import EventEmitter2 from 'eventemitter2';
|
||||||
import { opendirSync, readdirSync, rmSync } from 'fs';
|
import { opendirSync, readdirSync, rmSync, existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||||
import { Db } from 'mongodb';
|
import { Db } from 'mongodb';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
@ -27,6 +27,7 @@ import {
|
|||||||
} from '../models';
|
} from '../models';
|
||||||
import { RepositoryBroker } from '../repository/repository.manager';
|
import { RepositoryBroker } from '../repository/repository.manager';
|
||||||
import { WAStartupService } from './whatsapp.service';
|
import { WAStartupService } from './whatsapp.service';
|
||||||
|
import { WAStartupClass } from '../whatsapp.module';
|
||||||
|
|
||||||
export class WAMonitoringService {
|
export class WAMonitoringService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -359,13 +360,21 @@ export class WAMonitoringService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async setInstance(name: string) {
|
private async setInstance(name: string) {
|
||||||
const instance = new WAStartupService(this.configService, this.eventEmitter, this.repository, this.cache);
|
const path = join(INSTANCE_DIR, name);
|
||||||
|
let values: any;
|
||||||
|
if(this.db.ENABLED )
|
||||||
|
values = await this.dbInstance.collection(name).findOne({ _id: 'integration' })
|
||||||
|
else
|
||||||
|
values = JSON.parse(readFileSync(path + '/integration.json', 'utf8'));
|
||||||
|
const instance = new WAStartupClass[values.integration]
|
||||||
|
(this.configService, this.eventEmitter, this.repository, this.cache);
|
||||||
instance.instanceName = name;
|
instance.instanceName = name;
|
||||||
|
instance.instanceNumber = values.number;
|
||||||
|
instance.instanceToken = values.token;
|
||||||
|
this.waInstances[name] = instance;
|
||||||
this.logger.verbose('Instance loaded: ' + name);
|
this.logger.verbose('Instance loaded: ' + name);
|
||||||
await instance.connectToWhatsapp();
|
await instance.connectToWhatsapp();
|
||||||
this.logger.verbose('connectToWhatsapp: ' + name);
|
this.logger.verbose('connectToWhatsapp: ' + name);
|
||||||
|
|
||||||
this.waInstances[name] = instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadInstancesFromRedis() {
|
private async loadInstancesFromRedis() {
|
||||||
@ -473,4 +482,27 @@ export class WAMonitoringService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async saveInstance(data: any) {
|
||||||
|
this.logger.verbose('Save instance');
|
||||||
|
|
||||||
|
try {
|
||||||
|
let msgParsed = JSON.parse(JSON.stringify(data));
|
||||||
|
if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) {
|
||||||
|
await this.repository.dbServer.connect();
|
||||||
|
await this.dbInstance.collection(data.instanceName).replaceOne({ _id: 'integration' }, msgParsed,
|
||||||
|
{
|
||||||
|
upsert: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const path = join(INSTANCE_DIR, data.instanceName)
|
||||||
|
if (!existsSync(path))
|
||||||
|
mkdirSync(path, { recursive: true });
|
||||||
|
writeFileSync(path + '/integration.json', JSON.stringify(msgParsed));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import { Logger } from '../../config/logger.config';
|
|||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
import { Session, TypebotDto } from '../dto/typebot.dto';
|
import { Session, TypebotDto } from '../dto/typebot.dto';
|
||||||
import { MessageRaw } from '../models';
|
import { MessageRaw } from '../models';
|
||||||
import { Events } from '../types/wa.types';
|
import { Events, Integration } from '../types/wa.types';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { WAMonitoringService } from './monitor.service';
|
||||||
|
|
||||||
export class TypebotService {
|
export class TypebotService {
|
||||||
@ -405,6 +405,7 @@ export class TypebotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function processMessages(instance, messages, input, clientSideActions, eventEmitter) {
|
async function processMessages(instance, messages, input, clientSideActions, eventEmitter) {
|
||||||
|
let qtdMessages = 0, buttonText = '';
|
||||||
for (const message of messages) {
|
for (const message of messages) {
|
||||||
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
|
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
|
||||||
|
|
||||||
@ -463,20 +464,24 @@ export class TypebotService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formattedText = formattedText.replace(/\n$/, '');
|
formattedText = formattedText.replace(/\n$/, '');
|
||||||
|
qtdMessages++;
|
||||||
await instance.textMessage({
|
if (instance?.constructor.name == Integration.WABussinessService &&
|
||||||
number: remoteJid.split('@')[0],
|
input?.type === 'choice input' && messages.length == qtdMessages) {
|
||||||
options: {
|
buttonText = formattedText;
|
||||||
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
} else {
|
||||||
presence: 'composing',
|
await instance.textMessage({
|
||||||
linkPreview: linkPreview,
|
number: remoteJid.split('@')[0],
|
||||||
},
|
options: {
|
||||||
textMessage: {
|
delay: wait ? wait * 1000 : instance.localTypebot.delay_message || 1000,
|
||||||
text: formattedText,
|
presence: 'composing',
|
||||||
},
|
linkPreview: linkPreview,
|
||||||
});
|
},
|
||||||
|
textMessage: {
|
||||||
|
text: formattedText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.type === 'image') {
|
if (message.type === 'image') {
|
||||||
await instance.mediaMessage({
|
await instance.mediaMessage({
|
||||||
number: remoteJid.split('@')[0],
|
number: remoteJid.split('@')[0],
|
||||||
@ -522,27 +527,49 @@ export class TypebotService {
|
|||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
if (input.type === 'choice input') {
|
if (input.type === 'choice input') {
|
||||||
let formattedText = '';
|
|
||||||
|
|
||||||
const items = input.items;
|
const items = input.items;
|
||||||
|
if (instance?.constructor.name == Integration.WABussinessService) {
|
||||||
|
let buttons = [];
|
||||||
|
for (const item of items) {
|
||||||
|
buttons.push({
|
||||||
|
buttonId: item.id,
|
||||||
|
buttonText: item.content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await instance.buttonMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
linkPreview: false,
|
||||||
|
},
|
||||||
|
buttonMessage: {
|
||||||
|
title: buttonText,
|
||||||
|
buttons,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
for (const item of items) {
|
} else {
|
||||||
formattedText += `▶️ ${item.content}\n`;
|
let formattedText = '';
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
formattedText += `▶️ ${item.content}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedText = formattedText.replace(/\n$/, '');
|
||||||
|
|
||||||
|
await instance.textMessage({
|
||||||
|
number: remoteJid.split('@')[0],
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
linkPreview: false,
|
||||||
|
},
|
||||||
|
textMessage: {
|
||||||
|
text: formattedText,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formattedText = formattedText.replace(/\n$/, '');
|
|
||||||
|
|
||||||
await instance.textMessage({
|
|
||||||
number: remoteJid.split('@')[0],
|
|
||||||
options: {
|
|
||||||
delay: 1200,
|
|
||||||
presence: 'composing',
|
|
||||||
linkPreview: false,
|
|
||||||
},
|
|
||||||
textMessage: {
|
|
||||||
text: formattedText,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eventEmitter.emit('typebot:end', {
|
eventEmitter.emit('typebot:end', {
|
||||||
|
2813
src/whatsapp/services/whatsapp.baileys.service.ts
Normal file
2813
src/whatsapp/services/whatsapp.baileys.service.ts
Normal file
File diff suppressed because it is too large
Load Diff
1098
src/whatsapp/services/whatsapp.business.service.ts
Normal file
1098
src/whatsapp/services/whatsapp.business.service.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -45,6 +45,9 @@ export declare namespace wa {
|
|||||||
wuid?: string;
|
wuid?: string;
|
||||||
profileName?: string;
|
profileName?: string;
|
||||||
profilePictureUrl?: string;
|
profilePictureUrl?: string;
|
||||||
|
integration?: string;
|
||||||
|
number?: string;
|
||||||
|
token?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LocalWebHook = {
|
export type LocalWebHook = {
|
||||||
@ -139,3 +142,9 @@ export const MessageSubtype = [
|
|||||||
'viewOnceMessage',
|
'viewOnceMessage',
|
||||||
'viewOnceMessageV2',
|
'viewOnceMessageV2',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export enum Integration {
|
||||||
|
WHATSAPP_BUSINESS='WHATSAPP-BUSINESS',
|
||||||
|
WHATSAPP_BAILEYS='WHATSAPP-BAILEYS',
|
||||||
|
WABussinessService = 'WABussinessService',
|
||||||
|
}
|
||||||
|
@ -58,6 +58,11 @@ import { SqsService } from './services/sqs.service';
|
|||||||
import { TypebotService } from './services/typebot.service';
|
import { TypebotService } from './services/typebot.service';
|
||||||
import { WebhookService } from './services/webhook.service';
|
import { WebhookService } from './services/webhook.service';
|
||||||
import { WebsocketService } from './services/websocket.service';
|
import { WebsocketService } from './services/websocket.service';
|
||||||
|
import { WABaileysService } from './services/whatsapp.baileys.service';
|
||||||
|
import { WAStartupService } from './services/whatsapp.service';
|
||||||
|
import { WABussinessService } from './services/whatsapp.business.service';
|
||||||
|
import { ConfigService, } from '../config/env.config';
|
||||||
|
import EventEmitter2 from 'eventemitter2';
|
||||||
|
|
||||||
const logger = new Logger('WA MODULE');
|
const logger = new Logger('WA MODULE');
|
||||||
|
|
||||||
@ -107,7 +112,7 @@ export const typebotController = new TypebotController(typebotService);
|
|||||||
|
|
||||||
const webhookService = new WebhookService(waMonitor);
|
const webhookService = new WebhookService(waMonitor);
|
||||||
|
|
||||||
export const webhookController = new WebhookController(webhookService);
|
export const webhookController = new WebhookController(webhookService, waMonitor);
|
||||||
|
|
||||||
const websocketService = new WebsocketService(waMonitor);
|
const websocketService = new WebsocketService(waMonitor);
|
||||||
|
|
||||||
@ -157,4 +162,17 @@ export const sendMessageController = new SendMessageController(waMonitor);
|
|||||||
export const chatController = new ChatController(waMonitor);
|
export const chatController = new ChatController(waMonitor);
|
||||||
export const groupController = new GroupController(waMonitor);
|
export const groupController = new GroupController(waMonitor);
|
||||||
|
|
||||||
|
|
||||||
|
export const WAStartupClass: {
|
||||||
|
[key: string]: new (
|
||||||
|
configService: ConfigService,
|
||||||
|
eventEmitter: EventEmitter2,
|
||||||
|
repository: RepositoryBroker,
|
||||||
|
cache: RedisCache,
|
||||||
|
) => WAStartupService
|
||||||
|
} = {
|
||||||
|
'WHATSAPP-BUSINESS': WABussinessService,
|
||||||
|
'WHATSAPP-BAILEYS': WABaileysService,
|
||||||
|
};
|
||||||
|
|
||||||
logger.info('Module - ON');
|
logger.info('Module - ON');
|
||||||
|
Loading…
Reference in New Issue
Block a user