Merge branch 'release/1.7.2'

This commit is contained in:
Davidson Gomes 2024-04-12 17:32:18 -03:00
commit 8caf3a0a7b
134 changed files with 1058 additions and 600 deletions

View File

@ -1,3 +1,20 @@
# 1.7.2 (2024-04-12 17:31)
### Feature
* Mobile connection via sms (test)
### Fixed
* Adjusts in redis
* Send global event in websocket
* Adjusts in proxy
* Fix audio encoding
* Fix conversation read on chatwoot version 3.7
* Fix when receiving/sending messages from whatsapp desktop with ephemeral messages enabled
* Changed returned sessions on typebot status change
* Reorganization of files and folders
# 1.7.1 (2024-04-03 10:19) # 1.7.1 (2024-04-03 10:19)
### Fixed ### Fixed

View File

@ -53,6 +53,7 @@ RABBITMQ_EXCHANGE_NAME=evolution_exchange
RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672 RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
WEBSOCKET_ENABLED=false WEBSOCKET_ENABLED=false
WEBSOCKET_GLOBAL_EVENTS=false
WA_BUSINESS_TOKEN_WEBHOOK=evolution WA_BUSINESS_TOKEN_WEBHOOK=evolution
WA_BUSINESS_URL=https://graph.facebook.com WA_BUSINESS_URL=https://graph.facebook.com

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.1" description="Api to control whatsapp features through http requests." LABEL version="1.7.2" 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"
@ -68,6 +68,7 @@ ENV RABBITMQ_EXCHANGE_NAME=evolution_exchange
ENV RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672 ENV RABBITMQ_URI=amqp://guest:guest@rabbitmq:5672
ENV WEBSOCKET_ENABLED=false ENV WEBSOCKET_ENABLED=false
ENV WEBSOCKET_GLOBAL_EVENTS=false
ENV WA_BUSINESS_TOKEN_WEBHOOK=evolution ENV WA_BUSINESS_TOKEN_WEBHOOK=evolution
ENV WA_BUSINESS_URL=https://graph.facebook.com ENV WA_BUSINESS_URL=https://graph.facebook.com

View File

@ -1,6 +1,6 @@
{ {
"name": "evolution-api", "name": "evolution-api",
"version": "1.7.1", "version": "1.7.2",
"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": {
@ -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.6.0", "@whiskeysockets/baileys": "github:AtendAI/Baileys",
"amqplib": "^0.10.3", "amqplib": "^0.10.3",
"aws-sdk": "^2.1499.0", "aws-sdk": "^2.1499.0",
"axios": "^1.6.5", "axios": "^1.6.5",
@ -60,6 +60,7 @@
"exiftool-vendored": "^22.0.0", "exiftool-vendored": "^22.0.0",
"express": "^4.18.2", "express": "^4.18.2",
"express-async-errors": "^3.1.1", "express-async-errors": "^3.1.1",
"fluent-ffmpeg": "^2.1.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",
"hbs": "^4.2.0", "hbs": "^4.2.0",
"https-proxy-agent": "^7.0.2", "https-proxy-agent": "^7.0.2",

View File

@ -8,21 +8,22 @@ 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';
import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; import { InstanceDto, SetPresenceDto } from '../dto/instance.dto';
import { ChatwootService } from '../integrations/chatwoot/services/chatwoot.service';
import { RabbitmqService } from '../integrations/rabbitmq/services/rabbitmq.service';
import { SqsService } from '../integrations/sqs/services/sqs.service';
import { TypebotService } from '../integrations/typebot/services/typebot.service';
import { WebsocketService } from '../integrations/websocket/services/websocket.service';
import { RepositoryBroker } from '../repository/repository.manager'; import { RepositoryBroker } from '../repository/repository.manager';
import { AuthService, OldToken } from '../services/auth.service'; import { AuthService, OldToken } from '../services/auth.service';
import { CacheService } from '../services/cache.service'; import { CacheService } from '../services/cache.service';
import { ChatwootService } from '../services/chatwoot.service';
import { IntegrationService } from '../services/integration.service'; import { IntegrationService } from '../services/integration.service';
import { WAMonitoringService } from '../services/monitor.service'; import { WAMonitoringService } from '../services/monitor.service';
import { RabbitmqService } from '../services/rabbitmq.service';
import { SettingsService } from '../services/settings.service'; import { SettingsService } from '../services/settings.service';
import { SqsService } from '../services/sqs.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 { BaileysStartupService } from '../services/whatsapp/whatsapp.baileys.service';
import { BaileysStartupService } from '../services/whatsapp.baileys.service'; import { BusinessStartupService } from '../services/whatsapp/whatsapp.business.service';
import { BusinessStartupService } from '../services/whatsapp.business.service';
import { Events, Integration, wa } from '../types/wa.types'; import { Events, Integration, wa } from '../types/wa.types';
import { ProxyController } from './proxy.controller';
export class InstanceController { export class InstanceController {
constructor( constructor(
@ -39,6 +40,7 @@ export class InstanceController {
private readonly sqsService: SqsService, private readonly sqsService: SqsService,
private readonly typebotService: TypebotService, private readonly typebotService: TypebotService,
private readonly integrationService: IntegrationService, private readonly integrationService: IntegrationService,
private readonly proxyService: ProxyController,
private readonly cache: RedisCache, private readonly cache: RedisCache,
private readonly chatwootCache: CacheService, private readonly chatwootCache: CacheService,
) {} ) {}
@ -53,6 +55,7 @@ export class InstanceController {
events, events,
qrcode, qrcode,
number, number,
mobile,
integration, integration,
token, token,
chatwoot_account_id, chatwoot_account_id,
@ -84,6 +87,7 @@ export class InstanceController {
typebot_delay_message, typebot_delay_message,
typebot_unknown_message, typebot_unknown_message,
typebot_listening_from_me, typebot_listening_from_me,
proxy,
}: InstanceDto) { }: InstanceDto) {
try { try {
this.logger.verbose('requested createInstance from ' + instanceName + ' instance'); this.logger.verbose('requested createInstance from ' + instanceName + ' instance');
@ -115,7 +119,7 @@ export class InstanceController {
); );
} }
await this.waMonitor.saveInstance({ integration, instanceName, token, number }); await this.waMonitor.saveInstance({ integration, instanceName, token, number, mobile });
instance.instanceName = instanceName; instance.instanceName = instanceName;
@ -345,6 +349,18 @@ export class InstanceController {
} }
} }
if (proxy) {
const testProxy = await this.proxyService.testProxy(proxy);
if (!testProxy) {
throw new BadRequestException('Invalid proxy');
}
await this.proxyService.createProxy(instance, {
enabled: true,
proxy,
});
}
if (typebot_url) { if (typebot_url) {
try { try {
if (!isURL(typebot_url, { require_tld: false })) { if (!isURL(typebot_url, { require_tld: false })) {
@ -405,7 +421,7 @@ export class InstanceController {
if (qrcode) { if (qrcode) {
this.logger.verbose('creating qrcode'); this.logger.verbose('creating qrcode');
await instance.connectToWhatsapp(number); await instance.connectToWhatsapp(number, mobile);
await delay(5000); await delay(5000);
getQrcode = instance.qrCode; getQrcode = instance.qrCode;
} }
@ -569,7 +585,7 @@ export class InstanceController {
} }
} }
public async connectToWhatsapp({ instanceName, number = null }: InstanceDto) { public async connectToWhatsapp({ instanceName, number = null, mobile = null }: InstanceDto) {
try { try {
this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance'); this.logger.verbose('requested connectToWhatsapp from ' + instanceName + ' instance');
@ -592,7 +608,7 @@ export class InstanceController {
if (state == 'close') { if (state == 'close') {
this.logger.verbose('connecting'); this.logger.verbose('connecting');
await instance.connectToWhatsapp(number); await instance.connectToWhatsapp(number, mobile);
await delay(5000); await delay(5000);
return instance.qrCode; return instance.qrCode;
@ -633,6 +649,20 @@ export class InstanceController {
} }
} }
public async registerMobileCode({ instanceName }: InstanceDto, { mobileCode }: any) {
try {
this.logger.verbose('requested registerMobileCode from ' + instanceName + ' instance');
const instance = this.waMonitor.waInstances[instanceName];
console.log('mobileCode', mobileCode);
await instance.receiveMobileCode(mobileCode);
return { status: 'SUCCESS', error: false, response: { message: 'Mobile code registered' } };
} catch (error) {
this.logger.error(error);
}
}
public async connectionState({ instanceName }: InstanceDto) { public async connectionState({ instanceName }: InstanceDto) {
this.logger.verbose('requested connectionState from ' + instanceName + ' instance'); this.logger.verbose('requested connectionState from ' + instanceName + ' instance');
return { return {

View File

@ -46,7 +46,7 @@ export class ProxyController {
return this.proxyService.find(instance); return this.proxyService.find(instance);
} }
private async testProxy(proxy: ProxyDto['proxy']) { public async testProxy(proxy: ProxyDto['proxy']) {
logger.verbose('requested testProxy'); logger.verbose('requested testProxy');
try { try {
const serverIp = await axios.get('https://icanhazip.com/'); const serverIp = await axios.get('https://icanhazip.com/');

View File

@ -1,10 +1,13 @@
import { WAPresence } from "@whiskeysockets/baileys"; import { WAPresence } from '@whiskeysockets/baileys';
import { ProxyDto } from './proxy.dto';
export class InstanceDto { export class InstanceDto {
instanceName: string; instanceName: string;
instanceId?: string; instanceId?: string;
qrcode?: boolean; qrcode?: boolean;
number?: string; number?: string;
mobile?: boolean;
integration?: string; integration?: string;
token?: string; token?: string;
webhook?: string; webhook?: string;
@ -40,7 +43,7 @@ export class InstanceDto {
typebot_delay_message?: number; typebot_delay_message?: number;
typebot_unknown_message?: string; typebot_unknown_message?: string;
typebot_listening_from_me?: boolean; typebot_listening_from_me?: boolean;
proxy?: string; proxy?: ProxyDto['proxy'];
} }
export class SetPresenceDto { export class SetPresenceDto {

View File

@ -7,8 +7,8 @@ import { Auth, configService } from '../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { ForbiddenException, UnauthorizedException } from '../../exceptions'; import { ForbiddenException, UnauthorizedException } from '../../exceptions';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { repository } from '../server.module';
import { JwtPayload } from '../services/auth.service'; import { JwtPayload } from '../services/auth.service';
import { repository } from '../whatsapp.module';
const logger = new Logger('GUARD'); const logger = new Logger('GUARD');

View File

@ -12,7 +12,7 @@ import {
} from '../../exceptions'; } from '../../exceptions';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { cache, waMonitor } from '../whatsapp.module'; import { cache, waMonitor } from '../server.module';
async function getInstance(instanceName: string) { async function getInstance(instanceName: string) {
try { try {

View File

@ -1,6 +1,6 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../../../dto/instance.dto';
import { ChamaaiDto } from '../dto/chamaai.dto'; import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto';
import { ChamaaiService } from '../services/chamaai.service'; import { ChamaaiService } from '../services/chamaai.service';
const logger = new Logger('ChamaaiController'); const logger = new Logger('ChamaaiController');

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
export class ChamaaiRaw { export class ChamaaiRaw {
_id?: string; _id?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { ChamaaiRaw, IChamaaiModel } from '../models'; import { ChamaaiRaw, IChamaaiModel } from '../../../models';
export class ChamaaiRepository extends Repository { export class ChamaaiRepository extends Repository {
constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) { constructor(private readonly chamaaiModel: IChamaaiModel, private readonly configService: ConfigService) {

View File

@ -1,12 +1,12 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { chamaaiSchema, instanceNameSchema } from '../../validate/validate.schema'; import { chamaaiSchema, instanceNameSchema } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { chamaaiController } from '../../../server.module';
import { ChamaaiDto } from '../dto/chamaai.dto'; import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto';
import { chamaaiController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('ChamaaiRouter'); const logger = new Logger('ChamaaiRouter');

View File

@ -2,13 +2,13 @@ import axios from 'axios';
import { writeFileSync } from 'fs'; import { writeFileSync } from 'fs';
import path from 'path'; import path from 'path';
import { ConfigService, HttpServer } from '../../config/env.config'; import { ConfigService, HttpServer } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../../../dto/instance.dto';
import { ChamaaiRaw } from '../../../models';
import { WAMonitoringService } from '../../../services/monitor.service';
import { Events } from '../../../types/wa.types';
import { ChamaaiDto } from '../dto/chamaai.dto'; import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto';
import { ChamaaiRaw } from '../models';
import { Events } from '../types/wa.types';
import { WAMonitoringService } from './monitor.service';
export class ChamaaiService { export class ChamaaiService {
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {} constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {}

View File

@ -0,0 +1,35 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const chamaaiSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
url: { type: 'string' },
token: { type: 'string' },
waNumber: { type: 'string' },
answerByAudio: { type: 'boolean', enum: [true, false] },
},
required: ['enabled', 'url', 'token', 'waNumber', 'answerByAudio'],
...isNotEmpty('enabled', 'url', 'token', 'waNumber', 'answerByAudio'),
};

View File

@ -1,5 +1,5 @@
import { CacheConf, ConfigService } from '../config/env.config'; import { CacheConf, ConfigService } from '../../../../config/env.config';
import { ICache } from '../whatsapp/abstract/abstract.cache'; import { ICache } from '../../../abstract/abstract.cache';
import { LocalCache } from './localcache'; import { LocalCache } from './localcache';
import { RedisCache } from './rediscache'; import { RedisCache } from './rediscache';

View File

@ -1,7 +1,7 @@
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
import { CacheConf, CacheConfLocal, ConfigService } from '../config/env.config'; import { CacheConf, CacheConfLocal, ConfigService } from '../../../../config/env.config';
import { ICache } from '../whatsapp/abstract/abstract.cache'; import { ICache } from '../../../abstract/abstract.cache';
export class LocalCache implements ICache { export class LocalCache implements ICache {
private conf: CacheConfLocal; private conf: CacheConfLocal;

View File

@ -1,7 +1,7 @@
import { createClient, RedisClientType } from 'redis'; import { createClient, RedisClientType } from 'redis';
import { CacheConf, CacheConfRedis, configService } from '../config/env.config'; import { CacheConf, CacheConfRedis, configService } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
class Redis { class Redis {
private logger = new Logger(Redis.name); private logger = new Logger(Redis.name);

View File

@ -1,8 +1,8 @@
import { RedisClientType } from 'redis'; import { RedisClientType } from 'redis';
import { CacheConf, CacheConfRedis, ConfigService } from '../config/env.config'; import { CacheConf, CacheConfRedis, ConfigService } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { ICache } from '../whatsapp/abstract/abstract.cache'; import { ICache } from '../../../abstract/abstract.cache';
import { redisClient } from './rediscache.client'; import { redisClient } from './rediscache.client';
export class RedisCache implements ICache { export class RedisCache implements ICache {

View File

@ -1,15 +1,15 @@
import { isURL } from 'class-validator'; import { isURL } from 'class-validator';
import { ConfigService, HttpServer } from '../../config/env.config'; import { ConfigService, HttpServer } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { BadRequestException } from '../../exceptions'; import { BadRequestException } from '../../../../exceptions';
import { CacheEngine } from '../../libs/cacheengine'; import { InstanceDto } from '../../../dto/instance.dto';
import { RepositoryBroker } from '../../../repository/repository.manager';
import { waMonitor } from '../../../server.module';
import { CacheService } from '../../../services/cache.service';
import { CacheEngine } from '../cache/cacheengine';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { InstanceDto } from '../dto/instance.dto';
import { RepositoryBroker } from '../repository/repository.manager';
import { CacheService } from '../services/cache.service';
import { ChatwootService } from '../services/chatwoot.service'; import { ChatwootService } from '../services/chatwoot.service';
import { waMonitor } from '../whatsapp.module';
const logger = new Logger('ChatwootController'); const logger = new Logger('ChatwootController');

View File

@ -1,7 +1,7 @@
import postgresql from 'pg'; import postgresql from 'pg';
import { Chatwoot, configService } from '../config/env.config'; import { Chatwoot, configService } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
const { Pool } = postgresql; const { Pool } = postgresql;

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
export class ChatwootRaw { export class ChatwootRaw {
_id?: string; _id?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { ChatwootRaw, IChatwootModel } from '../models'; import { ChatwootRaw, IChatwootModel } from '../../../models';
export class ChatwootRepository extends Repository { export class ChatwootRepository extends Repository {
constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) { constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) {

View File

@ -1,12 +1,12 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { chatwootSchema, instanceNameSchema } from '../../validate/validate.schema'; import { chatwootSchema, instanceNameSchema } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { chatwootController } from '../../../server.module';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { InstanceDto } from '../dto/instance.dto';
import { chatwootController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('ChatwootRouter'); const logger = new Logger('ChatwootRouter');

View File

@ -1,4 +1,12 @@
import ChatwootClient, { ChatwootAPIConfig, contact, conversation, generic_id, inbox } from '@figuro/chatwoot-sdk'; import ChatwootClient, {
ChatwootAPIConfig,
contact,
contact_inboxes,
conversation,
conversation_show,
generic_id,
inbox,
} from '@figuro/chatwoot-sdk';
import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request'; import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request';
import axios from 'axios'; import axios from 'axios';
import FormData from 'form-data'; import FormData from 'form-data';
@ -7,18 +15,18 @@ import Jimp from 'jimp';
import mimeTypes from 'mime-types'; import mimeTypes from 'mime-types';
import path from 'path'; import path from 'path';
import { Chatwoot, ConfigService, HttpServer } from '../../config/env.config'; import { Chatwoot, ConfigService, HttpServer } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { chatwootImport } from '../../utils/chatwoot-import-helper'; import i18next from '../../../../utils/i18n';
import i18next from '../../utils/i18n'; import { ICache } from '../../../abstract/abstract.cache';
import { ICache } from '../abstract/abstract.cache'; import { InstanceDto } from '../../../dto/instance.dto';
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../../../dto/sendMessage.dto';
import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../models';
import { RepositoryBroker } from '../../../repository/repository.manager';
import { WAMonitoringService } from '../../../services/monitor.service';
import { Events } from '../../../types/wa.types';
import { ChatwootDto } from '../dto/chatwoot.dto'; import { ChatwootDto } from '../dto/chatwoot.dto';
import { InstanceDto } from '../dto/instance.dto'; import { chatwootImport } from '../utils/chatwoot-import-helper';
import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../dto/sendMessage.dto';
import { ChatwootRaw, ContactRaw, MessageRaw } from '../models';
import { RepositoryBroker } from '../repository/repository.manager';
import { Events } from '../types/wa.types';
import { WAMonitoringService } from './monitor.service';
export class ChatwootService { export class ChatwootService {
private readonly logger = new Logger(ChatwootService.name); private readonly logger = new Logger(ChatwootService.name);
@ -1774,6 +1782,13 @@ export class ChatwootService {
return; return;
} }
// fix when receiving/sending messages from whatsapp desktop with ephemeral messages enabled
if (body.message?.ephemeralMessage?.message) {
body.message = {
...body.message?.ephemeralMessage?.message,
};
}
this.logger.verbose('get conversation message'); this.logger.verbose('get conversation message');
// Whatsapp to Chatwoot // Whatsapp to Chatwoot
@ -2123,12 +2138,13 @@ export class ChatwootService {
}; };
if (!sourceId && inbox) { if (!sourceId && inbox) {
const contact = (await this.findContact( const conversation = (await client.conversations.get({
instance, accountId: this.provider.account_id,
this.getNumberFromRemoteJid(body.key.remoteJid), conversationId: conversationId,
)) as contact; })) as conversation_show & {
const contactInbox = contact?.contact_inboxes?.find((contactInbox) => contactInbox?.inbox?.id === inbox.id); last_non_activity_message: { conversation: { contact_inbox: contact_inboxes } };
sourceId = contactInbox?.source_id; };
sourceId = conversation.last_non_activity_message?.conversation?.contact_inbox?.source_id;
} }
if (sourceId && inbox?.inbox_identifier) { if (sourceId && inbox?.inbox_identifier) {

View File

@ -1,12 +1,12 @@
import { inbox } from '@figuro/chatwoot-sdk'; import { inbox } from '@figuro/chatwoot-sdk';
import { proto } from '@whiskeysockets/baileys'; import { proto } from '@whiskeysockets/baileys';
import { Chatwoot, configService } from '../config/env.config'; import { InstanceDto } from '../../../../api/dto/instance.dto';
import { Logger } from '../config/logger.config'; import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../../api/models';
import { Chatwoot, configService } from '../../../../config/env.config';
import { Logger } from '../../../../config/logger.config';
import { postgresClient } from '../libs/postgres.client'; import { postgresClient } from '../libs/postgres.client';
import { InstanceDto } from '../whatsapp/dto/instance.dto'; import { ChatwootService } from '../services/chatwoot.service';
import { ChatwootRaw, ContactRaw, MessageRaw } from '../whatsapp/models';
import { ChatwootService } from '../whatsapp/services/chatwoot.service';
type ChatwootUser = { type ChatwootUser = {
user_type: string; user_type: string;

View File

@ -0,0 +1,42 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const chatwootSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
account_id: { type: 'string' },
token: { type: 'string' },
url: { type: 'string' },
sign_msg: { type: 'boolean', enum: [true, false] },
sign_delimiter: { type: ['string', 'null'] },
reopen_conversation: { type: 'boolean', enum: [true, false] },
conversation_pending: { type: 'boolean', enum: [true, false] },
auto_create: { type: 'boolean', enum: [true, false] },
import_contacts: { type: 'boolean', enum: [true, false] },
import_messages: { type: 'boolean', enum: [true, false] },
days_limit_import_messages: { type: 'number' },
},
required: ['enabled', 'account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'],
...isNotEmpty('account_id', 'token', 'url', 'sign_msg', 'reopen_conversation', 'conversation_pending'),
};

View File

@ -1,5 +1,5 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { RabbitmqDto } from '../dto/rabbitmq.dto'; import { RabbitmqDto } from '../dto/rabbitmq.dto';
import { RabbitmqService } from '../services/rabbitmq.service'; import { RabbitmqService } from '../services/rabbitmq.service';

View File

@ -1,7 +1,7 @@
import * as amqp from 'amqplib/callback_api'; import * as amqp from 'amqplib/callback_api';
import { configService, Rabbitmq } from '../config/env.config'; import { configService, Rabbitmq } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
const logger = new Logger('AMQP'); const logger = new Logger('AMQP');

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
export class RabbitmqRaw { export class RabbitmqRaw {
_id?: string; _id?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { IRabbitmqModel, RabbitmqRaw } from '../models'; import { IRabbitmqModel, RabbitmqRaw } from '../../../models';
export class RabbitmqRepository extends Repository { export class RabbitmqRepository extends Repository {
constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) { constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) {

View File

@ -1,12 +1,12 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { instanceNameSchema, rabbitmqSchema } from '../../validate/validate.schema'; import { instanceNameSchema, rabbitmqSchema } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { rabbitmqController } from '../../../server.module';
import { RabbitmqDto } from '../dto/rabbitmq.dto'; import { RabbitmqDto } from '../dto/rabbitmq.dto';
import { rabbitmqController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('RabbitmqRouter'); const logger = new Logger('RabbitmqRouter');

View File

@ -1,9 +1,9 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { initQueues } from '../../libs/amqp.server'; import { InstanceDto } from '../../../dto/instance.dto';
import { InstanceDto } from '../dto/instance.dto'; import { RabbitmqRaw } from '../../../models';
import { WAMonitoringService } from '../../../services/monitor.service';
import { RabbitmqDto } from '../dto/rabbitmq.dto'; import { RabbitmqDto } from '../dto/rabbitmq.dto';
import { RabbitmqRaw } from '../models'; import { initQueues } from '../libs/amqp.server';
import { WAMonitoringService } from './monitor.service';
export class RabbitmqService { export class RabbitmqService {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}

View File

@ -0,0 +1,66 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const rabbitmqSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'LABELS_EDIT',
'LABELS_ASSOCIATION',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['enabled'],
...isNotEmpty('enabled'),
};

View File

@ -1,5 +1,5 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { SqsDto } from '../dto/sqs.dto'; import { SqsDto } from '../dto/sqs.dto';
import { SqsService } from '../services/sqs.service'; import { SqsService } from '../services/sqs.service';

View File

@ -1,7 +1,7 @@
import { SQS } from 'aws-sdk'; import { SQS } from 'aws-sdk';
import { configService, Sqs } from '../config/env.config'; import { configService, Sqs } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
const logger = new Logger('SQS'); const logger = new Logger('SQS');

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
export class SqsRaw { export class SqsRaw {
_id?: string; _id?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { ISqsModel, SqsRaw } from '../models'; import { ISqsModel, SqsRaw } from '../../../models';
export class SqsRepository extends Repository { export class SqsRepository extends Repository {
constructor(private readonly sqsModel: ISqsModel, private readonly configService: ConfigService) { constructor(private readonly sqsModel: ISqsModel, private readonly configService: ConfigService) {

View File

@ -1,12 +1,12 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { instanceNameSchema, sqsSchema } from '../../validate/validate.schema'; import { instanceNameSchema, sqsSchema } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { sqsController } from '../../../server.module';
import { SqsDto } from '../dto/sqs.dto'; import { SqsDto } from '../dto/sqs.dto';
import { sqsController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('SqsRouter'); const logger = new Logger('SqsRouter');

View File

@ -1,9 +1,9 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { initQueues } from '../../libs/sqs.server'; import { InstanceDto } from '../../../dto/instance.dto';
import { InstanceDto } from '../dto/instance.dto'; import { SqsRaw } from '../../../models';
import { WAMonitoringService } from '../../../services/monitor.service';
import { SqsDto } from '../dto/sqs.dto'; import { SqsDto } from '../dto/sqs.dto';
import { SqsRaw } from '../models'; import { initQueues } from '../libs/sqs.server';
import { WAMonitoringService } from './monitor.service';
export class SqsService { export class SqsService {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}

View File

@ -0,0 +1,66 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const sqsSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'LABELS_EDIT',
'LABELS_ASSOCIATION',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['enabled'],
...isNotEmpty('enabled'),
};

View File

@ -1,5 +1,5 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { TypebotDto } from '../dto/typebot.dto'; import { TypebotDto } from '../dto/typebot.dto';
import { TypebotService } from '../services/typebot.service'; import { TypebotService } from '../services/typebot.service';

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
class Session { class Session {
remoteJid?: string; remoteJid?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { ITypebotModel, TypebotRaw } from '../models'; import { ITypebotModel, TypebotRaw } from '../../../models';
export class TypebotRepository extends Repository { export class TypebotRepository extends Repository {
constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) { constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) {

View File

@ -1,17 +1,17 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { import {
instanceNameSchema, instanceNameSchema,
typebotSchema, typebotSchema,
typebotStartSchema, typebotStartSchema,
typebotStatusSchema, typebotStatusSchema,
} from '../../validate/validate.schema'; } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { typebotController } from '../../../server.module';
import { TypebotDto } from '../dto/typebot.dto'; import { TypebotDto } from '../dto/typebot.dto';
import { typebotController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('TypebotRouter'); const logger = new Logger('TypebotRouter');

View File

@ -1,13 +1,13 @@
import axios from 'axios'; import axios from 'axios';
import EventEmitter2 from 'eventemitter2'; import EventEmitter2 from 'eventemitter2';
import { ConfigService, Typebot } from '../../config/env.config'; import { ConfigService, Typebot } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { MessageRaw } from '../../../models';
import { WAMonitoringService } from '../../../services/monitor.service';
import { Events } from '../../../types/wa.types';
import { Session, TypebotDto } from '../dto/typebot.dto'; import { Session, TypebotDto } from '../dto/typebot.dto';
import { MessageRaw } from '../models';
import { Events } from '../types/wa.types';
import { WAMonitoringService } from './monitor.service';
export class TypebotService { export class TypebotService {
constructor( constructor(
@ -57,7 +57,7 @@ export class TypebotService {
if (session) { if (session) {
if (status === 'closed') { if (status === 'closed') {
findData.sessions.splice(findData.sessions.indexOf(session), 1); const found_session: Session[] = findData.sessions.splice(findData.sessions.indexOf(session), 1);
const typebotData = { const typebotData = {
enabled: findData.enabled, enabled: findData.enabled,
@ -68,7 +68,7 @@ export class TypebotService {
delay_message: findData.delay_message, delay_message: findData.delay_message,
unknown_message: findData.unknown_message, unknown_message: findData.unknown_message,
listening_from_me: findData.listening_from_me, listening_from_me: findData.listening_from_me,
sessions: findData.sessions, sessions: found_session,
}; };
this.create(instance, typebotData); this.create(instance, typebotData);
@ -106,7 +106,7 @@ export class TypebotService {
delay_message: findData.delay_message, delay_message: findData.delay_message,
unknown_message: findData.unknown_message, unknown_message: findData.unknown_message,
listening_from_me: findData.listening_from_me, listening_from_me: findData.listening_from_me,
sessions: findData.sessions, sessions: findData.sessions.splice(findData.sessions.indexOf(session), 1),
}; };
this.create(instance, typebotData); this.create(instance, typebotData);
@ -269,27 +269,30 @@ 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 = { const types = {
conversation: msg.conversation, conversation: msg.conversation,
extendedTextMessage: msg.extendedTextMessage?.text, extendedTextMessage: msg.extendedTextMessage?.text,
audioMessage: msg.audioMessage?.url, audioMessage: msg.audioMessage?.url,
imageMessage: msg.imageMessage?.url, imageMessage: msg.imageMessage?.url,
videoMessage: msg.videoMessage?.url, videoMessage: msg.videoMessage?.url,
documentMessage: msg.documentMessage?.fileName, documentMessage: msg.documentMessage?.fileName,
contactMessage: msg.contactMessage?.displayName, contactMessage: msg.contactMessage?.displayName,
locationMessage: msg.locationMessage?.degreesLatitude, locationMessage: msg.locationMessage?.degreesLatitude,
viewOnceMessageV2: msg.viewOnceMessageV2?.message?.imageMessage?.url || msg.viewOnceMessageV2?.message?.videoMessage?.url || msg.viewOnceMessageV2?.message?.audioMessage?.url, viewOnceMessageV2:
listResponseMessage: msg.listResponseMessage?.singleSelectReply?.selectedRowId, msg.viewOnceMessageV2?.message?.imageMessage?.url ||
responseRowId: msg.listResponseMessage?.singleSelectReply?.selectedRowId, msg.viewOnceMessageV2?.message?.videoMessage?.url ||
}; msg.viewOnceMessageV2?.message?.audioMessage?.url,
listResponseMessage: msg.listResponseMessage?.singleSelectReply?.selectedRowId,
responseRowId: msg.listResponseMessage?.singleSelectReply?.selectedRowId,
};
const messageType = Object.keys(types).find(key => types[key] !== undefined) || 'unknown'; const messageType = Object.keys(types).find((key) => types[key] !== undefined) || 'unknown';
this.logger.verbose('Type message: ' + JSON.stringify(types)); this.logger.verbose('Type message: ' + JSON.stringify(types));
return { ...types, messageType }; return { ...types, messageType };
} }
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);
@ -317,7 +320,7 @@ export class TypebotService {
this.logger.verbose('get audio message content'); this.logger.verbose('get audio message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const audioContent = types.audioMessage; const audioContent = types.audioMessage;
this.logger.verbose('audio message URL: ' + audioContent); this.logger.verbose('audio message URL: ' + audioContent);
@ -327,85 +330,85 @@ export class TypebotService {
private getImageMessageContent(msg: any) { private getImageMessageContent(msg: any) {
this.logger.verbose('get image message content'); this.logger.verbose('get image message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const imageContent = types.imageMessage; const imageContent = types.imageMessage;
this.logger.verbose('image message URL: ' + imageContent); this.logger.verbose('image message URL: ' + imageContent);
return imageContent; return imageContent;
} }
private getVideoMessageContent(msg: any) { private getVideoMessageContent(msg: any) {
this.logger.verbose('get video message content'); this.logger.verbose('get video message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const videoContent = types.videoMessage; const videoContent = types.videoMessage;
this.logger.verbose('video message URL: ' + videoContent); this.logger.verbose('video message URL: ' + videoContent);
return videoContent; return videoContent;
} }
private getDocumentMessageContent(msg: any) { private getDocumentMessageContent(msg: any) {
this.logger.verbose('get document message content'); this.logger.verbose('get document message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const documentContent = types.documentMessage; const documentContent = types.documentMessage;
this.logger.verbose('document message fileName: ' + documentContent); this.logger.verbose('document message fileName: ' + documentContent);
return documentContent; return documentContent;
} }
private getContactMessageContent(msg: any) { private getContactMessageContent(msg: any) {
this.logger.verbose('get contact message content'); this.logger.verbose('get contact message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const contactContent = types.contactMessage; const contactContent = types.contactMessage;
this.logger.verbose('contact message displayName: ' + contactContent); this.logger.verbose('contact message displayName: ' + contactContent);
return contactContent; return contactContent;
} }
private getLocationMessageContent(msg: any) { private getLocationMessageContent(msg: any) {
this.logger.verbose('get location message content'); this.logger.verbose('get location message content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const locationContent = types.locationMessage; const locationContent = types.locationMessage;
this.logger.verbose('location message degreesLatitude: ' + locationContent); this.logger.verbose('location message degreesLatitude: ' + locationContent);
return locationContent; return locationContent;
} }
private getViewOnceMessageV2Content(msg: any) { private getViewOnceMessageV2Content(msg: any) {
this.logger.verbose('get viewOnceMessageV2 content'); this.logger.verbose('get viewOnceMessageV2 content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const viewOnceContent = types.viewOnceMessageV2; const viewOnceContent = types.viewOnceMessageV2;
this.logger.verbose('viewOnceMessageV2 URL: ' + viewOnceContent); this.logger.verbose('viewOnceMessageV2 URL: ' + viewOnceContent);
return viewOnceContent; return viewOnceContent;
} }
private getListResponseMessageContent(msg: any) { private getListResponseMessageContent(msg: any) {
this.logger.verbose('get listResponseMessage content'); this.logger.verbose('get listResponseMessage content');
const types = this.getTypeMessage(msg); const types = this.getTypeMessage(msg);
const listResponseContent = types.listResponseMessage || types.responseRowId; const listResponseContent = types.listResponseMessage || types.responseRowId;
this.logger.verbose('listResponseMessage selectedRowId: ' + listResponseContent); this.logger.verbose('listResponseMessage selectedRowId: ' + listResponseContent);
return listResponseContent; return listResponseContent;
} }
public async createNewSession(instance: InstanceDto, data: any) { public async createNewSession(instance: InstanceDto, data: any) {
@ -791,7 +794,7 @@ export class TypebotService {
sessions: sessions, sessions: sessions,
remoteJid: remoteJid, remoteJid: remoteJid,
pushName: msg.pushName, pushName: msg.pushName,
prefilledVariables: { prefilledVariables: {
messageType: messageType, messageType: messageType,
}, },
}); });

View File

@ -0,0 +1,60 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const typebotSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
url: { type: 'string' },
typebot: { type: 'string' },
expire: { type: 'integer' },
delay_message: { type: 'integer' },
unknown_message: { type: 'string' },
listening_from_me: { type: 'boolean', enum: [true, false] },
},
required: ['enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'],
...isNotEmpty('enabled', 'url', 'typebot', 'expire', 'delay_message', 'unknown_message', 'listening_from_me'),
};
export const typebotStatusSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
remoteJid: { type: 'string' },
status: { type: 'string', enum: ['opened', 'closed', 'paused'] },
},
required: ['remoteJid', 'status'],
...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'),
};

View File

@ -1,5 +1,5 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { WebsocketDto } from '../dto/websocket.dto'; import { WebsocketDto } from '../dto/websocket.dto';
import { WebsocketService } from '../services/websocket.service'; import { WebsocketService } from '../services/websocket.service';

View File

@ -1,8 +1,8 @@
import { Server } from 'http'; import { Server } from 'http';
import { Server as SocketIO } from 'socket.io'; import { Server as SocketIO } from 'socket.io';
import { configService, Cors, Websocket } from '../config/env.config'; import { configService, Cors, Websocket } from '../../../../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../../../../config/logger.config';
const logger = new Logger('Socket'); const logger = new Logger('Socket');

View File

@ -1,6 +1,6 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../../../libs/db.connect';
export class WebsocketRaw { export class WebsocketRaw {
_id?: string; _id?: string;

View File

@ -1,10 +1,10 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService } from '../../config/env.config'; import { ConfigService } from '../../../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../../../abstract/abstract.repository';
import { IWebsocketModel, WebsocketRaw } from '../models'; import { IWebsocketModel, WebsocketRaw } from '../../../models';
export class WebsocketRepository extends Repository { export class WebsocketRepository extends Repository {
constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) { constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) {

View File

@ -1,12 +1,12 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { instanceNameSchema, websocketSchema } from '../../validate/validate.schema'; import { instanceNameSchema, websocketSchema } from '../../../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../../../abstract/abstract.router';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { HttpStatus } from '../../../routes/index.router';
import { websocketController } from '../../../server.module';
import { WebsocketDto } from '../dto/websocket.dto'; import { WebsocketDto } from '../dto/websocket.dto';
import { websocketController } from '../whatsapp.module';
import { HttpStatus } from './index.router';
const logger = new Logger('WebsocketRouter'); const logger = new Logger('WebsocketRouter');

View File

@ -1,8 +1,8 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../../../dto/instance.dto';
import { WebsocketRaw } from '../../../models';
import { WAMonitoringService } from '../../../services/monitor.service';
import { WebsocketDto } from '../dto/websocket.dto'; import { WebsocketDto } from '../dto/websocket.dto';
import { WebsocketRaw } from '../models';
import { WAMonitoringService } from './monitor.service';
export class WebsocketService { export class WebsocketService {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}

View File

@ -0,0 +1,66 @@
import { JSONSchema7 } from 'json-schema';
import { v4 } from 'uuid';
const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => {
const properties = {};
propertyNames.forEach(
(property) =>
(properties[property] = {
minLength: 1,
description: `The "${property}" cannot be empty`,
}),
);
return {
if: {
propertyNames: {
enum: [...propertyNames],
},
},
then: { properties },
};
};
export const websocketSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
enabled: { type: 'boolean', enum: [true, false] },
events: {
type: 'array',
minItems: 0,
items: {
type: 'string',
enum: [
'APPLICATION_STARTUP',
'QRCODE_UPDATED',
'MESSAGES_SET',
'MESSAGES_UPSERT',
'MESSAGES_UPDATE',
'MESSAGES_DELETE',
'SEND_MESSAGE',
'CONTACTS_SET',
'CONTACTS_UPSERT',
'CONTACTS_UPDATE',
'PRESENCE_UPDATE',
'CHATS_SET',
'CHATS_UPSERT',
'CHATS_UPDATE',
'CHATS_DELETE',
'GROUPS_UPSERT',
'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE',
'LABELS_EDIT',
'LABELS_ASSOCIATION',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
],
},
},
},
required: ['enabled'],
...isNotEmpty('enabled'),
};

15
src/api/models/index.ts Normal file
View File

@ -0,0 +1,15 @@
export * from '../integrations/chamaai/models/chamaai.model';
export * from '../integrations/chatwoot/models/chatwoot.model';
export * from '../integrations/rabbitmq/models/rabbitmq.model';
export * from '../integrations/sqs/models/sqs.model';
export * from '../integrations/typebot/models/typebot.model';
export * from '../integrations/websocket/models/websocket.model';
export * from './auth.model';
export * from './chat.model';
export * from './contact.model';
export * from './integration.model';
export * from './label.model';
export * from './message.model';
export * from './proxy.model';
export * from './settings.model';
export * from './webhook.model';

View File

@ -4,22 +4,22 @@ import { join } from 'path';
import { Auth, ConfigService, Database } from '../../config/env.config'; import { Auth, ConfigService, Database } from '../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { ChamaaiRepository } from '../integrations/chamaai/repository/chamaai.repository';
import { ChatwootRepository } from '../integrations/chatwoot/repository/chatwoot.repository';
import { RabbitmqRepository } from '../integrations/rabbitmq/repository/rabbitmq.repository';
import { SqsRepository } from '../integrations/sqs/repository/sqs.repository';
import { TypebotRepository } from '../integrations/typebot/repository/typebot.repository';
import { WebsocketRepository } from '../integrations/websocket/repository/websocket.repository';
import { AuthRepository } from './auth.repository'; import { AuthRepository } from './auth.repository';
import { ChamaaiRepository } from './chamaai.repository';
import { ChatRepository } from './chat.repository'; import { ChatRepository } from './chat.repository';
import { ChatwootRepository } from './chatwoot.repository';
import { ContactRepository } from './contact.repository'; import { ContactRepository } from './contact.repository';
import { IntegrationRepository } from './integration.repository'; import { IntegrationRepository } from './integration.repository';
import { LabelRepository } from './label.repository'; import { LabelRepository } from './label.repository';
import { MessageRepository } from './message.repository'; import { MessageRepository } from './message.repository';
import { MessageUpRepository } from './messageUp.repository'; import { MessageUpRepository } from './messageUp.repository';
import { ProxyRepository } from './proxy.repository'; import { ProxyRepository } from './proxy.repository';
import { RabbitmqRepository } from './rabbitmq.repository';
import { SettingsRepository } from './settings.repository'; import { SettingsRepository } from './settings.repository';
import { SqsRepository } from './sqs.repository';
import { TypebotRepository } from './typebot.repository';
import { WebhookRepository } from './webhook.repository'; import { WebhookRepository } from './webhook.repository';
import { WebsocketRepository } from './websocket.repository';
export class RepositoryBroker { export class RepositoryBroker {
constructor( constructor(
public readonly message: MessageRepository, public readonly message: MessageRepository,

View File

@ -9,7 +9,6 @@ import {
messageUpSchema, messageUpSchema,
messageValidateSchema, messageValidateSchema,
presenceSchema, presenceSchema,
presenceOnlySchema,
privacySettingsSchema, privacySettingsSchema,
profileNameSchema, profileNameSchema,
profilePictureSchema, profilePictureSchema,
@ -39,7 +38,7 @@ import { InstanceDto } from '../dto/instance.dto';
import { ContactQuery } from '../repository/contact.repository'; import { ContactQuery } from '../repository/contact.repository';
import { MessageQuery } from '../repository/message.repository'; import { MessageQuery } from '../repository/message.repository';
import { MessageUpQuery } from '../repository/messageUp.repository'; import { MessageUpQuery } from '../repository/messageUp.repository';
import { chatController } from '../whatsapp.module'; import { chatController } from '../server.module';
import { HttpStatus } from './index.router'; import { HttpStatus } from './index.router';
const logger = new Logger('ChatRouter'); const logger = new Logger('ChatRouter');

View File

@ -30,7 +30,7 @@ import {
GroupUpdateParticipantDto, GroupUpdateParticipantDto,
GroupUpdateSettingDto, GroupUpdateSettingDto,
} from '../dto/group.dto'; } from '../dto/group.dto';
import { groupController } from '../whatsapp.module'; import { groupController } from '../server.module';
import { HttpStatus } from './index.router'; import { HttpStatus } from './index.router';
const logger = new Logger('GroupRouter'); const logger = new Logger('GroupRouter');

Some files were not shown because too many files have changed in this diff Show More