added: Integration with whatsapp business api

This commit is contained in:
microprocessgit 2024-01-16 16:19:30 -03:00
parent 1a2546c52b
commit 1686ef58cf
23 changed files with 4406 additions and 2871 deletions

View File

@ -46,7 +46,7 @@
"@figuro/chatwoot-sdk": "^1.1.16",
"@hapi/boom": "^10.0.1",
"@sentry/node": "^7.59.2",
"@whiskeysockets/baileys": "^6.5.0",
"@whiskeysockets/baileys": "github:PurpShell/Baileys#combined",
"amqplib": "^0.10.3",
"aws-sdk": "^2.1499.0",
"axios": "^1.3.5",

View File

@ -120,6 +120,7 @@ export type EventsWebhook = {
export type ApiKey = { KEY: string };
export type Jwt = { EXPIRIN_IN: number; SECRET: string };
export type WABussiness = { ACESS_TOKEN: string, URL: string, VERSION: string, LANGUAGE: string };
export type Auth = {
API_KEY: ApiKey;
@ -161,6 +162,7 @@ export interface Env {
TYPEBOT: Typebot;
AUTHENTICATION: Auth;
PRODUCTION?: Production;
WABUSSINESS: WABussiness;
}
export type Key = keyof Env;
@ -337,6 +339,12 @@ export class ConfigService {
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
},
};
}
}

View File

@ -155,7 +155,7 @@ export class Logger {
function salvarLog(env: any, log: string): void {
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';
try {
if (fs.existsSync(file)) {
@ -176,9 +176,9 @@ function excluirArquivosAntigos(path: string, diasLimite: number): void {
data.setDate(data.getDate() - diasLimite);
fs.readdirSync(path).forEach((nomeArquivo) => {
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);
console.log(`Arquivo ${nomeArquivo} excluído.`);
}

View File

@ -389,6 +389,25 @@ export const listMessageSchema: JSONSchema7 = {
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 = {
$id: v4(),
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 = {
type: 'object',
properties: {

View File

@ -11,6 +11,7 @@ import {
ReadMessageDto,
SendPresenceDto,
WhatsAppNumberDto,
NumberBusiness,
} from '../dto/chat.dto';
import { InstanceDto } from '../dto/instance.dto';
import { ContactQuery } from '../repository/contact.repository';
@ -117,4 +118,9 @@ export class ChatController {
logger.verbose('requested removeProfilePicture from ' + instanceName + ' instance');
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);
}
}

View File

@ -3,7 +3,7 @@ import { isURL } from 'class-validator';
import EventEmitter2 from 'eventemitter2';
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 { BadRequestException, InternalServerErrorException } from '../../exceptions';
import { RedisCache } from '../../libs/redis.client';
@ -19,8 +19,8 @@ import { SqsService } from '../services/sqs.service';
import { TypebotService } from '../services/typebot.service';
import { WebhookService } from '../services/webhook.service';
import { WebsocketService } from '../services/websocket.service';
import { WAStartupService } from '../services/whatsapp.service';
import { Events, wa } from '../types/wa.types';
import { Events, wa, Integration } from '../types/wa.types';
import { WAStartupClass } from '../whatsapp.module';
export class InstanceController {
constructor(
@ -50,6 +50,7 @@ export class InstanceController {
events,
qrcode,
number,
integration,
token,
chatwoot_account_id,
chatwoot_token,
@ -85,9 +86,10 @@ export class InstanceController {
await this.authService.checkDuplicateToken(token);
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.instanceNumber = number;
instance.instanceToken = token;
const instanceId = v4();
instance.sendDataWebhook(Events.INSTANCE_CREATE, {
@ -359,20 +361,30 @@ export class InstanceController {
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) {
let getQrcode: wa.QrCode;
await this.waMonitor.saveInstance({integration, instanceName, token, number});
if (qrcode) {
this.logger.verbose('creating qrcode');
await instance.connectToWhatsapp(number);
await delay(5000);
getQrcode = instance.qrCode;
}
const result = {
instance: {
instanceName: instance.instanceName,
instanceId: instanceId,
integration: integration,
status: 'created',
},
hash,
@ -405,6 +417,7 @@ export class InstanceController {
listening_from_me: typebot_listening_from_me,
},
settings,
webhook_url: webhook_url,
qrcode: getQrcode,
proxy,
};
@ -423,6 +436,10 @@ export class InstanceController {
throw new BadRequestException('token is required');
}
if (!integration) {
throw new BadRequestException('integration is required');
}
if (!chatwoot_url) {
throw new BadRequestException('url is required');
}
@ -443,8 +460,6 @@ export class InstanceController {
throw new BadRequestException('conversation_pending is required');
}
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
try {
this.chatwootService.create(instance, {
enabled: true,
@ -617,7 +632,7 @@ export class InstanceController {
await this.waMonitor.waInstances[instanceName]?.client?.logout('Log out 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' } };
} catch (error) {

View File

@ -15,6 +15,7 @@ import {
SendStatusDto,
SendStickerDto,
SendTextDto,
SendTemplateDto,
} from '../dto/sendMessage.dto';
import { WAMonitoringService } from '../services/monitor.service';
@ -86,6 +87,11 @@ export class SendMessageController {
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) {
logger.verbose('requested sendContact from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].contactMessage(data);

View File

@ -5,11 +5,19 @@ import { BadRequestException } from '../../exceptions';
import { InstanceDto } from '../dto/instance.dto';
import { WebhookDto } from '../dto/webhook.dto';
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');
export class WebhookController {
constructor(private readonly webhookService: WebhookService) {}
constructor(
private readonly webhookService: WebhookService,
private readonly waMonitor: WAMonitoringService,
) {}
public async createWebhook(instance: InstanceDto, data: WebhookDto) {
logger.verbose('requested createWebhook from ' + instance.instanceName + ' instance');
@ -61,4 +69,9 @@ export class WebhookController {
logger.verbose('requested findWebhook from ' + instance.instanceName + ' 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);
}
}

View File

@ -26,8 +26,11 @@ export class NumberBusiness {
message?: string;
description?: string;
email?: string;
website?: string[];
websites?: string[];
address?: string;
about?: string;
vertical?: string;
profilehandle?: string;
}
export class ProfileNameDto {

View File

@ -3,6 +3,7 @@ export class InstanceDto {
instanceId?: string;
qrcode?: boolean;
number?: string;
integration?: string;
token?: string;
webhook?: string;
webhook_by_events?: boolean;

View File

@ -134,6 +134,15 @@ export class SendListDto extends Metadata {
listMessage: ListMessage;
}
export class TemplateMessage {
name: string;
language: string;
}
export class SendTemplateDto extends Metadata {
templateMessage: TemplateMessage;
}
export class ContactMessage {
fullName: string;
wuid: string;

View File

@ -15,6 +15,7 @@ import {
profileStatusSchema,
readMessageSchema,
whatsappNumberSchema,
profileBusinessSchema,
} from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import {
@ -29,6 +30,7 @@ import {
ReadMessageDto,
SendPresenceDto,
WhatsAppNumberDto,
NumberBusiness,
} from '../dto/chat.dto';
import { InstanceDto } from '../dto/instance.dto';
import { ContactQuery } from '../repository/contact.repository';
@ -213,6 +215,23 @@ export class ChatRouter extends RouterBroker {
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) => {
logger.verbose('request received in findChats');
logger.verbose('request body: ');
@ -291,7 +310,7 @@ export class ChatRouter extends RouterBroker {
const response = await this.dataValidate<ProfilePictureDto>({
request: req,
schema: profilePictureSchema,
schema: profileBusinessSchema,
ClassRef: ProfilePictureDto,
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
});

View File

@ -53,7 +53,7 @@ router
.use('/message', new MessageRouter(...guards).router)
.use('/chat', new ChatRouter(...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('/settings', new SettingsRouter(...guards).router)
.use('/websocket', new WebsocketRouter(...guards).router)

View File

@ -13,6 +13,7 @@ import {
statusMessageSchema,
stickerMessageSchema,
textMessageSchema,
templateMessageSchema,
} from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router';
import {
@ -27,6 +28,7 @@ import {
SendStatusDto,
SendStickerDto,
SendTextDto,
SendTemplateDto,
} from '../dto/sendMessage.dto';
import { sendMessageController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
@ -133,6 +135,22 @@ export class MessageRouter extends RouterBroker {
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) => {
logger.verbose('request received in sendContact');
logger.verbose('request body: ');

View File

@ -7,11 +7,12 @@ import { InstanceDto } from '../dto/instance.dto';
import { WebhookDto } from '../dto/webhook.dto';
import { webhookController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
import { WABussiness, ConfigService } from '../../config/env.config';
const logger = new Logger('WebhookRouter');
export class WebhookRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) {
constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) {
super();
this.router
.post(this.routerPath('set'), ...guards, async (req, res) => {
@ -30,6 +31,32 @@ export class WebhookRouter extends RouterBroker {
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) => {
logger.verbose('request received in findWebhook');
logger.verbose('request body: ');

View File

@ -6,12 +6,12 @@ import Jimp from 'jimp';
import mimeTypes from 'mime-types';
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 { ROOT_DIR } from '../../config/path.config';
import { ChatwootDto } from '../dto/chatwoot.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 { RepositoryBroker } from '../repository/repository.manager';
import { Events } from '../types/wa.types';
@ -457,7 +457,7 @@ export class ChatwootService {
if (!findParticipant.name || findParticipant.name === chatId) {
await this.updateContact(instance, findParticipant.id, {
name: body.pushName,
avatar_url: picture_url.profilePictureUrl || null,
avatar_url: picture_url?.profilePictureUrl || null,
});
}
} else {
@ -467,7 +467,7 @@ export class ChatwootService {
filterInbox.id,
false,
body.pushName,
picture_url.profilePictureUrl || null,
picture_url?.profilePictureUrl || null,
body.key.participant,
);
}
@ -483,7 +483,7 @@ export class ChatwootService {
if (body.key.fromMe) {
if (findContact) {
contact = await this.updateContact(instance, findContact.id, {
avatar_url: picture_url.profilePictureUrl || null,
avatar_url: picture_url?.profilePictureUrl || null,
});
} else {
const jid = isGroup ? null : body.key.remoteJid;
@ -493,7 +493,7 @@ export class ChatwootService {
filterInbox.id,
isGroup,
nameContact,
picture_url.profilePictureUrl || null,
picture_url?.profilePictureUrl || null,
jid,
);
}
@ -502,11 +502,11 @@ export class ChatwootService {
if (!findContact.name || findContact.name === chatId) {
contact = await this.updateContact(instance, findContact.id, {
name: nameContact,
avatar_url: picture_url.profilePictureUrl || null,
avatar_url: picture_url?.profilePictureUrl || null,
});
} else {
contact = await this.updateContact(instance, findContact.id, {
avatar_url: picture_url.profilePictureUrl || null,
avatar_url: picture_url?.profilePictureUrl || null,
});
}
if (!contact) {
@ -520,7 +520,7 @@ export class ChatwootService {
filterInbox.id,
isGroup,
nameContact,
picture_url.profilePictureUrl || null,
picture_url?.profilePictureUrl || null,
jid,
);
}
@ -785,9 +785,9 @@ export class ChatwootService {
const replyToIds = await this.getReplyToIds(messageBody, instance);
if (replyToIds.in_reply_to || replyToIds.in_reply_to_external_id) {
data.append('content_attributes', {
...replyToIds,
});
data.append('content_attributes',
JSON.stringify(replyToIds),
);
}
}
@ -1044,7 +1044,7 @@ export class ChatwootService {
limit: 1,
});
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' };
}
@ -1123,6 +1123,36 @@ export class ChatwootService {
this.logger.verbose('Format message to send');
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) {
formatText = messageReceived;
} else {
@ -1137,7 +1167,7 @@ export class ChatwootService {
for (const message of body.conversation.messages) {
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');
for (const attachment of message.attachments) {
this.logger.verbose('send media to whatsapp');

View File

@ -1,6 +1,6 @@
import { execSync } from 'child_process';
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 { join } from 'path';
@ -27,6 +27,7 @@ import {
} from '../models';
import { RepositoryBroker } from '../repository/repository.manager';
import { WAStartupService } from './whatsapp.service';
import { WAStartupClass } from '../whatsapp.module';
export class WAMonitoringService {
constructor(
@ -359,13 +360,21 @@ export class WAMonitoringService {
}
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.instanceNumber = values.number;
instance.instanceToken = values.token;
this.waInstances[name] = instance;
this.logger.verbose('Instance loaded: ' + name);
await instance.connectToWhatsapp();
this.logger.verbose('connectToWhatsapp: ' + name);
this.waInstances[name] = instance;
}
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);
}
}
}

View File

@ -6,7 +6,7 @@ import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { Session, TypebotDto } from '../dto/typebot.dto';
import { MessageRaw } from '../models';
import { Events } from '../types/wa.types';
import { Events, Integration } from '../types/wa.types';
import { WAMonitoringService } from './monitor.service';
export class TypebotService {
@ -405,6 +405,7 @@ export class TypebotService {
}
async function processMessages(instance, messages, input, clientSideActions, eventEmitter) {
let qtdMessages = 0, buttonText = '';
for (const message of messages) {
const wait = findItemAndGetSecondsToWait(clientSideActions, message.id);
@ -463,7 +464,11 @@ export class TypebotService {
}
formattedText = formattedText.replace(/\n$/, '');
qtdMessages++;
if (instance?.constructor.name == Integration.WABussinessService &&
input?.type === 'choice input' && messages.length == qtdMessages) {
buttonText = formattedText;
} else {
await instance.textMessage({
number: remoteJid.split('@')[0],
options: {
@ -476,7 +481,7 @@ export class TypebotService {
},
});
}
}
if (message.type === 'image') {
await instance.mediaMessage({
number: remoteJid.split('@')[0],
@ -522,9 +527,30 @@ export class TypebotService {
if (input) {
if (input.type === 'choice input') {
let formattedText = '';
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,
},
});
} else {
let formattedText = '';
for (const item of items) {
formattedText += `▶️ ${item.content}\n`;
@ -544,6 +570,7 @@ export class TypebotService {
},
});
}
}
} else {
eventEmitter.emit('typebot:end', {
instance: instance,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,9 @@ export declare namespace wa {
wuid?: string;
profileName?: string;
profilePictureUrl?: string;
integration?: string;
number?: string;
token?: string;
};
export type LocalWebHook = {
@ -139,3 +142,9 @@ export const MessageSubtype = [
'viewOnceMessage',
'viewOnceMessageV2',
];
export enum Integration {
WHATSAPP_BUSINESS='WHATSAPP-BUSINESS',
WHATSAPP_BAILEYS='WHATSAPP-BAILEYS',
WABussinessService = 'WABussinessService',
}

View File

@ -58,6 +58,11 @@ import { SqsService } from './services/sqs.service';
import { TypebotService } from './services/typebot.service';
import { WebhookService } from './services/webhook.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');
@ -107,7 +112,7 @@ export const typebotController = new TypebotController(typebotService);
const webhookService = new WebhookService(waMonitor);
export const webhookController = new WebhookController(webhookService);
export const webhookController = new WebhookController(webhookService, waMonitor);
const websocketService = new WebsocketService(waMonitor);
@ -157,4 +162,17 @@ export const sendMessageController = new SendMessageController(waMonitor);
export const chatController = new ChatController(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');