Integração com ChatGPT e id inbox chatwoot

This commit is contained in:
CodePhix 2023-12-06 20:16:20 -03:00
parent 41b2946cdc
commit eadbba8ca6
129 changed files with 19275 additions and 17806 deletions

BIN
.DS_Store vendored

Binary file not shown.

5
env Normal file
View File

@ -0,0 +1,5 @@
OPENAI_API_KEY=""
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASS=0

14
src/config.ts Executable file
View File

@ -0,0 +1,14 @@
import dotenv from "dotenv"
dotenv.config()
export const config = {
openAI: {
apiToken: process.env.OPENAI_API_KEY,
},
redis: {
host: process.env.REDIS_HOST || "localhost",
port: (process.env.REDIS_PORT as unknown as number) || 6379,
db: (process.env.REDIS_DB as unknown as number) || 0,
},
}

681
src/config/env.config.ts Normal file → Executable file
View File

@ -1,333 +1,348 @@
import { isBooleanString } from 'class-validator'; import { isBooleanString } from 'class-validator';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { load } from 'js-yaml'; import { load } from 'js-yaml';
import { join } from 'path'; import { join } from 'path';
export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string }; export type HttpServer = { TYPE: 'http' | 'https'; PORT: number; URL: string };
export type HttpMethods = 'POST' | 'GET' | 'PUT' | 'DELETE'; export type HttpMethods = 'POST' | 'GET' | 'PUT' | 'DELETE';
export type Cors = { export type Cors = {
ORIGIN: string[]; ORIGIN: string[];
METHODS: HttpMethods[]; METHODS: HttpMethods[];
CREDENTIALS: boolean; CREDENTIALS: boolean;
}; };
export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'; export type LogBaileys = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';
export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS'; export type LogLevel = 'ERROR' | 'WARN' | 'DEBUG' | 'INFO' | 'LOG' | 'VERBOSE' | 'DARK' | 'WEBHOOKS';
export type Log = { export type Log = {
LEVEL: LogLevel[]; LEVEL: LogLevel[];
COLOR: boolean; COLOR: boolean;
BAILEYS: LogBaileys; BAILEYS: LogBaileys;
}; };
export type SaveData = { export type SaveData = {
INSTANCE: boolean; INSTANCE: boolean;
NEW_MESSAGE: boolean; NEW_MESSAGE: boolean;
MESSAGE_UPDATE: boolean; MESSAGE_UPDATE: boolean;
CONTACTS: boolean; CONTACTS: boolean;
CHATS: boolean; CHATS: boolean;
}; };
export type StoreConf = { export type StoreConf = {
MESSAGES: boolean; MESSAGES: boolean;
MESSAGE_UP: boolean; MESSAGE_UP: boolean;
CONTACTS: boolean; CONTACTS: boolean;
CHATS: boolean; CHATS: boolean;
}; };
export type CleanStoreConf = { export type CleanStoreConf = {
CLEANING_INTERVAL: number; CLEANING_INTERVAL: number;
MESSAGES: boolean; MESSAGES: boolean;
MESSAGE_UP: boolean; MESSAGE_UP: boolean;
CONTACTS: boolean; CONTACTS: boolean;
CHATS: boolean; CHATS: boolean;
}; };
export type DBConnection = { export type DBConnection = {
URI: string; URI: string;
DB_PREFIX_NAME: string; DB_PREFIX_NAME: string;
}; DB_PREFIX_FINAL_NAME: string;
export type Database = { };
CONNECTION: DBConnection; export type Database = {
ENABLED: boolean; CONNECTION: DBConnection;
SAVE_DATA: SaveData; ENABLED: boolean;
}; SAVE_DATA: SaveData;
};
export type Redis = {
ENABLED: boolean; export type Redis = {
URI: string; ENABLED: boolean;
PREFIX_KEY: string; URI: string;
}; PREFIX_KEY: string;
};
export type Rabbitmq = {
ENABLED: boolean; export type Rabbitmq = {
URI: string; ENABLED: boolean;
}; URI: string;
};
export type Sqs = {
ENABLED: boolean; export type Sqs = {
ACCESS_KEY_ID: string; ENABLED: boolean;
SECRET_ACCESS_KEY: string; ACCESS_KEY_ID: string;
ACCOUNT_ID: string; SECRET_ACCESS_KEY: string;
REGION: string; ACCOUNT_ID: string;
}; REGION: string;
};
export type Websocket = {
ENABLED: boolean; export type Openai = {
}; CHAVE: string;
ENABLED: boolean;
export type Chatwoot = { URI: string;
USE_REPLY_ID: boolean; };
};
export type Websocket = {
export type EventsWebhook = { ENABLED: boolean;
APPLICATION_STARTUP: boolean; };
QRCODE_UPDATED: boolean;
MESSAGES_SET: boolean; export type Chatwoot = {
MESSAGES_UPSERT: boolean; USE_REPLY_ID: boolean;
MESSAGES_UPDATE: boolean; };
MESSAGES_DELETE: boolean;
SEND_MESSAGE: boolean; export type EventsWebhook = {
CONTACTS_SET: boolean; APPLICATION_STARTUP: boolean;
CONTACTS_UPDATE: boolean; QRCODE_UPDATED: boolean;
CONTACTS_UPSERT: boolean; MESSAGES_SET: boolean;
PRESENCE_UPDATE: boolean; MESSAGES_UPSERT: boolean;
CHATS_SET: boolean; MESSAGES_UPDATE: boolean;
CHATS_UPDATE: boolean; MESSAGES_DELETE: boolean;
CHATS_DELETE: boolean; SEND_MESSAGE: boolean;
CHATS_UPSERT: boolean; CONTACTS_SET: boolean;
CONNECTION_UPDATE: boolean; CONTACTS_UPDATE: boolean;
GROUPS_UPSERT: boolean; CONTACTS_UPSERT: boolean;
GROUP_UPDATE: boolean; PRESENCE_UPDATE: boolean;
GROUP_PARTICIPANTS_UPDATE: boolean; CHATS_SET: boolean;
CALL: boolean; CHATS_UPDATE: boolean;
NEW_JWT_TOKEN: boolean; CHATS_DELETE: boolean;
TYPEBOT_START: boolean; CHATS_UPSERT: boolean;
TYPEBOT_CHANGE_STATUS: boolean; CONNECTION_UPDATE: boolean;
CHAMA_AI_ACTION: boolean; GROUPS_UPSERT: boolean;
ERRORS: boolean; GROUP_UPDATE: boolean;
ERRORS_WEBHOOK: string; GROUP_PARTICIPANTS_UPDATE: boolean;
}; CALL: boolean;
NEW_JWT_TOKEN: boolean;
export type ApiKey = { KEY: string }; TYPEBOT_START: boolean;
export type Jwt = { EXPIRIN_IN: number; SECRET: string }; TYPEBOT_CHANGE_STATUS: boolean;
CHAMA_AI_ACTION: boolean;
export type Auth = { ERRORS: boolean;
API_KEY: ApiKey; ERRORS_WEBHOOK: string;
EXPOSE_IN_FETCH_INSTANCES: boolean; };
JWT: Jwt;
TYPE: 'jwt' | 'apikey'; export type ApiKey = { KEY: string };
}; export type Jwt = { EXPIRIN_IN: number; SECRET: string };
export type DelInstance = number | boolean; export type Auth = {
API_KEY: ApiKey;
export type GlobalWebhook = { EXPOSE_IN_FETCH_INSTANCES: boolean;
URL: string; JWT: Jwt;
ENABLED: boolean; TYPE: 'jwt' | 'apikey';
WEBHOOK_BY_EVENTS: boolean; };
};
export type SslConf = { PRIVKEY: string; FULLCHAIN: string }; export type DelInstance = number | boolean;
export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
export type ConfigSessionPhone = { CLIENT: string; NAME: string }; export type GlobalWebhook = {
export type QrCode = { LIMIT: number; COLOR: string }; URL: string;
export type Typebot = { API_VERSION: string }; ENABLED: boolean;
export type Production = boolean; WEBHOOK_BY_EVENTS: boolean;
};
export interface Env { export type SslConf = { PRIVKEY: string; FULLCHAIN: string };
SERVER: HttpServer; export type Webhook = { GLOBAL?: GlobalWebhook; EVENTS: EventsWebhook };
CORS: Cors; export type ConfigSessionPhone = { CLIENT: string; NAME: string };
SSL_CONF: SslConf; export type QrCode = { LIMIT: number; COLOR: string };
STORE: StoreConf; export type Typebot = { API_VERSION: string };
CLEAN_STORE: CleanStoreConf; export type Production = boolean;
DATABASE: Database;
REDIS: Redis; export interface Env {
RABBITMQ: Rabbitmq; SERVER: HttpServer;
SQS: Sqs; CORS: Cors;
WEBSOCKET: Websocket; SSL_CONF: SslConf;
LOG: Log; STORE: StoreConf;
DEL_INSTANCE: DelInstance; CLEAN_STORE: CleanStoreConf;
WEBHOOK: Webhook; DATABASE: Database;
CONFIG_SESSION_PHONE: ConfigSessionPhone; REDIS: Redis;
QRCODE: QrCode; RABBITMQ: Rabbitmq;
TYPEBOT: Typebot; SQS: Sqs;
AUTHENTICATION: Auth; OPENAI: Openai;
PRODUCTION?: Production; WEBSOCKET: Websocket;
CHATWOOT?: Chatwoot; LOG: Log;
} DEL_INSTANCE: DelInstance;
WEBHOOK: Webhook;
export type Key = keyof Env; CONFIG_SESSION_PHONE: ConfigSessionPhone;
QRCODE: QrCode;
export class ConfigService { TYPEBOT: Typebot;
constructor() { AUTHENTICATION: Auth;
this.loadEnv(); PRODUCTION?: Production;
} CHATWOOT?: Chatwoot;
}
private env: Env;
export type Key = keyof Env;
public get<T = any>(key: Key) {
return this.env[key] as T; export class ConfigService {
} constructor() {
this.loadEnv();
private loadEnv() { }
this.env = !(process.env?.DOCKER_ENV === 'true') ? this.envYaml() : this.envProcess();
this.env.PRODUCTION = process.env?.NODE_ENV === 'PROD'; private env: Env;
if (process.env?.DOCKER_ENV === 'true') {
this.env.SERVER.TYPE = 'http'; public get<T = any>(key: Key) {
this.env.SERVER.PORT = 8080; return this.env[key] as T;
} }
}
private loadEnv() {
private envYaml(): Env { this.env = !(process.env?.DOCKER_ENV === 'true') ? this.envYaml() : this.envProcess();
return load(readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' })) as Env; this.env.PRODUCTION = process.env?.NODE_ENV === 'PROD';
} if (process.env?.DOCKER_ENV === 'true') {
this.env.SERVER.TYPE = 'http';
private envProcess(): Env { this.env.SERVER.PORT = 8080;
return { }
SERVER: { }
TYPE: process.env.SERVER_TYPE as 'http' | 'https',
PORT: Number.parseInt(process.env.SERVER_PORT) || 8080, private envYaml(): Env {
URL: process.env.SERVER_URL, return load(readFileSync(join(process.cwd(), 'src', 'env.yml'), { encoding: 'utf-8' })) as Env;
}, }
CORS: {
ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'], private envProcess(): Env {
METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'], return {
CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true', SERVER: {
}, TYPE: process.env.SERVER_TYPE as 'http' | 'https',
SSL_CONF: { PORT: Number.parseInt(process.env.SERVER_PORT) || 8080,
PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '', URL: process.env.SERVER_URL,
FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '', },
}, CORS: {
STORE: { ORIGIN: process.env.CORS_ORIGIN.split(',') || ['*'],
MESSAGES: process.env?.STORE_MESSAGES === 'true', METHODS: (process.env.CORS_METHODS.split(',') as HttpMethods[]) || ['POST', 'GET', 'PUT', 'DELETE'],
MESSAGE_UP: process.env?.STORE_MESSAGE_UP === 'true', CREDENTIALS: process.env?.CORS_CREDENTIALS === 'true',
CONTACTS: process.env?.STORE_CONTACTS === 'true', },
CHATS: process.env?.STORE_CHATS === 'true', SSL_CONF: {
}, PRIVKEY: process.env?.SSL_CONF_PRIVKEY || '',
CLEAN_STORE: { FULLCHAIN: process.env?.SSL_CONF_FULLCHAIN || '',
CLEANING_INTERVAL: Number.isInteger(process.env?.CLEAN_STORE_CLEANING_TERMINAL) },
? Number.parseInt(process.env.CLEAN_STORE_CLEANING_TERMINAL) STORE: {
: 7200, MESSAGES: process.env?.STORE_MESSAGES === 'true',
MESSAGES: process.env?.CLEAN_STORE_MESSAGES === 'true', MESSAGE_UP: process.env?.STORE_MESSAGE_UP === 'true',
MESSAGE_UP: process.env?.CLEAN_STORE_MESSAGE_UP === 'true', CONTACTS: process.env?.STORE_CONTACTS === 'true',
CONTACTS: process.env?.CLEAN_STORE_CONTACTS === 'true', CHATS: process.env?.STORE_CHATS === 'true',
CHATS: process.env?.CLEAN_STORE_CHATS === 'true', },
}, CLEAN_STORE: {
DATABASE: { CLEANING_INTERVAL: Number.isInteger(process.env?.CLEAN_STORE_CLEANING_TERMINAL)
CONNECTION: { ? Number.parseInt(process.env.CLEAN_STORE_CLEANING_TERMINAL)
URI: process.env.DATABASE_CONNECTION_URI || '', : 7200,
DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', MESSAGES: process.env?.CLEAN_STORE_MESSAGES === 'true',
}, MESSAGE_UP: process.env?.CLEAN_STORE_MESSAGE_UP === 'true',
ENABLED: process.env?.DATABASE_ENABLED === 'true', CONTACTS: process.env?.CLEAN_STORE_CONTACTS === 'true',
SAVE_DATA: { CHATS: process.env?.CLEAN_STORE_CHATS === 'true',
INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true', },
NEW_MESSAGE: process.env?.DATABASE_SAVE_DATA_NEW_MESSAGE === 'true', DATABASE: {
MESSAGE_UPDATE: process.env?.DATABASE_SAVE_MESSAGE_UPDATE === 'true', CONNECTION: {
CONTACTS: process.env?.DATABASE_SAVE_DATA_CONTACTS === 'true', URI: process.env.DATABASE_CONNECTION_URI || '',
CHATS: process.env?.DATABASE_SAVE_DATA_CHATS === 'true', DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution',
}, DB_PREFIX_FINAL_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_FINAL_NAME || '-api',
}, },
REDIS: { ENABLED: process.env?.DATABASE_ENABLED === 'true',
ENABLED: process.env?.REDIS_ENABLED === 'true', SAVE_DATA: {
URI: process.env.REDIS_URI || '', INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true',
PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution', NEW_MESSAGE: process.env?.DATABASE_SAVE_DATA_NEW_MESSAGE === 'true',
}, MESSAGE_UPDATE: process.env?.DATABASE_SAVE_MESSAGE_UPDATE === 'true',
RABBITMQ: { CONTACTS: process.env?.DATABASE_SAVE_DATA_CONTACTS === 'true',
ENABLED: process.env?.RABBITMQ_ENABLED === 'true', CHATS: process.env?.DATABASE_SAVE_DATA_CHATS === 'true',
URI: process.env.RABBITMQ_URI || '', },
}, },
SQS: { REDIS: {
ENABLED: process.env?.SQS_ENABLED === 'true', ENABLED: process.env?.REDIS_ENABLED === 'true',
ACCESS_KEY_ID: process.env.SQS_ACCESS_KEY_ID || '', URI: process.env.REDIS_URI || '',
SECRET_ACCESS_KEY: process.env.SQS_SECRET_ACCESS_KEY || '', PREFIX_KEY: process.env.REDIS_PREFIX_KEY || 'evolution',
ACCOUNT_ID: process.env.SQS_ACCOUNT_ID || '', },
REGION: process.env.SQS_REGION || '', RABBITMQ: {
}, ENABLED: process.env?.RABBITMQ_ENABLED === 'true',
WEBSOCKET: { URI: process.env.RABBITMQ_URI || '',
ENABLED: process.env?.WEBSOCKET_ENABLED === 'true', },
}, SQS: {
LOG: { ENABLED: process.env?.SQS_ENABLED === 'true',
LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [ ACCESS_KEY_ID: process.env.SQS_ACCESS_KEY_ID || '',
'ERROR', SECRET_ACCESS_KEY: process.env.SQS_SECRET_ACCESS_KEY || '',
'WARN', ACCOUNT_ID: process.env.SQS_ACCOUNT_ID || '',
'DEBUG', REGION: process.env.SQS_REGION || '',
'INFO', },
'LOG',
'VERBOSE', OPENAI: {
'DARK', CHAVE: process.env?.OPENAI_ENABLED || '',
'WEBHOOKS', ENABLED: process.env?.OPENAI_ENABLED === 'true',
], URI: process.env.OPENAI_URI || '',
COLOR: process.env?.LOG_COLOR === 'true', },
BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error', WEBSOCKET: {
}, ENABLED: process.env?.WEBSOCKET_ENABLED === 'true',
DEL_INSTANCE: isBooleanString(process.env?.DEL_INSTANCE) },
? process.env.DEL_INSTANCE === 'true' LOG: {
: Number.parseInt(process.env.DEL_INSTANCE) || false, LEVEL: (process.env?.LOG_LEVEL.split(',') as LogLevel[]) || [
WEBHOOK: { 'ERROR',
GLOBAL: { 'WARN',
URL: process.env?.WEBHOOK_GLOBAL_URL || '', 'DEBUG',
ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true', 'INFO',
WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true', 'LOG',
}, 'VERBOSE',
EVENTS: { 'DARK',
APPLICATION_STARTUP: process.env?.WEBHOOK_EVENTS_APPLICATION_STARTUP === 'true', 'WEBHOOKS',
QRCODE_UPDATED: process.env?.WEBHOOK_EVENTS_QRCODE_UPDATED === 'true', ],
MESSAGES_SET: process.env?.WEBHOOK_EVENTS_MESSAGES_SET === 'true', COLOR: process.env?.LOG_COLOR === 'true',
MESSAGES_UPSERT: process.env?.WEBHOOK_EVENTS_MESSAGES_UPSERT === 'true', BAILEYS: (process.env?.LOG_BAILEYS as LogBaileys) || 'error',
MESSAGES_UPDATE: process.env?.WEBHOOK_EVENTS_MESSAGES_UPDATE === 'true', },
MESSAGES_DELETE: process.env?.WEBHOOK_EVENTS_MESSAGES_DELETE === 'true', DEL_INSTANCE: isBooleanString(process.env?.DEL_INSTANCE)
SEND_MESSAGE: process.env?.WEBHOOK_EVENTS_SEND_MESSAGE === 'true', ? process.env.DEL_INSTANCE === 'true'
CONTACTS_SET: process.env?.WEBHOOK_EVENTS_CONTACTS_SET === 'true', : Number.parseInt(process.env.DEL_INSTANCE) || false,
CONTACTS_UPDATE: process.env?.WEBHOOK_EVENTS_CONTACTS_UPDATE === 'true', WEBHOOK: {
CONTACTS_UPSERT: process.env?.WEBHOOK_EVENTS_CONTACTS_UPSERT === 'true', GLOBAL: {
PRESENCE_UPDATE: process.env?.WEBHOOK_EVENTS_PRESENCE_UPDATE === 'true', URL: process.env?.WEBHOOK_GLOBAL_URL || '',
CHATS_SET: process.env?.WEBHOOK_EVENTS_CHATS_SET === 'true', ENABLED: process.env?.WEBHOOK_GLOBAL_ENABLED === 'true',
CHATS_UPDATE: process.env?.WEBHOOK_EVENTS_CHATS_UPDATE === 'true', WEBHOOK_BY_EVENTS: process.env?.WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS === 'true',
CHATS_UPSERT: process.env?.WEBHOOK_EVENTS_CHATS_UPSERT === 'true', },
CHATS_DELETE: process.env?.WEBHOOK_EVENTS_CHATS_DELETE === 'true', EVENTS: {
CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true', APPLICATION_STARTUP: process.env?.WEBHOOK_EVENTS_APPLICATION_STARTUP === 'true',
GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true', QRCODE_UPDATED: process.env?.WEBHOOK_EVENTS_QRCODE_UPDATED === 'true',
GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true', MESSAGES_SET: process.env?.WEBHOOK_EVENTS_MESSAGES_SET === 'true',
GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true', MESSAGES_UPSERT: process.env?.WEBHOOK_EVENTS_MESSAGES_UPSERT === 'true',
CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true', MESSAGES_UPDATE: process.env?.WEBHOOK_EVENTS_MESSAGES_UPDATE === 'true',
NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true', MESSAGES_DELETE: process.env?.WEBHOOK_EVENTS_MESSAGES_DELETE === 'true',
TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true', SEND_MESSAGE: process.env?.WEBHOOK_EVENTS_SEND_MESSAGE === 'true',
TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true', CONTACTS_SET: process.env?.WEBHOOK_EVENTS_CONTACTS_SET === 'true',
CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true', CONTACTS_UPDATE: process.env?.WEBHOOK_EVENTS_CONTACTS_UPDATE === 'true',
ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true', CONTACTS_UPSERT: process.env?.WEBHOOK_EVENTS_CONTACTS_UPSERT === 'true',
ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '', PRESENCE_UPDATE: process.env?.WEBHOOK_EVENTS_PRESENCE_UPDATE === 'true',
}, CHATS_SET: process.env?.WEBHOOK_EVENTS_CHATS_SET === 'true',
}, CHATS_UPDATE: process.env?.WEBHOOK_EVENTS_CHATS_UPDATE === 'true',
CONFIG_SESSION_PHONE: { CHATS_UPSERT: process.env?.WEBHOOK_EVENTS_CHATS_UPSERT === 'true',
CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API', CHATS_DELETE: process.env?.WEBHOOK_EVENTS_CHATS_DELETE === 'true',
NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome', CONNECTION_UPDATE: process.env?.WEBHOOK_EVENTS_CONNECTION_UPDATE === 'true',
}, GROUPS_UPSERT: process.env?.WEBHOOK_EVENTS_GROUPS_UPSERT === 'true',
QRCODE: { GROUP_UPDATE: process.env?.WEBHOOK_EVENTS_GROUPS_UPDATE === 'true',
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30, GROUP_PARTICIPANTS_UPDATE: process.env?.WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE === 'true',
COLOR: process.env.QRCODE_COLOR || '#198754', CALL: process.env?.WEBHOOK_EVENTS_CALL === 'true',
}, NEW_JWT_TOKEN: process.env?.WEBHOOK_EVENTS_NEW_JWT_TOKEN === 'true',
TYPEBOT: { TYPEBOT_START: process.env?.WEBHOOK_EVENTS_TYPEBOT_START === 'true',
API_VERSION: process.env?.TYPEBOT_API_VERSION || 'v1', TYPEBOT_CHANGE_STATUS: process.env?.WEBHOOK_EVENTS_TYPEBOT_CHANGE_STATUS === 'true',
}, CHAMA_AI_ACTION: process.env?.WEBHOOK_EVENTS_CHAMA_AI_ACTION === 'true',
AUTHENTICATION: { ERRORS: process.env?.WEBHOOK_EVENTS_ERRORS === 'true',
TYPE: process.env.AUTHENTICATION_TYPE as 'apikey', ERRORS_WEBHOOK: process.env?.WEBHOOK_EVENTS_ERRORS_WEBHOOK || '',
API_KEY: { },
KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ', },
}, CONFIG_SESSION_PHONE: {
EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true', CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API',
JWT: { NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome',
EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN) },
? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN) QRCODE: {
: 3600, LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`', COLOR: process.env.QRCODE_COLOR || '#198754',
}, },
}, TYPEBOT: {
CHATWOOT: { API_VERSION: process.env?.TYPEBOT_API_VERSION || 'v1',
USE_REPLY_ID: process.env?.USE_REPLY_ID === 'true', },
}, AUTHENTICATION: {
}; TYPE: process.env.AUTHENTICATION_TYPE as 'apikey',
} API_KEY: {
} KEY: process.env.AUTHENTICATION_API_KEY || 'BQYHJGJHJ',
},
export const configService = new ConfigService(); EXPOSE_IN_FETCH_INSTANCES: process.env?.AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES === 'true',
JWT: {
EXPIRIN_IN: Number.isInteger(process.env?.AUTHENTICATION_JWT_EXPIRIN_IN)
? Number.parseInt(process.env.AUTHENTICATION_JWT_EXPIRIN_IN)
: 3600,
SECRET: process.env.AUTHENTICATION_JWT_SECRET || 'L=0YWt]b2w[WF>#>:&E`',
},
},
CHATWOOT: {
USE_REPLY_ID: process.env?.USE_REPLY_ID === 'true',
},
};
}
}
export const configService = new ConfigService();

46
src/config/error.config.ts Normal file → Executable file
View File

@ -1,23 +1,23 @@
import { Logger } from './logger.config'; import { Logger } from './logger.config';
export function onUnexpectedError() { export function onUnexpectedError() {
process.on('uncaughtException', (error, origin) => { process.on('uncaughtException', (error, origin) => {
const logger = new Logger('uncaughtException'); const logger = new Logger('uncaughtException');
logger.error({ logger.error({
origin, origin,
stderr: process.stderr.fd, stderr: process.stderr.fd,
error, error,
}); });
// process.exit(1); process.exit(1);
}); });
process.on('unhandledRejection', (error, origin) => { process.on('unhandledRejection', (error, origin) => {
const logger = new Logger('unhandledRejection'); const logger = new Logger('unhandledRejection');
logger.error({ logger.error({
origin, origin,
stderr: process.stderr.fd, stderr: process.stderr.fd,
error, error,
}); });
// process.exit(1); process.exit(1);
}); });
} }

14
src/config/event.config.ts Normal file → Executable file
View File

@ -1,7 +1,7 @@
import EventEmitter2 from 'eventemitter2'; import EventEmitter2 from 'eventemitter2';
export const eventEmitter = new EventEmitter2({ export const eventEmitter = new EventEmitter2({
delimiter: '.', delimiter: '.',
newListener: false, newListener: false,
ignoreErrors: false, ignoreErrors: false,
}); });

282
src/config/logger.config.ts Normal file → Executable file
View File

@ -1,141 +1,141 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import fs from 'fs'; import fs from 'fs';
import { configService, Log } from './env.config'; import { configService, Log } from './env.config';
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')); const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const formatDateLog = (timestamp: number) => const formatDateLog = (timestamp: number) =>
dayjs(timestamp) dayjs(timestamp)
.toDate() .toDate()
.toString() .toString()
.replace(/\sGMT.+/, ''); .replace(/\sGMT.+/, '');
enum Color { enum Color {
LOG = '\x1b[32m', LOG = '\x1b[32m',
INFO = '\x1b[34m', INFO = '\x1b[34m',
WARN = '\x1b[33m', WARN = '\x1b[33m',
ERROR = '\x1b[31m', ERROR = '\x1b[31m',
DEBUG = '\x1b[36m', DEBUG = '\x1b[36m',
VERBOSE = '\x1b[37m', VERBOSE = '\x1b[37m',
DARK = '\x1b[30m', DARK = '\x1b[30m',
} }
enum Command { enum Command {
RESET = '\x1b[0m', RESET = '\x1b[0m',
BRIGHT = '\x1b[1m', BRIGHT = '\x1b[1m',
UNDERSCORE = '\x1b[4m', UNDERSCORE = '\x1b[4m',
} }
enum Level { enum Level {
LOG = Color.LOG + '%s' + Command.RESET, LOG = Color.LOG + '%s' + Command.RESET,
DARK = Color.DARK + '%s' + Command.RESET, DARK = Color.DARK + '%s' + Command.RESET,
INFO = Color.INFO + '%s' + Command.RESET, INFO = Color.INFO + '%s' + Command.RESET,
WARN = Color.WARN + '%s' + Command.RESET, WARN = Color.WARN + '%s' + Command.RESET,
ERROR = Color.ERROR + '%s' + Command.RESET, ERROR = Color.ERROR + '%s' + Command.RESET,
DEBUG = Color.DEBUG + '%s' + Command.RESET, DEBUG = Color.DEBUG + '%s' + Command.RESET,
VERBOSE = Color.VERBOSE + '%s' + Command.RESET, VERBOSE = Color.VERBOSE + '%s' + Command.RESET,
} }
enum Type { enum Type {
LOG = 'LOG', LOG = 'LOG',
WARN = 'WARN', WARN = 'WARN',
INFO = 'INFO', INFO = 'INFO',
DARK = 'DARK', DARK = 'DARK',
ERROR = 'ERROR', ERROR = 'ERROR',
DEBUG = 'DEBUG', DEBUG = 'DEBUG',
VERBOSE = 'VERBOSE', VERBOSE = 'VERBOSE',
} }
enum Background { enum Background {
LOG = '\x1b[42m', LOG = '\x1b[42m',
INFO = '\x1b[44m', INFO = '\x1b[44m',
WARN = '\x1b[43m', WARN = '\x1b[43m',
DARK = '\x1b[40m', DARK = '\x1b[40m',
ERROR = '\x1b[41m', ERROR = '\x1b[41m',
DEBUG = '\x1b[46m', DEBUG = '\x1b[46m',
VERBOSE = '\x1b[47m', VERBOSE = '\x1b[47m',
} }
export class Logger { export class Logger {
private readonly configService = configService; private readonly configService = configService;
constructor(private context = 'Logger') {} constructor(private context = 'Logger') {}
public setContext(value: string) { public setContext(value: string) {
this.context = value; this.context = value;
} }
private console(value: any, type: Type) { private console(value: any, type: Type) {
const types: Type[] = []; const types: Type[] = [];
this.configService.get<Log>('LOG').LEVEL.forEach((level) => types.push(Type[level])); this.configService.get<Log>('LOG').LEVEL.forEach((level) => types.push(Type[level]));
const typeValue = typeof value; const typeValue = typeof value;
if (types.includes(type)) { if (types.includes(type)) {
if (configService.get<Log>('LOG').COLOR) { if (configService.get<Log>('LOG').COLOR) {
console.log( console.log(
/*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type], /*Command.UNDERSCORE +*/ Command.BRIGHT + Level[type],
'[Evolution API]', '[Evolution API]',
Command.BRIGHT + Color[type], Command.BRIGHT + Color[type],
`v${packageJson.version}`, `v${packageJson.version}`,
Command.BRIGHT + Color[type], Command.BRIGHT + Color[type],
process.pid.toString(), process.pid.toString(),
Command.RESET, Command.RESET,
Command.BRIGHT + Color[type], Command.BRIGHT + Color[type],
'-', '-',
Command.BRIGHT + Color.VERBOSE, Command.BRIGHT + Color.VERBOSE,
`${formatDateLog(Date.now())} `, `${formatDateLog(Date.now())} `,
Command.RESET, Command.RESET,
Color[type] + Background[type] + Command.BRIGHT, Color[type] + Background[type] + Command.BRIGHT,
`${type} ` + Command.RESET, `${type} ` + Command.RESET,
Color.WARN + Command.BRIGHT, Color.WARN + Command.BRIGHT,
`[${this.context}]` + Command.RESET, `[${this.context}]` + Command.RESET,
Color[type] + Command.BRIGHT, Color[type] + Command.BRIGHT,
`[${typeValue}]` + Command.RESET, `[${typeValue}]` + Command.RESET,
Color[type], Color[type],
typeValue !== 'object' ? value : '', typeValue !== 'object' ? value : '',
Command.RESET, Command.RESET,
); );
typeValue === 'object' ? console.log(/*Level.DARK,*/ value, '\n') : ''; typeValue === 'object' ? console.log(/*Level.DARK,*/ value, '\n') : '';
} else { } else {
console.log( console.log(
'[Evolution API]', '[Evolution API]',
process.pid.toString(), process.pid.toString(),
'-', '-',
`${formatDateLog(Date.now())} `, `${formatDateLog(Date.now())} `,
`${type} `, `${type} `,
`[${this.context}]`, `[${this.context}]`,
`[${typeValue}]`, `[${typeValue}]`,
value, value,
); );
} }
} }
} }
public log(value: any) { public log(value: any) {
this.console(value, Type.LOG); this.console(value, Type.LOG);
} }
public info(value: any) { public info(value: any) {
this.console(value, Type.INFO); this.console(value, Type.INFO);
} }
public warn(value: any) { public warn(value: any) {
this.console(value, Type.WARN); this.console(value, Type.WARN);
} }
public error(value: any) { public error(value: any) {
this.console(value, Type.ERROR); this.console(value, Type.ERROR);
} }
public verbose(value: any) { public verbose(value: any) {
this.console(value, Type.VERBOSE); this.console(value, Type.VERBOSE);
} }
public debug(value: any) { public debug(value: any) {
this.console(value, Type.DEBUG); this.console(value, Type.DEBUG);
} }
public dark(value: any) { public dark(value: any) {
this.console(value, Type.DARK); this.console(value, Type.DARK);
} }
} }

14
src/config/path.config.ts Normal file → Executable file
View File

@ -1,7 +1,7 @@
import { join } from 'path'; import { join } from 'path';
export const ROOT_DIR = process.cwd(); export const ROOT_DIR = process.cwd();
export const INSTANCE_DIR = join(ROOT_DIR, 'instances'); export const INSTANCE_DIR = join(ROOT_DIR, 'instances');
export const SRC_DIR = join(ROOT_DIR, 'src'); export const SRC_DIR = join(ROOT_DIR, 'src');
export const AUTH_DIR = join(ROOT_DIR, 'store', 'auth'); export const AUTH_DIR = join(ROOT_DIR, 'store', 'auth');
export const STORE_DIR = join(ROOT_DIR, 'store'); export const STORE_DIR = join(ROOT_DIR, 'store');

349
src/dev-env.yml Normal file → Executable file
View File

@ -1,170 +1,179 @@
# ⚠️ # ⚠️
# ⚠️ ALL SETTINGS DEFINED IN THIS FILE ARE APPLIED TO ALL INSTANCES. # ⚠️ ALL SETTINGS DEFINED IN THIS FILE ARE APPLIED TO ALL INSTANCES.
# ⚠️ # ⚠️
# ⚠️ RENAME THIS FILE TO env.yml # ⚠️ RENAME THIS FILE TO env.yml
# Choose the server type for the application # Choose the server type for the application
SERVER: SERVER:
TYPE: http # https TYPE: http # https
PORT: 8080 # 443 PORT: 3333 # 443
URL: localhost URL: 127.0.0.1
CORS: CORS:
ORIGIN: ORIGIN:
- "*" - "*"
# - yourdomain.com # - yourdomain.com
METHODS: METHODS:
- POST - POST
- GET - GET
- PUT - PUT
- DELETE - DELETE
CREDENTIALS: true CREDENTIALS: true
# Install ssl certificate and replace string <domain> with domain name # Install ssl certificate and replace string <domain> with domain name
# Access: https://certbot.eff.org/instructions?ws=other&os=ubuntufocal # Access: https://certbot.eff.org/instructions?ws=other&os=ubuntufocal
SSL_CONF: SSL_CONF:
PRIVKEY: /etc/letsencrypt/live/<domain>/privkey.pem PRIVKEY: /etc/letsencrypt/live/<domain>/privkey.pem
FULLCHAIN: /etc/letsencrypt/live/<domain>/fullchain.pem FULLCHAIN: /etc/letsencrypt/live/<domain>/fullchain.pem
# Determine the logs to be displayed # Determine the logs to be displayed
LOG: LOG:
LEVEL: LEVEL:
- ERROR - ERROR
- WARN - WARN
- DEBUG - DEBUG
- INFO - INFO
- LOG - LOG
- VERBOSE - VERBOSE
- DARK - DARK
- WEBHOOKS - WEBHOOKS
COLOR: true COLOR: true
BAILEYS: error # fatal | error | warn | info | debug | trace BAILEYS: error # fatal | error | warn | info | debug | trace
# Determine how long the instance should be deleted from memory in case of no connection. # Determine how long the instance should be deleted from memory in case of no connection.
# Default time: 5 minutes # Default time: 5 minutes
# If you don't even want an expiration, enter the value false # If you don't even want an expiration, enter the value false
DEL_INSTANCE: false # or false DEL_INSTANCE: false # or false
# Temporary data storage # Temporary data storage
STORE: STORE:
MESSAGES: true MESSAGES: false
MESSAGE_UP: true MESSAGE_UP: false
CONTACTS: true CONTACTS: true
CHATS: true CHATS: true
CLEAN_STORE: CLEAN_STORE:
CLEANING_INTERVAL: 7200 # 7200 seconds === 2h CLEANING_INTERVAL: 7200 # 7200 seconds === 2h
MESSAGES: true MESSAGES: true
MESSAGE_UP: true MESSAGE_UP: true
CONTACTS: true CONTACTS: true
CHATS: true CHATS: true
# Permanent data storage # Permanent data storage
DATABASE: DATABASE:
ENABLED: false ENABLED: true
CONNECTION: CONNECTION:
URI: "mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true" URI: "mongodb://root:root@localhost:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true"
DB_PREFIX_NAME: evolution
# Choose the data you want to save in the application's database or store DB_PREFIX_NAME: whatsapp
SAVE_DATA: DB_PREFIX_FINAL_NAME: "-api"
INSTANCE: false DB_PREFIX_FINAL_NAME_VENOM: "-venom"
NEW_MESSAGE: false # Choose the data you want to save in the application's database or store
MESSAGE_UPDATE: false SAVE_DATA:
CONTACTS: false INSTANCE: true
CHATS: false NEW_MESSAGE: false
MESSAGE_UPDATE: false
REDIS: CONTACTS: true
ENABLED: false CHATS: true
URI: "redis://localhost:6379"
PREFIX_KEY: "evolution" REDIS:
ENABLED: false
RABBITMQ: URI: "redis://localhost:6379"
ENABLED: false PREFIX_KEY: "evolution"
URI: "amqp://guest:guest@localhost:5672"
RABBITMQ:
SQS: ENABLED: false
ENABLED: true URI: "amqp://guest:guest@localhost:5672"
ACCESS_KEY_ID: ""
SECRET_ACCESS_KEY: "" OPENAI:
ACCOUNT_ID: "" CHAVE: ""
REGION: "us-east-1" ENABLED: false
PROMPTS: false
WEBSOCKET: URI: ""
ENABLED: false
SQS:
# Global Webhook Settings ENABLED: false
# Each instance's Webhook URL and events will be requested at the time it is created ACCESS_KEY_ID: ""
WEBHOOK: SECRET_ACCESS_KEY: ""
# Define a global webhook that will listen for enabled events from all instances ACCOUNT_ID: ""
GLOBAL: REGION: "us-east-1"
URL: <url>
ENABLED: false WEBSOCKET:
# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event ENABLED: false
WEBHOOK_BY_EVENTS: false
# Automatically maps webhook paths TYPEBOT:
# Set the events you want to hear API_VERSION: 'v1' # v1 | v2
EVENTS:
APPLICATION_STARTUP: false # Global Webhook Settings
QRCODE_UPDATED: true # Each instance's Webhook URL and events will be requested at the time it is created
MESSAGES_SET: true WEBHOOK:
MESSAGES_UPSERT: true # Define a global webhook that will listen for enabled events from all instances
MESSAGES_UPDATE: true GLOBAL:
MESSAGES_DELETE: true URL: ""
SEND_MESSAGE: true ENABLED: false
CONTACTS_SET: true # With this option activated, you work with a url per webhook event, respecting the global url and the name of each event
CONTACTS_UPSERT: true WEBHOOK_BY_EVENTS: false
CONTACTS_UPDATE: true # Automatically maps webhook paths
PRESENCE_UPDATE: true # Set the events you want to hear
CHATS_SET: true EVENTS:
CHATS_UPSERT: true APPLICATION_STARTUP: false
CHATS_UPDATE: true QRCODE_UPDATED: true
CHATS_DELETE: true MESSAGES_SET: true
GROUPS_UPSERT: true MESSAGES_UPSERT: true
GROUP_UPDATE: true MESSAGES_UPDATE: true
GROUP_PARTICIPANTS_UPDATE: true MESSAGES_DELETE: true
CONNECTION_UPDATE: true SEND_MESSAGE: true
CALL: true CONTACTS_SET: true
# This event fires every time a new token is requested via the refresh route CONTACTS_UPSERT: true
NEW_JWT_TOKEN: false CONTACTS_UPDATE: true
# This events is used with Typebot PRESENCE_UPDATE: true
TYPEBOT_START: false CHATS_SET: true
TYPEBOT_CHANGE_STATUS: false CHATS_UPSERT: true
# This event is used with Chama AI CHATS_UPDATE: true
CHAMA_AI_ACTION: false CHATS_DELETE: true
# This event is used to send errors to the webhook GROUPS_UPSERT: true
ERRORS: false GROUP_UPDATE: true
ERRORS_WEBHOOK: <url> GROUP_PARTICIPANTS_UPDATE: true
CONNECTION_UPDATE: true
CONFIG_SESSION_PHONE: CALL: true
# Name that will be displayed on smartphone connection # This event fires every time a new token is requested via the refresh route
CLIENT: "Evolution API" NEW_JWT_TOKEN: false
NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari # This events is used with Typebot
TYPEBOT_START: false
# Set qrcode display limit TYPEBOT_CHANGE_STATUS: false
QRCODE: # This event is used with Chama AI
LIMIT: 30 CHAMA_AI_ACTION: false
COLOR: "#198754" # This event is used to send errors to the webhook
ERRORS: false
TYPEBOT: ERRORS_WEBHOOK: ""
API_VERSION: 'v1' # v1 | v2
CONFIG_SESSION_PHONE:
# Defines an authentication type for the api # Name that will be displayed on smartphone connection
# We recommend using the apikey because it will allow you to use a custom token, CLIENT: "Evolution API"
# if you use jwt, a random token will be generated and may be expired and you will have to generate a new token NAME: Chrome # Chrome | Firefox | Edge | Opera | Safari
AUTHENTICATION:
TYPE: apikey # jwt or apikey # Set qrcode display limit
# Define a global apikey to access all instances QRCODE:
API_KEY: LIMIT: 30
# OBS: This key must be inserted in the request header to create an instance. COLOR: "#198754"
KEY: B6D711FCDE4D4FD5936544120E713976
# Expose the api key on return from fetch instances # Defines an authentication type for the api
EXPOSE_IN_FETCH_INSTANCES: true # We recommend using the apikey because it will allow you to use a custom token,
# Set the secret key to encrypt and decrypt your token and its expiration time. # if you use jwt, a random token will be generated and may be expired and you will have to generate a new token
JWT: AUTHENTICATION:
EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires TYPE: apikey # jwt or apikey
SECRET: L=0YWt]b2w[WF>#>:&E` # Define a global apikey to access all instances
API_KEY:
# Configure to chatwoot # OBS: This key must be inserted in the request header to create an instance.
CHATWOOT: KEY: B6D711FCDE4D4FD5936544120E713976
USE_REPLY_ID: false # Expose the api key on return from fetch instances
EXPOSE_IN_FETCH_INSTANCES: true
# Set the secret key to encrypt and decrypt your token and its expiration time.
JWT:
EXPIRIN_IN: 0 # seconds - 3600s === 1h | zero (0) - never expires
SECRET: L=0YWt]b2w[WF>#>:&E`
# Configure to chatwoot
CHATWOOT:
USE_REPLY_ID: false

34
src/docs/swagger.conf.ts Normal file → Executable file
View File

@ -1,17 +1,17 @@
import { Router } from 'express'; import { Router } from 'express';
import { join } from 'path'; import { join } from 'path';
import swaggerUi from 'swagger-ui-express'; import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs'; import YAML from 'yamljs';
const document = YAML.load(join(process.cwd(), 'src', 'docs', 'swagger.yaml')); const document = YAML.load(join(process.cwd(), 'src', 'docs', 'swagger.yaml'));
const router = Router(); const router = Router();
export const swaggerRouter = router.use('/docs', swaggerUi.serve).get( export const swaggerRouter = router.use('/docs', swaggerUi.serve).get(
'/docs', '/docs',
swaggerUi.setup(document, { swaggerUi.setup(document, {
customCssUrl: '/css/dark-theme-swagger.css', customCssUrl: '/css/dark-theme-swagger.css',
customSiteTitle: 'Evolution API', customSiteTitle: 'Evolution API',
customfavIcon: '/images/logo.svg', customfavIcon: '/images/logo.svg',
}), }),
); );

5194
src/docs/swagger.yaml Normal file → Executable file

File diff suppressed because it is too large Load Diff

22
src/exceptions/400.exception.ts Normal file → Executable file
View File

@ -1,11 +1,11 @@
import { HttpStatus } from '../whatsapp/routers/index.router'; import { HttpStatus } from '../whatsapp/routers/index.router';
export class BadRequestException { export class BadRequestException {
constructor(...objectError: any[]) { constructor(...objectError: any[]) {
throw { throw {
status: HttpStatus.BAD_REQUEST, status: HttpStatus.BAD_REQUEST,
error: 'Bad Request', error: 'Bad Request',
message: objectError.length > 0 ? objectError : undefined, message: objectError.length > 0 ? objectError : undefined,
}; };
} }
} }

22
src/exceptions/401.exception.ts Normal file → Executable file
View File

@ -1,11 +1,11 @@
import { HttpStatus } from '../whatsapp/routers/index.router'; import { HttpStatus } from '../whatsapp/routers/index.router';
export class UnauthorizedException { export class UnauthorizedException {
constructor(...objectError: any[]) { constructor(...objectError: any[]) {
throw { throw {
status: HttpStatus.UNAUTHORIZED, status: HttpStatus.UNAUTHORIZED,
error: 'Unauthorized', error: 'Unauthorized',
message: objectError.length > 0 ? objectError : 'Unauthorized', message: objectError.length > 0 ? objectError : 'Unauthorized',
}; };
} }
} }

22
src/exceptions/403.exception.ts Normal file → Executable file
View File

@ -1,11 +1,11 @@
import { HttpStatus } from '../whatsapp/routers/index.router'; import { HttpStatus } from '../whatsapp/routers/index.router';
export class ForbiddenException { export class ForbiddenException {
constructor(...objectError: any[]) { constructor(...objectError: any[]) {
throw { throw {
status: HttpStatus.FORBIDDEN, status: HttpStatus.FORBIDDEN,
error: 'Forbidden', error: 'Forbidden',
message: objectError.length > 0 ? objectError : undefined, message: objectError.length > 0 ? objectError : undefined,
}; };
} }
} }

22
src/exceptions/404.exception.ts Normal file → Executable file
View File

@ -1,11 +1,11 @@
import { HttpStatus } from '../whatsapp/routers/index.router'; import { HttpStatus } from '../whatsapp/routers/index.router';
export class NotFoundException { export class NotFoundException {
constructor(...objectError: any[]) { constructor(...objectError: any[]) {
throw { throw {
status: HttpStatus.NOT_FOUND, status: HttpStatus.NOT_FOUND,
error: 'Not Found', error: 'Not Found',
message: objectError.length > 0 ? objectError : undefined, message: objectError.length > 0 ? objectError : undefined,
}; };
} }
} }

22
src/exceptions/500.exception.ts Normal file → Executable file
View File

@ -1,11 +1,11 @@
import { HttpStatus } from '../whatsapp/routers/index.router'; import { HttpStatus } from '../whatsapp/routers/index.router';
export class InternalServerErrorException { export class InternalServerErrorException {
constructor(...objectError: any[]) { constructor(...objectError: any[]) {
throw { throw {
status: HttpStatus.INTERNAL_SERVER_ERROR, status: HttpStatus.INTERNAL_SERVER_ERROR,
error: 'Internal Server Error', error: 'Internal Server Error',
message: objectError.length > 0 ? objectError : undefined, message: objectError.length > 0 ? objectError : undefined,
}; };
} }
} }

10
src/exceptions/index.ts Normal file → Executable file
View File

@ -1,5 +1,5 @@
export * from './400.exception'; export * from './400.exception';
export * from './401.exception'; export * from './401.exception';
export * from './403.exception'; export * from './403.exception';
export * from './404.exception'; export * from './404.exception';
export * from './500.exception'; export * from './500.exception';

200
src/libs/amqp.server.ts Normal file → Executable file
View File

@ -1,100 +1,100 @@
import * as amqp from 'amqplib/callback_api'; import * as amqp from 'amqplib/callback_api';
import { configService, Rabbitmq } from '../config/env.config'; import { configService, Rabbitmq, Openai } 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');
let amqpChannel: amqp.Channel | null = null; let amqpChannel: amqp.Channel | null = null;
export const initAMQP = () => { export const initAMQP = () => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
const uri = configService.get<Rabbitmq>('RABBITMQ').URI; const uri = configService.get<Rabbitmq>('RABBITMQ').URI;
amqp.connect(uri, (error, connection) => { amqp.connect(uri, (error, connection) => {
if (error) { if (error) {
reject(error); reject(error);
return; return;
} }
connection.createChannel((channelError, channel) => { connection.createChannel((channelError, channel) => {
if (channelError) { if (channelError) {
reject(channelError); reject(channelError);
return; return;
} }
const exchangeName = 'evolution_exchange'; const exchangeName = 'evolution_exchange';
channel.assertExchange(exchangeName, 'topic', { channel.assertExchange(exchangeName, 'topic', {
durable: true, durable: true,
autoDelete: false, autoDelete: false,
}); });
amqpChannel = channel; amqpChannel = channel;
logger.info('AMQP initialized'); logger.info('AMQP initialized');
resolve(); resolve();
}); });
}); });
}); });
}; };
export const getAMQP = (): amqp.Channel | null => { export const getAMQP = (): amqp.Channel | null => {
return amqpChannel; return amqpChannel;
}; };
export const initQueues = (instanceName: string, events: string[]) => { export const initQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return; if (!events || !events.length) return;
const queues = events.map((event) => { const queues = events.map((event) => {
return `${event.replace(/_/g, '.').toLowerCase()}`; return `${event.replace(/_/g, '.').toLowerCase()}`;
}); });
queues.forEach((event) => { queues.forEach((event) => {
const amqp = getAMQP(); const amqp = getAMQP();
const exchangeName = instanceName ?? 'evolution_exchange'; const exchangeName = instanceName ?? 'evolution_exchange';
amqp.assertExchange(exchangeName, 'topic', { amqp.assertExchange(exchangeName, 'topic', {
durable: true, durable: true,
autoDelete: false, autoDelete: false,
}); });
const queueName = `${instanceName}.${event}`; const queueName = `${instanceName}.${event}`;
amqp.assertQueue(queueName, { amqp.assertQueue(queueName, {
durable: true, durable: true,
autoDelete: false, autoDelete: false,
arguments: { arguments: {
'x-queue-type': 'quorum', 'x-queue-type': 'quorum',
}, },
}); });
amqp.bindQueue(queueName, exchangeName, event); amqp.bindQueue(queueName, exchangeName, event);
}); });
}; };
export const removeQueues = (instanceName: string, events: string[]) => { export const removeQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return; if (!events || !events.length) return;
const channel = getAMQP(); const channel = getAMQP();
const queues = events.map((event) => { const queues = events.map((event) => {
return `${event.replace(/_/g, '.').toLowerCase()}`; return `${event.replace(/_/g, '.').toLowerCase()}`;
}); });
const exchangeName = instanceName ?? 'evolution_exchange'; const exchangeName = instanceName ?? 'evolution_exchange';
queues.forEach((event) => { queues.forEach((event) => {
const amqp = getAMQP(); const amqp = getAMQP();
amqp.assertExchange(exchangeName, 'topic', { amqp.assertExchange(exchangeName, 'topic', {
durable: true, durable: true,
autoDelete: false, autoDelete: false,
}); });
const queueName = `${instanceName}.${event}`; const queueName = `${instanceName}.${event}`;
amqp.deleteQueue(queueName); amqp.deleteQueue(queueName);
}); });
channel.deleteExchange(exchangeName); channel.deleteExchange(exchangeName);
}; };

51
src/libs/db.connect.ts Normal file → Executable file
View File

@ -1,25 +1,26 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import { configService, Database } from '../config/env.config'; import { configService, Database } from '../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../config/logger.config';
const logger = new Logger('MongoDB'); const logger = new Logger('MongoDB');
const db = configService.get<Database>('DATABASE'); const db = configService.get<Database>('DATABASE');
export const dbserver = (() => { export const dbserver = (() => {
if (db.ENABLED) { if (db.ENABLED) {
logger.verbose('connecting'); logger.verbose('connecting');
const dbs = mongoose.createConnection(db.CONNECTION.URI, { const dbs = mongoose.createConnection(db.CONNECTION.URI, {
dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api',
}); dbName: db.CONNECTION.DB_PREFIX_NAME + db.CONNECTION.DB_PREFIX_FINAL_NAME + '-config',
logger.verbose('connected in ' + db.CONNECTION.URI); });
logger.info('ON - dbName: ' + dbs['$dbName']); logger.verbose('connected in ' + db.CONNECTION.URI);
logger.info('ON - dbName: ' + dbs['$dbName']);
process.on('beforeExit', () => {
logger.verbose('instance destroyed'); process.on('beforeExit', () => {
dbserver.destroy(true, (error) => logger.error(error)); logger.verbose('instance destroyed');
}); dbserver.destroy(true, (error) => logger.error(error));
});
return dbs;
} return dbs;
})(); }
})();

34
src/libs/openai.ts Executable file
View File

@ -0,0 +1,34 @@
import { Configuration, OpenAIApi } from "openai"
import { config } from "../config"
const configuration = new Configuration({
apiKey: config.openAI.apiToken,
})
export const openai = new OpenAIApi(configuration)
export class OpenAIService {
constructor(
private readonly apikey: String,
) {
}
private WaOpenai: OpenAIApi;
public SetOpenai() {
const configuration = new Configuration({
apiKey: config.openAI.apiToken,
})
this.WaOpenai = new OpenAIApi(configuration)
}
public openai() {
return this.WaOpenai;
}
}

247
src/libs/redis.client.ts Normal file → Executable file
View File

@ -1,115 +1,132 @@
import { createClient, RedisClientType } from '@redis/client'; import { createClient, RedisClientType } from '@redis/client';
import { BufferJSON } from '@whiskeysockets/baileys'; import { BufferJSON } from '@whiskeysockets/baileys';
import { Redis } from '../config/env.config'; import { Redis } from '../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../config/logger.config';
export class RedisCache { export class RedisCache {
private readonly logger = new Logger(RedisCache.name);
private client: RedisClientType; constructor() {
private statusConnection = false; this.logger.verbose('RedisCache instance created');
private instanceName: string; process.on('beforeExit', () => {
private redisEnv: Redis; this.logger.verbose('RedisCache instance destroyed');
this.disconnect();
constructor() { });
this.logger.verbose('RedisCache instance created'); }
process.on('beforeExit', () => {
this.logger.verbose('RedisCache instance destroyed'); // constructor() {
this.disconnect(); // this.logger.verbose('instance created');
}); // process.on('beforeExit', async () => {
} // this.logger.verbose('instance destroyed');
// if (this.statusConnection) {
public set reference(reference: string) { // this.logger.verbose('instance disconnect');
this.logger.verbose('set reference: ' + reference); // await this.client.disconnect();
this.instanceName = reference; // }
} // });
// }
public async connect(redisEnv: Redis) {
this.logger.verbose('Connecting to Redis...'); private statusConnection = false;
this.client = createClient({ url: redisEnv.URI }); private instanceName: string;
this.client.on('error', (err) => this.logger.error('Redis Client Error ' + err)); private redisEnv: Redis;
await this.client.connect(); public set reference(reference: string) {
this.statusConnection = true; this.logger.verbose('set reference: ' + reference);
this.redisEnv = redisEnv; this.instanceName = reference;
this.logger.verbose(`Connected to ${redisEnv.URI}`); }
}
public async connect(redisEnv: Redis) {
public async disconnect() { this.logger.verbose('Connecting to Redis...');
if (this.statusConnection) { this.client = createClient({ url: redisEnv.URI });
await this.client.disconnect(); //this.logger.verbose('connected in ' + redisEnv.URI);
this.statusConnection = false; this.client.on('error', (err) => this.logger.error('Redis Client Error ' + err));
this.logger.verbose('Redis client disconnected'); await this.client.connect();
} this.statusConnection = true;
} this.redisEnv = redisEnv;
this.logger.verbose(`Connected to ${redisEnv.URI}`);
public async instanceKeys(): Promise<string[]> { }
const keys: string[] = [];
try { private readonly logger = new Logger(RedisCache.name);
this.logger.verbose('Fetching instance keys'); private client: RedisClientType;
for await (const key of this.client.scanIterator({ MATCH: `${this.redisEnv.PREFIX_KEY}:*` })) {
keys.push(key);
} public async disconnect() {
} catch (error) { if (this.statusConnection) {
this.logger.error('Error fetching instance keys ' + error); await this.client.disconnect();
} this.statusConnection = false;
return keys; this.logger.verbose('Redis client disconnected');
} }
}
public async keyExists(key?: string) {
if (key) { public async instanceKeys(): Promise<string[]> {
this.logger.verbose('keyExists: ' + key); const keys: string[] = [];
return !!(await this.instanceKeys()).find((i) => i === key); try {
} //this.logger.verbose('instance keys: ' + this.redisEnv.PREFIX_KEY + ':*');
this.logger.verbose('keyExists: ' + this.instanceName); //return await this.client.sendCommand(['keys', this.redisEnv.PREFIX_KEY + ':*']);
return !!(await this.instanceKeys()).find((i) => i === this.instanceName); this.logger.verbose('Fetching instance keys');
} for await (const key of this.client.scanIterator({ MATCH: `${this.redisEnv.PREFIX_KEY}:*` })) {
keys.push(key);
public async writeData(field: string, data: any) { }
try { } catch (error) {
this.logger.verbose('writeData: ' + field); this.logger.error(error);
const json = JSON.stringify(data, BufferJSON.replacer); this.logger.error('Error fetching instance keys ' + error);
}
return await this.client.hSet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field, json); return keys;
} catch (error) { }
this.logger.error(error);
} public async keyExists(key?: string) {
} if (key) {
this.logger.verbose('keyExists: ' + key);
public async readData(field: string) { return !!(await this.instanceKeys()).find((i) => i === key);
try { }
this.logger.verbose('readData: ' + field); this.logger.verbose('keyExists: ' + this.instanceName);
const data = await this.client.hGet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field); return !!(await this.instanceKeys()).find((i) => i === this.instanceName);
}
if (data) {
this.logger.verbose('readData: ' + field + ' success'); public async writeData(field: string, data: any) {
return JSON.parse(data, BufferJSON.reviver); try {
} this.logger.verbose('writeData: ' + field);
const json = JSON.stringify(data, BufferJSON.replacer);
this.logger.verbose('readData: ' + field + ' not found');
return null; return await this.client.hSet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field, json);
} catch (error) { } catch (error) {
this.logger.error(error); this.logger.error(error);
} }
} }
public async removeData(field: string) { public async readData(field: string) {
try { try {
this.logger.verbose('removeData: ' + field); this.logger.verbose('readData: ' + field);
return await this.client.hDel(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field); const data = await this.client.hGet(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
} catch (error) {
this.logger.error(error); if (data) {
} this.logger.verbose('readData: ' + field + ' success');
} return JSON.parse(data, BufferJSON.reviver);
}
public async delAll(hash?: string) {
try { this.logger.verbose('readData: ' + field + ' not found');
this.logger.verbose('instance delAll: ' + hash); return null;
const result = await this.client.del(hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName); } catch (error) {
this.logger.error(error);
return result; }
} catch (error) { }
this.logger.error(error);
} public async removeData(field: string) {
} try {
} this.logger.verbose('removeData: ' + field);
return await this.client.hDel(this.redisEnv.PREFIX_KEY + ':' + this.instanceName, field);
} catch (error) {
this.logger.error(error);
}
}
public async delAll(hash?: string) {
try {
this.logger.verbose('instance delAll: ' + hash);
const result = await this.client.del(hash || this.redisEnv.PREFIX_KEY + ':' + this.instanceName);
return result;
} catch (error) {
this.logger.error(error);
}
}
}

9
src/libs/redis.ts Executable file
View File

@ -0,0 +1,9 @@
import { Redis } from "ioredis"
import { config } from "../config"
export const redis = new Redis({
host: config.redis.host,
port: config.redis.port,
db: config.redis.db,
})

88
src/libs/socket.server.ts Normal file → Executable file
View File

@ -1,44 +1,44 @@
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');
let io: SocketIO; let io: SocketIO;
const cors = configService.get<Cors>('CORS').ORIGIN; const cors = configService.get<Cors>('CORS').ORIGIN;
export const initIO = (httpServer: Server) => { export const initIO = (httpServer: Server) => {
if (configService.get<Websocket>('WEBSOCKET')?.ENABLED) { if (configService.get<Websocket>('WEBSOCKET')?.ENABLED) {
io = new SocketIO(httpServer, { io = new SocketIO(httpServer, {
cors: { cors: {
origin: cors, origin: cors,
}, },
}); });
io.on('connection', (socket) => { io.on('connection', (socket) => {
logger.info('User connected'); logger.info('User connected');
socket.on('disconnect', () => { socket.on('disconnect', () => {
logger.info('User disconnected'); logger.info('User disconnected');
}); });
}); });
logger.info('Socket.io initialized'); logger.info('Socket.io initialized');
return io; return io;
} }
return null; return null;
}; };
export const getIO = (): SocketIO => { export const getIO = (): SocketIO => {
logger.verbose('Getting Socket.io'); logger.verbose('Getting Socket.io');
if (!io) { if (!io) {
logger.error('Socket.io not initialized'); logger.error('Socket.io not initialized');
throw new Error('Socket.io not initialized'); throw new Error('Socket.io not initialized');
} }
return io; return io;
}; };

194
src/libs/sqs.server.ts Normal file → Executable file
View File

@ -1,97 +1,97 @@
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');
let sqs: SQS; let sqs: SQS;
export const initSQS = () => { export const initSQS = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
const awsConfig = configService.get<Sqs>('SQS'); const awsConfig = configService.get<Sqs>('SQS');
sqs = new SQS({ sqs = new SQS({
accessKeyId: awsConfig.ACCESS_KEY_ID, accessKeyId: awsConfig.ACCESS_KEY_ID,
secretAccessKey: awsConfig.SECRET_ACCESS_KEY, secretAccessKey: awsConfig.SECRET_ACCESS_KEY,
region: awsConfig.REGION, region: awsConfig.REGION,
}); });
logger.info('SQS initialized'); logger.info('SQS initialized');
resolve(); resolve();
}); });
}; };
export const getSQS = (): SQS => { export const getSQS = (): SQS => {
return sqs; return sqs;
}; };
export const initQueues = (instanceName: string, events: string[]) => { export const initQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return; if (!events || !events.length) return;
const queues = events.map((event) => { const queues = events.map((event) => {
return `${event.replace(/_/g, '_').toLowerCase()}`; return `${event.replace(/_/g, '_').toLowerCase()}`;
}); });
const sqs = getSQS(); const sqs = getSQS();
queues.forEach((event) => { queues.forEach((event) => {
const queueName = `${instanceName}_${event}.fifo`; const queueName = `${instanceName}_${event}.fifo`;
sqs.createQueue( sqs.createQueue(
{ {
QueueName: queueName, QueueName: queueName,
Attributes: { Attributes: {
FifoQueue: 'true', FifoQueue: 'true',
}, },
}, },
(err, data) => { (err, data) => {
if (err) { if (err) {
logger.error(`Error creating queue ${queueName}: ${err.message}`); logger.error(`Error creating queue ${queueName}: ${err.message}`);
} else { } else {
logger.info(`Queue ${queueName} created: ${data.QueueUrl}`); logger.info(`Queue ${queueName} created: ${data.QueueUrl}`);
} }
}, },
); );
}); });
}; };
export const removeQueues = (instanceName: string, events: string[]) => { export const removeQueues = (instanceName: string, events: string[]) => {
if (!events || !events.length) return; if (!events || !events.length) return;
const sqs = getSQS(); const sqs = getSQS();
const queues = events.map((event) => { const queues = events.map((event) => {
return `${event.replace(/_/g, '_').toLowerCase()}`; return `${event.replace(/_/g, '_').toLowerCase()}`;
}); });
queues.forEach((event) => { queues.forEach((event) => {
const queueName = `${instanceName}_${event}.fifo`; const queueName = `${instanceName}_${event}.fifo`;
sqs.getQueueUrl( sqs.getQueueUrl(
{ {
QueueName: queueName, QueueName: queueName,
}, },
(err, data) => { (err, data) => {
if (err) { if (err) {
logger.error(`Error getting queue URL for ${queueName}: ${err.message}`); logger.error(`Error getting queue URL for ${queueName}: ${err.message}`);
} else { } else {
const queueUrl = data.QueueUrl; const queueUrl = data.QueueUrl;
sqs.deleteQueue( sqs.deleteQueue(
{ {
QueueUrl: queueUrl, QueueUrl: queueUrl,
}, },
(deleteErr) => { (deleteErr) => {
if (deleteErr) { if (deleteErr) {
logger.error(`Error deleting queue ${queueName}: ${deleteErr.message}`); logger.error(`Error deleting queue ${queueName}: ${deleteErr.message}`);
} else { } else {
logger.info(`Queue ${queueName} deleted`); logger.info(`Queue ${queueName} deleted`);
} }
}, },
); );
} }
}, },
); );
}); });
}; };

274
src/main.ts Normal file → Executable file
View File

@ -1,137 +1,137 @@
import 'express-async-errors'; import 'express-async-errors';
import axios from 'axios'; import axios from 'axios';
import compression from 'compression'; import compression from 'compression';
import cors from 'cors'; import cors from 'cors';
import express, { json, NextFunction, Request, Response, urlencoded } from 'express'; import express, { json, NextFunction, Request, Response, urlencoded } from 'express';
import { join } from 'path'; import { join } from 'path';
import { Auth, configService, Cors, HttpServer, Rabbitmq, Sqs, Webhook } from './config/env.config'; import { Auth, configService, Cors, HttpServer, Rabbitmq, Sqs, Webhook } from './config/env.config';
import { onUnexpectedError } from './config/error.config'; import { onUnexpectedError } from './config/error.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 { swaggerRouter } from './docs/swagger.conf'; import { swaggerRouter } from './docs/swagger.conf';
import { initAMQP } from './libs/amqp.server'; import { initAMQP } from './libs/amqp.server';
import { initIO } from './libs/socket.server'; import { initIO } from './libs/socket.server';
import { initSQS } from './libs/sqs.server'; import { initSQS } from './libs/sqs.server';
import { ServerUP } from './utils/server-up'; import { ServerUP } from './utils/server-up';
import { HttpStatus, router } from './whatsapp/routers/index.router'; import { HttpStatus, router } from './whatsapp/routers/index.router';
import { waMonitor } from './whatsapp/whatsapp.module'; import { waMonitor } from './whatsapp/whatsapp.module';
function initWA() { function initWA() {
waMonitor.loadInstance(); waMonitor.loadInstance();
} }
function bootstrap() { function bootstrap() {
const logger = new Logger('SERVER'); const logger = new Logger('SERVER');
const app = express(); const app = express();
app.use( app.use(
cors({ cors({
origin(requestOrigin, callback) { origin(requestOrigin, callback) {
const { ORIGIN } = configService.get<Cors>('CORS'); const { ORIGIN } = configService.get<Cors>('CORS');
if (ORIGIN.includes('*')) { if (ORIGIN.includes('*')) {
return callback(null, true); return callback(null, true);
} }
if (ORIGIN.indexOf(requestOrigin) !== -1) { if (ORIGIN.indexOf(requestOrigin) !== -1) {
return callback(null, true); return callback(null, true);
} }
return callback(new Error('Not allowed by CORS')); return callback(new Error('Not allowed by CORS'));
}, },
methods: [...configService.get<Cors>('CORS').METHODS], methods: [...configService.get<Cors>('CORS').METHODS],
credentials: configService.get<Cors>('CORS').CREDENTIALS, credentials: configService.get<Cors>('CORS').CREDENTIALS,
}), }),
urlencoded({ extended: true, limit: '136mb' }), urlencoded({ extended: true, limit: '136mb' }),
json({ limit: '136mb' }), json({ limit: '136mb' }),
compression(), compression(),
); );
app.set('view engine', 'hbs'); app.set('view engine', 'hbs');
app.set('views', join(ROOT_DIR, 'views')); app.set('views', join(ROOT_DIR, 'views'));
app.use(express.static(join(ROOT_DIR, 'public'))); app.use(express.static(join(ROOT_DIR, 'public')));
app.use('/store', express.static(join(ROOT_DIR, 'store'))); app.use('/store', express.static(join(ROOT_DIR, 'store')));
app.use('/', router); app.use('/', router);
app.use(swaggerRouter); app.use(swaggerRouter);
app.use( app.use(
(err: Error, req: Request, res: Response, next: NextFunction) => { (err: Error, req: Request, res: Response, next: NextFunction) => {
if (err) { if (err) {
const webhook = configService.get<Webhook>('WEBHOOK'); const webhook = configService.get<Webhook>('WEBHOOK');
if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) { if (webhook.EVENTS.ERRORS_WEBHOOK && webhook.EVENTS.ERRORS_WEBHOOK != '' && webhook.EVENTS.ERRORS) {
const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds const tzoffset = new Date().getTimezoneOffset() * 60000; //offset in milliseconds
const localISOTime = new Date(Date.now() - tzoffset).toISOString(); const localISOTime = new Date(Date.now() - tzoffset).toISOString();
const now = localISOTime; const now = localISOTime;
const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY; const globalApiKey = configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
const serverUrl = configService.get<HttpServer>('SERVER').URL; const serverUrl = configService.get<HttpServer>('SERVER').URL;
const errorData = { const errorData = {
event: 'error', event: 'error',
data: { data: {
error: err['error'] || 'Internal Server Error', error: err['error'] || 'Internal Server Error',
message: err['message'] || 'Internal Server Error', message: err['message'] || 'Internal Server Error',
status: err['status'] || 500, status: err['status'] || 500,
response: { response: {
message: err['message'] || 'Internal Server Error', message: err['message'] || 'Internal Server Error',
}, },
}, },
date_time: now, date_time: now,
api_key: globalApiKey, api_key: globalApiKey,
server_url: serverUrl, server_url: serverUrl,
}; };
logger.error(errorData); logger.error(errorData);
const baseURL = webhook.EVENTS.ERRORS_WEBHOOK; const baseURL = webhook.EVENTS.ERRORS_WEBHOOK;
const httpService = axios.create({ baseURL }); const httpService = axios.create({ baseURL });
httpService.post('', errorData); httpService.post('', errorData);
} }
return res.status(err['status'] || 500).json({ return res.status(err['status'] || 500).json({
status: err['status'] || 500, status: err['status'] || 500,
error: err['error'] || 'Internal Server Error', error: err['error'] || 'Internal Server Error',
response: { response: {
message: err['message'] || 'Internal Server Error', message: err['message'] || 'Internal Server Error',
}, },
}); });
} }
next(); next();
}, },
(req: Request, res: Response, next: NextFunction) => { (req: Request, res: Response, next: NextFunction) => {
const { method, url } = req; const { method, url } = req;
res.status(HttpStatus.NOT_FOUND).json({ res.status(HttpStatus.NOT_FOUND).json({
status: HttpStatus.NOT_FOUND, status: HttpStatus.NOT_FOUND,
error: 'Not Found', error: 'Not Found',
response: { response: {
message: [`Cannot ${method.toUpperCase()} ${url}`], message: [`Cannot ${method.toUpperCase()} ${url}`],
}, },
}); });
next(); next();
}, },
); );
const httpServer = configService.get<HttpServer>('SERVER'); const httpServer = configService.get<HttpServer>('SERVER');
ServerUP.app = app; ServerUP.app = app;
const server = ServerUP[httpServer.TYPE]; const server = ServerUP[httpServer.TYPE];
server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT)); server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));
initWA(); initWA();
initIO(server); initIO(server);
if (configService.get<Rabbitmq>('RABBITMQ')?.ENABLED) initAMQP(); if (configService.get<Rabbitmq>('RABBITMQ')?.ENABLED) initAMQP();
if (configService.get<Sqs>('SQS')?.ENABLED) initSQS(); if (configService.get<Sqs>('SQS')?.ENABLED) initSQS();
onUnexpectedError(); onUnexpectedError();
} }
bootstrap(); bootstrap();

49
src/prompts/contabilAgent.ts Executable file
View File

@ -0,0 +1,49 @@
export const promptContabil = `Você é uma assistente virtual de atendimento de um escritorio de contabilidade chamado {{ storeName }}. Você deve ser educada, atenciosa, amigável, cordial e muito paciente.
O roteiro de atendimento é:
1. Saudação inicial: Cumprimente o cliente e agradeça por entrar em contato.
2. Coleta de informações: Solicite ao cliente seu nome para registro caso ainda não tenha registrado. Informe que os dados são apenas para controle de atendimento e não serão compartilhados com terceiros.
3. Pergunte o setor que deseja seguir, sendo o seguinte Financeiro, suporte ou novo cliente.
4. Serviços de Contabilidade:
4.1 Apresente os principais serviços de contabilidade oferecidos pelo escritório.
4.2 Oferecemos uma ampla gama de serviços contábeis, incluindo ABERTURA DE EMPRESA, ABERTURA DE FILIAL, ASSESSORIA CONTÁBIL, ASSESSORIA FISCAL, BAIXA E REGULARIZAÇÃO DE EMPRESAS, CONSULTORIA CONTÁBIL, PLANEJAMENTO TRIBUTÁRIO, RECURSOS HUMANOS, REVISÃO TRIBUTÁRIA, Administração de Condomínios. Como posso ajudá-lo com seus desafios financeiros hoje?
5. Perguntas Frequentes (FAQ):
5.1 Forneça respostas para perguntas frequentes sobre impostos, contabilidade e serviços específicos.
5.2 Aqui estão algumas perguntas frequentes sobre nossos serviços: [
Pergunta 1: Vou precisar falar com meu antigo contador ou escritório de contabilidade sobre a migração?
Resposta 1: Não. Fique tranquilo pois a Anexo Gestão Contábil cuida disso para você. Você precisará enviar o seu Certificado Digital. Caso não tenha um e-CNPJ(A1), vamos te ajudar no processo de migração de outra forma, falando com o contador ou auxiliando na contratação de um Certificado Digital. Depois dessa etapa nós vamos fazer todo o seu processo com o seu antigo contador ou escritório de contabilidade. É simples, transparente e sem burocracia para você.
Pergunta 2: Quanto tempo demora para mudar para a Anexo Gestão Contábil?
Resposta 2: O processo é rápido, prático e você não precisa sair de casa. Aproximadamente 5 dias úteis é o prazo após conseguirmos acessar a documentação via Certificado Digital ou com o contador antigo.
].
5. Agendamento de Consulta:
5.2 Permita que os usuários agendem uma consulta com um contador.
5.3 Pergunte sobre a data e hora preferidas.
5.3 Se você gostaria de agendar uma consulta com um de nossos contadores, por favor, informe-nos sobre a data e horário que funcionam melhor para você.
6. Impostos:
6.1 Forneça informações sobre prazos de declaração de impostos, documentos necessários e dicas fiscais.
6.2 Os prazos para a declaração de impostos estão se aproximando. Aqui estão algumas dicas sobre como se preparar e os documentos necessários.
7. Contato e Localização:
7.1 Fornecer informações de contato, incluindo número de telefone, endereço de e-mail e endereço físico do escritório.
7.2 Você pode nos contatar pelo telefone [número], enviar um e-mail para [e-mail] ou nos visitar no seguinte endereço [endereço].
8. Encaminhamento para um Contador:
8.1 Se o chatbot não puder responder a uma pergunta específica, ofereça a opção de ser encaminhado para um contador real.
8.2 Se você tiver uma pergunta mais complexa que eu não possa responder, gostaria de ser encaminhado para um dos nossos contadores?"
9. Despedida:
9.1 Encerre a conversa de maneira cortês e ofereça informações de contato adicionais.
9.2 Obrigado por usar nossos serviços! Se precisar de assistência futura, estamos à disposição. Tenha um ótimo dia!"
10. Feedback:
10.1 Solicite feedback aos usuários para melhorar o desempenho do chatbot.
10.2 Gostaríamos de ouvir sua opinião! Em uma escala de 1 a 5, quão útil você achou nosso chatbot hoje?
`

94
src/prompts/pizzaAgent.ts Executable file
View File

@ -0,0 +1,94 @@
export const promptPizza = `Você é uma assistente virtual de atendimento de uma pizzaria chamada {{ storeName }}. Você deve ser educada, atenciosa, amigável, cordial e muito paciente.
Você não pode oferecer nenhum item ou sabor que não esteja em nosso cardápio. Siga estritamente as listas de opções.
O código do pedido é: {{ orderCode }}
O roteiro de atendimento é:
1. Saudação inicial: Cumprimente o cliente e agradeça por entrar em contato.
2. Coleta de informações: Solicite ao cliente seu nome para registro caso ainda não tenha registrado. Informe que os dados são apenas para controle de pedidos e não serão compartilhados com terceiros.
3. Quantidade de pizzas: Pergunte ao cliente quantas pizzas ele deseja pedir.
4. Sabores: Envie a lista resumida apenas com os nomes de sabores salgados e doces e pergunte ao cliente quais sabores de pizza ele deseja pedir.
4.1 O cliente pode escolher a pizza fracionada em até 2 sabores na mesma pizza.
4.2 Se o cliente escolher mais de uma pizza, pergunte se ele deseja que os sabores sejam repetidos ou diferentes.
4.3 Se o cliente escolher sabores diferentes, pergunte quais são os sabores de cada pizza.
4.4 Se o cliente escolher sabores repetidos, pergunte quantas pizzas de cada sabor ele deseja.
4.5 Se o cliente estiver indeciso, ofereça sugestões de sabores ou se deseja receber o cardápio completo.
4.6 Se o sabor não estiver no cardápio, não deve prosseguir com o atendimento. Nesse caso informe que o sabor não está disponível e agradeça o cliente.
5. Tamanho: Pergunte ao cliente qual o tamanho das pizzas.
5.1 Se o cliente escolher mais de um tamanho, pergunte se ele deseja que os tamanhos sejam repetidos ou diferentes.
5.2 Se o cliente escolher tamanhos diferentes, pergunte qual o tamanho de cada pizza.
5.3 Se o cliente escolher tamanhos repetidos, pergunte quantas pizzas de cada tamanho ele deseja.
5.4 Se o cliente estiver indeciso, ofereça sugestões de tamanhos. Se for para 1 pessoa o tamanho pequeno é ideal, para 2 pessoas o tamanho médio é ideal e para 3 ou mais pessoas o tamanho grande é ideal.
6. Ingredientes adicionais: Pergunte ao cliente se ele deseja adicionar algum ingrediente extra.
6.1 Se o cliente escolher ingredientes extras, pergunte quais são os ingredientes adicionais de cada pizza.
6.2 Se o cliente estiver indeciso, ofereça sugestões de ingredientes extras.
7. Remover ingredientes: Pergunte ao cliente se ele deseja remover algum ingrediente, por exemplo, cebola.
7.1 Se o cliente escolher ingredientes para remover, pergunte quais são os ingredientes que ele deseja remover de cada pizza.
7.2 Não é possível remover ingredientes que não existam no cardápio.
8. Borda: Pergunte ao cliente se ele deseja borda recheada.
8.1 Se o cliente escolher borda recheada, pergunte qual o sabor da borda recheada.
8.2 Se o cliente estiver indeciso, ofereça sugestões de sabores de borda recheada. Uma dica é oferecer a borda como sobremesa com sabor de chocolate.
9. Bebidas: Pergunte ao cliente se ele deseja pedir alguma bebida.
9.1 Se o cliente escolher bebidas, pergunte quais são as bebidas que ele deseja pedir.
9.2 Se o cliente estiver indeciso, ofereça sugestões de bebidas.
10. Entrega: Pergunte ao cliente se ele deseja receber o pedido em casa ou se prefere retirar no balcão.
10.1 Se o cliente escolher entrega, pergunte qual o endereço de entrega. O endereço deverá conter Rua, Número, Bairro e CEP.
10.2 Os CEPs de 12.220-000 até 12.330-000 possuem uma taxa de entrega de R$ 10,00.
10.3 Se o cliente escolher retirar no balcão, informe o endereço da pizzaria e o horário de funcionamento: Rua Abaeté, 123, Centro, São José dos Campos, SP. Horário de funcionamento: 18h às 23h.
11. Forma de pagamento: Pergunte ao cliente qual a forma de pagamento desejada, oferecendo opções como dinheiro, PIX, cartão de crédito ou débito na entrega.
11.1 Se o cliente escolher dinheiro, pergunte o valor em mãos e calcule o troco. O valor informado não pode ser menor que o valor total do pedido.
11.2 Se o cliente escolher PIX, forneça a chave PIX CNPJ: 1234
11.3 Se o cliente escolher cartão de crédito/débito, informe que a máquininha será levada pelo entregador.
12. Mais alguma coisa? Pergunte ao cliente se ele deseja pedir mais alguma coisa.
12.1 Se o cliente desejar pedir mais alguma coisa, pergunte o que ele deseja pedir.
12.2 Se o cliente não desejar pedir mais nada, informe o resumo do pedido: Dados do cliente, quantidade de pizzas, sabores, tamanhos, ingredientes adicionais, ingredientes removidos, borda, bebidas, endereço de entrega, forma de pagamento e valor total.
12.3 Confirmação do pedido: Pergunte ao cliente se o pedido está correto.
12.4 Se o cliente confirmar o pedido, informe o tempo de entrega médio de 45 minutos e agradeça.
12.5 Se o cliente não confirmar o pedido, pergunte o que está errado e corrija o pedido.
13. Despedida: Agradeça o cliente por entrar em contato. É muito importante que se despeça informando o número do pedido.
Cardápio de pizzas salgadas (os valores estão separados por tamanho - Broto, Médio e Grande):
- Muzzarella: Queijo mussarela, tomate e orégano. R$ 25,00 / R$ 30,00 / R$ 35,00
- Calabresa: Calabresa, cebola e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
- Nordestina: Carne de sol, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Frango: Frango desfiado, milho e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
- Frango c/ Catupiry: Frango desfiado, catupiry e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- A moda da Casa: Carne de sol, bacon, cebola e orégano. R$ 40,00 / R$ 45,00 / R$ 50,00
- Presunto: Presunto, queijo mussarela e orégano. R$ 30,00 / R$ 35,00 / R$ 40,00
- Quatro Estações: Presunto, queijo mussarela, ervilha, milho, palmito e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Mista: Presunto, queijo mussarela, calabresa, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Toscana: Calabresa, bacon, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Portuguesa: Presunto, queijo mussarela, calabresa, ovo, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Dois Queijos: Queijo mussarela, catupiry e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Quatro Queijos: Queijo mussarela, provolone, catupiry, parmesão e orégano. R$ 40,00 / R$ 45,00 / R$ 50,00
- Salame: Salame, queijo mussarela e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
- Atum: Atum, cebola e orégano. R$ 35,00 / R$ 40,00 / R$ 45,00
Cardápio de pizzas doces (os valores estão separados por tamanho - Broto, Médio e Grande):
- Chocolate: Chocolate ao leite e granulado. R$ 30,00 / R$ 35,00 / R$ 40,00
- Romeu e Julieta: Goiabada e queijo mussarela. R$ 30,00 / R$ 35,00 / R$ 40,00
- California: Banana, canela e açúcar. R$ 30,00 / R$ 35,00 / R$ 40,00
Extras/Adicionais (os valores estão separados por tamanho - Broto, Médio e Grande):
- Catupiry: R$ 5,00 / R$ 7,00 / R$ 9,00
Bordas (os valores estão separados por tamanho - Broto, Médio e Grande):
- Chocolate: R$ 5,00 / R$ 7,00 / R$ 9,00
- Cheddar: R$ 5,00 / R$ 7,00 / R$ 9,00
- Catupiry: R$ 5,00 / R$ 7,00 / R$ 9,00
Bebidas:
- Coca-Cola 2L: R$ 10,00
- Coca-Cola Lata: R$ 8,00
- Guaraná 2L: R$ 10,00
- Guaraná Lata: R$ 7,00
- Água com Gás 500 ml: R$ 5,00
- Água sem Gás 500 ml: R$ 4,00
`

13
src/utils/initPrompt.ts Executable file
View File

@ -0,0 +1,13 @@
import { promptPizza } from "../prompts/pizzaAgent"
export function initPrompt(storeName: string, orderCode: string, prompt?: string ): string {
if(prompt){
return prompt
.replace(/{{[\s]?storeName[\s]?}}/g, storeName)
.replace(/{{[\s]?orderCode[\s]?}}/g, orderCode)
}else{
return promptPizza
.replace(/{{[\s]?storeName[\s]?}}/g, storeName)
.replace(/{{[\s]?orderCode[\s]?}}/g, orderCode)
}
}

58
src/utils/server-up.ts Normal file → Executable file
View File

@ -1,29 +1,29 @@
import { Express } from 'express'; import { Express } from 'express';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import * as http from 'http'; import * as http from 'http';
import * as https from 'https'; import * as https from 'https';
import { configService, SslConf } from '../config/env.config'; import { configService, SslConf } from '../config/env.config';
export class ServerUP { export class ServerUP {
static #app: Express; static #app: Express;
static set app(e: Express) { static set app(e: Express) {
this.#app = e; this.#app = e;
} }
static get https() { static get https() {
const { FULLCHAIN, PRIVKEY } = configService.get<SslConf>('SSL_CONF'); const { FULLCHAIN, PRIVKEY } = configService.get<SslConf>('SSL_CONF');
return https.createServer( return https.createServer(
{ {
cert: readFileSync(FULLCHAIN), cert: readFileSync(FULLCHAIN),
key: readFileSync(PRIVKEY), key: readFileSync(PRIVKEY),
}, },
ServerUP.#app, ServerUP.#app,
); );
} }
static get http() { static get http() {
return http.createServer(ServerUP.#app); return http.createServer(ServerUP.#app);
} }
} }

219
src/utils/use-multi-file-auth-state-db.ts Normal file → Executable file
View File

@ -1,107 +1,112 @@
import { import {
AuthenticationCreds, AuthenticationCreds,
AuthenticationState, AuthenticationState,
BufferJSON, BufferJSON,
initAuthCreds, initAuthCreds,
proto, proto,
SignalDataTypeMap, SignalDataTypeMap,
} from '@whiskeysockets/baileys'; } from '@whiskeysockets/baileys';
import { configService, Database } from '../config/env.config'; import { configService, Database } from '../config/env.config';
import { Logger } from '../config/logger.config'; import { Logger } from '../config/logger.config';
import { dbserver } from '../libs/db.connect'; import { dbserver } from '../libs/db.connect';
export async function useMultiFileAuthStateDb( export async function useMultiFileAuthStateDb(
coll: string, coll: string,
): Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }> { ): Promise<{ state: AuthenticationState; saveCreds: () => Promise<void> }> {
const logger = new Logger(useMultiFileAuthStateDb.name); const logger = new Logger(useMultiFileAuthStateDb.name);
const client = dbserver.getClient(); const client = dbserver.getClient();
const collection = client const collection = client
.db(configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances') .db(
.collection(coll); configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_NAME +
configService.get<Database>('DATABASE').CONNECTION.DB_PREFIX_FINAL_NAME
const writeData = async (data: any, key: string): Promise<any> => { )
try { .collection(coll);
await client.connect();
let msgParsed = JSON.parse(JSON.stringify(data, BufferJSON.replacer)); const writeData = async (data: any, key: string): Promise<any> => {
if (Array.isArray(msgParsed)) { try {
msgParsed = { await client.connect();
_id: key, let msgParsed = JSON.parse(JSON.stringify(data, BufferJSON.replacer));
content_array: msgParsed, if (Array.isArray(msgParsed)) {
}; msgParsed = {
} _id: key,
return await collection.replaceOne({ _id: key }, msgParsed, { content_array: msgParsed,
upsert: true, };
}); }
} catch (error) { return await collection.replaceOne({ _id: key }, msgParsed, {
logger.error(error); //return await collection.replaceOne({ _id: key }, JSON.parse(JSON.stringify(data, BufferJSON.replacer)), {
} upsert: true,
}; });
} catch (error) {
const readData = async (key: string): Promise<any> => { logger.error(error);
try { }
await client.connect(); };
let data = (await collection.findOne({ _id: key })) as any;
if (data?.content_array) { const readData = async (key: string): Promise<any> => {
data = data.content_array; try {
} await client.connect();
const creds = JSON.stringify(data); let data = (await collection.findOne({ _id: key })) as any;
return JSON.parse(creds, BufferJSON.reviver); if (data?.content_array) {
} catch (error) { data = data.content_array;
logger.error(error); }
} //const data = await collection.findOne({ _id: key });
}; const creds = JSON.stringify(data);
return JSON.parse(creds, BufferJSON.reviver);
const removeData = async (key: string) => { } catch (error) {
try { logger.error(error);
await client.connect(); }
return await collection.deleteOne({ _id: key }); };
} catch (error) {
logger.error(error); const removeData = async (key: string) => {
} try {
}; await client.connect();
return await collection.deleteOne({ _id: key });
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds(); } catch (error) {
logger.error(error);
return { }
state: { };
creds,
keys: { const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
get: async (type, ids: string[]) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment return {
// @ts-ignore state: {
const data: { [_: string]: SignalDataTypeMap[type] } = {}; creds,
await Promise.all( keys: {
ids.map(async (id) => { get: async (type, ids: string[]) => {
let value = await readData(`${type}-${id}`); // eslint-disable-next-line @typescript-eslint/ban-ts-comment
if (type === 'app-state-sync-key' && value) { // @ts-ignore
value = proto.Message.AppStateSyncKeyData.fromObject(value); const data: { [_: string]: SignalDataTypeMap[type] } = {};
} await Promise.all(
ids.map(async (id) => {
data[id] = value; let value = await readData(`${type}-${id}`);
}), if (type === 'app-state-sync-key' && value) {
); value = proto.Message.AppStateSyncKeyData.fromObject(value);
}
return data;
}, data[id] = value;
set: async (data: any) => { }),
const tasks: Promise<void>[] = []; );
for (const category in data) {
for (const id in data[category]) { return data;
const value = data[category][id]; },
const key = `${category}-${id}`; set: async (data: any) => {
tasks.push(value ? writeData(value, key) : removeData(key)); const tasks: Promise<void>[] = [];
} for (const category in data) {
} for (const id in data[category]) {
const value = data[category][id];
await Promise.all(tasks); const key = `${category}-${id}`;
}, tasks.push(value ? writeData(value, key) : removeData(key));
}, }
}, }
saveCreds: async () => {
return await writeData(creds, 'creds'); await Promise.all(tasks);
}, },
}; },
} },
saveCreds: async () => {
return writeData(creds, 'creds');
},
};
}

168
src/utils/use-multi-file-auth-state-redis-db.ts Normal file → Executable file
View File

@ -1,84 +1,84 @@
import { import {
AuthenticationCreds, AuthenticationCreds,
AuthenticationState, AuthenticationState,
initAuthCreds, initAuthCreds,
proto, proto,
SignalDataTypeMap, SignalDataTypeMap,
} from '@whiskeysockets/baileys'; } from '@whiskeysockets/baileys';
import { Logger } from '../config/logger.config'; import { Logger } from '../config/logger.config';
import { RedisCache } from '../libs/redis.client'; import { RedisCache } from '../libs/redis.client';
export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{ export async function useMultiFileAuthStateRedisDb(cache: RedisCache): Promise<{
state: AuthenticationState; state: AuthenticationState;
saveCreds: () => Promise<void>; saveCreds: () => Promise<void>;
}> { }> {
const logger = new Logger(useMultiFileAuthStateRedisDb.name); const logger = new Logger(useMultiFileAuthStateRedisDb.name);
const writeData = async (data: any, key: string): Promise<any> => { const writeData = async (data: any, key: string): Promise<any> => {
try { try {
return await cache.writeData(key, data); return await cache.writeData(key, data);
} catch (error) { } catch (error) {
return logger.error({ localError: 'writeData', error }); return logger.error({ localError: 'writeData', error });
} }
}; };
const readData = async (key: string): Promise<any> => { const readData = async (key: string): Promise<any> => {
try { try {
return await cache.readData(key); return await cache.readData(key);
} catch (error) { } catch (error) {
logger.error({ readData: 'writeData', error }); logger.error({ readData: 'writeData', error });
return; return;
} }
}; };
const removeData = async (key: string) => { const removeData = async (key: string) => {
try { try {
return await cache.removeData(key); return await cache.removeData(key);
} catch (error) { } catch (error) {
logger.error({ readData: 'removeData', error }); logger.error({ readData: 'removeData', error });
} }
}; };
const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds(); const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds();
return { return {
state: { state: {
creds, creds,
keys: { keys: {
get: async (type, ids: string[]) => { get: async (type, ids: string[]) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
const data: { [_: string]: SignalDataTypeMap[type] } = {}; const data: { [_: string]: SignalDataTypeMap[type] } = {};
await Promise.all( await Promise.all(
ids.map(async (id) => { ids.map(async (id) => {
let value = await readData(`${type}-${id}`); let value = await readData(`${type}-${id}`);
if (type === 'app-state-sync-key' && value) { if (type === 'app-state-sync-key' && value) {
value = proto.Message.AppStateSyncKeyData.fromObject(value); value = proto.Message.AppStateSyncKeyData.fromObject(value);
} }
data[id] = value; data[id] = value;
}), }),
); );
return data; return data;
}, },
set: async (data: any) => { set: async (data: any) => {
const tasks: Promise<void>[] = []; const tasks: Promise<void>[] = [];
for (const category in data) { for (const category in data) {
for (const id in data[category]) { for (const id in data[category]) {
const value = data[category][id]; const value = data[category][id];
const key = `${category}-${id}`; const key = `${category}-${id}`;
tasks.push(value ? await writeData(value, key) : await removeData(key)); tasks.push(value ? await writeData(value, key) : await removeData(key));
} }
} }
await Promise.all(tasks); await Promise.all(tasks);
}, },
}, },
}, },
saveCreds: async () => { saveCreds: async () => {
return await writeData(creds, 'creds'); return await writeData(creds, 'creds');
}, },
}; };
} }

2235
src/validate/validate.schema.ts Normal file → Executable file

File diff suppressed because it is too large Load Diff

134
src/whatsapp/abstract/abstract.repository.ts Normal file → Executable file
View File

@ -1,67 +1,67 @@
import { existsSync, mkdirSync, writeFileSync } from 'fs'; import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService, Database } from '../../config/env.config'; import { ConfigService, Database } from '../../config/env.config';
import { ROOT_DIR } from '../../config/path.config'; import { ROOT_DIR } from '../../config/path.config';
export type IInsert = { insertCount: number }; export type IInsert = { insertCount: number };
export interface IRepository { export interface IRepository {
insert(data: any, instanceName: string, saveDb?: boolean): Promise<IInsert>; insert(data: any, instanceName: string, saveDb?: boolean): Promise<IInsert>;
update(data: any, instanceName: string, saveDb?: boolean): Promise<IInsert>; update(data: any, instanceName: string, saveDb?: boolean): Promise<IInsert>;
find(query: any): Promise<any>; find(query: any): Promise<any>;
delete(query: any, force?: boolean): Promise<any>; delete(query: any, force?: boolean): Promise<any>;
dbSettings: Database; dbSettings: Database;
readonly storePath: string; readonly storePath: string;
} }
type WriteStore<U> = { type WriteStore<U> = {
path: string; path: string;
fileName: string; fileName: string;
data: U; data: U;
}; };
export abstract class Repository implements IRepository { export abstract class Repository implements IRepository {
constructor(configService: ConfigService) { constructor(configService: ConfigService) {
this.dbSettings = configService.get<Database>('DATABASE'); this.dbSettings = configService.get<Database>('DATABASE');
} }
dbSettings: Database; dbSettings: Database;
readonly storePath = join(ROOT_DIR, 'store'); readonly storePath = join(ROOT_DIR, 'store');
public writeStore = <T = any>(create: WriteStore<T>) => { public writeStore = <T = any>(create: WriteStore<T>) => {
if (!existsSync(create.path)) { if (!existsSync(create.path)) {
mkdirSync(create.path, { recursive: true }); mkdirSync(create.path, { recursive: true });
} }
try { try {
writeFileSync(join(create.path, create.fileName + '.json'), JSON.stringify({ ...create.data }), { writeFileSync(join(create.path, create.fileName + '.json'), JSON.stringify({ ...create.data }), {
encoding: 'utf-8', encoding: 'utf-8',
}); });
return { message: 'create - success' }; return { message: 'create - success' };
} finally { } finally {
create.data = undefined; create.data = undefined;
} }
}; };
// eslint-disable-next-line // eslint-disable-next-line
public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> { public insert(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
// eslint-disable-next-line // eslint-disable-next-line
public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> { public update(data: any, instanceName: string, saveDb = false): Promise<IInsert> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
// eslint-disable-next-line // eslint-disable-next-line
public find(query: any): Promise<any> { public find(query: any): Promise<any> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
// eslint-disable-next-line // eslint-disable-next-line
delete(query: any, force?: boolean): Promise<any> { delete(query: any, force?: boolean): Promise<any> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
} }

464
src/whatsapp/abstract/abstract.router.ts Normal file → Executable file
View File

@ -1,232 +1,232 @@
import 'express-async-errors'; import 'express-async-errors';
import { Request } from 'express'; import { Request } from 'express';
import { JSONSchema7 } from 'json-schema'; import { JSONSchema7 } from 'json-schema';
import { validate } from 'jsonschema'; import { validate } from 'jsonschema';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { BadRequestException } from '../../exceptions'; import { BadRequestException } from '../../exceptions';
import { GetParticipant, GroupInvite } from '../dto/group.dto'; import { GetParticipant, GroupInvite } from '../dto/group.dto';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
type DataValidate<T> = { type DataValidate<T> = {
request: Request; request: Request;
schema: JSONSchema7; schema: JSONSchema7;
ClassRef: any; ClassRef: any;
execute: (instance: InstanceDto, data: T) => Promise<any>; execute: (instance: InstanceDto, data: T) => Promise<any>;
}; };
const logger = new Logger('Validate'); const logger = new Logger('Validate');
export abstract class RouterBroker { export abstract class RouterBroker {
constructor() {} constructor() {}
public routerPath(path: string, param = true) { public routerPath(path: string, param = true) {
// const route = param ? '/:instanceName/' + path : '/' + path; // const route = param ? '/:instanceName/' + path : '/' + path;
let route = '/' + path; let route = '/' + path;
param ? (route += '/:instanceName') : null; param ? (route += '/:instanceName') : null;
return route; return route;
} }
public async dataValidate<T>(args: DataValidate<T>) { public async dataValidate<T>(args: DataValidate<T>) {
const { request, schema, ClassRef, execute } = args; const { request, schema, ClassRef, execute } = args;
const ref = new ClassRef(); const ref = new ClassRef();
const body = request.body; const body = request.body;
const instance = request.params as unknown as InstanceDto; const instance = request.params as unknown as InstanceDto;
if (request?.query && Object.keys(request.query).length > 0) { if (request?.query && Object.keys(request.query).length > 0) {
Object.assign(instance, request.query); Object.assign(instance, request.query);
} }
if (request.originalUrl.includes('/instance/create')) { if (request.originalUrl.includes('/instance/create')) {
Object.assign(instance, body); Object.assign(instance, body);
} }
Object.assign(ref, body); Object.assign(ref, body);
const v = schema ? validate(ref, schema) : { valid: true, errors: [] }; const v = schema ? validate(ref, schema) : { valid: true, errors: [] };
if (!v.valid) { if (!v.valid) {
const message: any[] = v.errors.map(({ stack, schema }) => { const message: any[] = v.errors.map(({ stack, schema }) => {
let message: string; let message: string;
if (schema['description']) { if (schema['description']) {
message = schema['description']; message = schema['description'];
} else { } else {
message = stack.replace('instance.', ''); message = stack.replace('instance.', '');
} }
return message; return message;
// return { // return {
// property: property.replace('instance.', ''), // property: property.replace('instance.', ''),
// message, // message,
// }; // };
}); });
logger.error(message); logger.error(message);
throw new BadRequestException(message); throw new BadRequestException(message);
} }
return await execute(instance, ref); return await execute(instance, ref);
} }
public async groupNoValidate<T>(args: DataValidate<T>) { public async groupNoValidate<T>(args: DataValidate<T>) {
const { request, ClassRef, schema, execute } = args; const { request, ClassRef, schema, execute } = args;
const instance = request.params as unknown as InstanceDto; const instance = request.params as unknown as InstanceDto;
const ref = new ClassRef(); const ref = new ClassRef();
Object.assign(ref, request.body); Object.assign(ref, request.body);
const v = validate(ref, schema); const v = validate(ref, schema);
if (!v.valid) { if (!v.valid) {
const message: any[] = v.errors.map(({ property, stack, schema }) => { const message: any[] = v.errors.map(({ property, stack, schema }) => {
let message: string; let message: string;
if (schema['description']) { if (schema['description']) {
message = schema['description']; message = schema['description'];
} else { } else {
message = stack.replace('instance.', ''); message = stack.replace('instance.', '');
} }
return { return {
property: property.replace('instance.', ''), property: property.replace('instance.', ''),
message, message,
}; };
}); });
logger.error([...message]); logger.error([...message]);
throw new BadRequestException(...message); throw new BadRequestException(...message);
} }
return await execute(instance, ref); return await execute(instance, ref);
} }
public async groupValidate<T>(args: DataValidate<T>) { public async groupValidate<T>(args: DataValidate<T>) {
const { request, ClassRef, schema, execute } = args; const { request, ClassRef, schema, execute } = args;
const instance = request.params as unknown as InstanceDto; const instance = request.params as unknown as InstanceDto;
const body = request.body; const body = request.body;
let groupJid = body?.groupJid; let groupJid = body?.groupJid;
if (!groupJid) { if (!groupJid) {
if (request.query?.groupJid) { if (request.query?.groupJid) {
groupJid = request.query.groupJid; groupJid = request.query.groupJid;
} else { } else {
throw new BadRequestException('The group id needs to be informed in the query', 'ex: "groupJid=120362@g.us"'); throw new BadRequestException('The group id needs to be informed in the query', 'ex: "groupJid=120362@g.us"');
} }
} }
if (!groupJid.endsWith('@g.us')) { if (!groupJid.endsWith('@g.us')) {
groupJid = groupJid + '@g.us'; groupJid = groupJid + '@g.us';
} }
Object.assign(body, { Object.assign(body, {
groupJid: groupJid, groupJid: groupJid,
}); });
const ref = new ClassRef(); const ref = new ClassRef();
Object.assign(ref, body); Object.assign(ref, body);
const v = validate(ref, schema); const v = validate(ref, schema);
if (!v.valid) { if (!v.valid) {
const message: any[] = v.errors.map(({ property, stack, schema }) => { const message: any[] = v.errors.map(({ property, stack, schema }) => {
let message: string; let message: string;
if (schema['description']) { if (schema['description']) {
message = schema['description']; message = schema['description'];
} else { } else {
message = stack.replace('instance.', ''); message = stack.replace('instance.', '');
} }
return { return {
property: property.replace('instance.', ''), property: property.replace('instance.', ''),
message, message,
}; };
}); });
logger.error([...message]); logger.error([...message]);
throw new BadRequestException(...message); throw new BadRequestException(...message);
} }
return await execute(instance, ref); return await execute(instance, ref);
} }
public async inviteCodeValidate<T>(args: DataValidate<T>) { public async inviteCodeValidate<T>(args: DataValidate<T>) {
const { request, ClassRef, schema, execute } = args; const { request, ClassRef, schema, execute } = args;
const inviteCode = request.query as unknown as GroupInvite; const inviteCode = request.query as unknown as GroupInvite;
if (!inviteCode?.inviteCode) { if (!inviteCode?.inviteCode) {
throw new BadRequestException( throw new BadRequestException(
'The group invite code id needs to be informed in the query', 'The group invite code id needs to be informed in the query',
'ex: "inviteCode=F1EX5QZxO181L3TMVP31gY" (Obtained from group join link)', 'ex: "inviteCode=F1EX5QZxO181L3TMVP31gY" (Obtained from group join link)',
); );
} }
const instance = request.params as unknown as InstanceDto; const instance = request.params as unknown as InstanceDto;
const body = request.body; const body = request.body;
const ref = new ClassRef(); const ref = new ClassRef();
Object.assign(body, inviteCode); Object.assign(body, inviteCode);
Object.assign(ref, body); Object.assign(ref, body);
const v = validate(ref, schema); const v = validate(ref, schema);
if (!v.valid) { if (!v.valid) {
const message: any[] = v.errors.map(({ property, stack, schema }) => { const message: any[] = v.errors.map(({ property, stack, schema }) => {
let message: string; let message: string;
if (schema['description']) { if (schema['description']) {
message = schema['description']; message = schema['description'];
} else { } else {
message = stack.replace('instance.', ''); message = stack.replace('instance.', '');
} }
return { return {
property: property.replace('instance.', ''), property: property.replace('instance.', ''),
message, message,
}; };
}); });
logger.error([...message]); logger.error([...message]);
throw new BadRequestException(...message); throw new BadRequestException(...message);
} }
return await execute(instance, ref); return await execute(instance, ref);
} }
public async getParticipantsValidate<T>(args: DataValidate<T>) { public async getParticipantsValidate<T>(args: DataValidate<T>) {
const { request, ClassRef, schema, execute } = args; const { request, ClassRef, schema, execute } = args;
const getParticipants = request.query as unknown as GetParticipant; const getParticipants = request.query as unknown as GetParticipant;
if (!getParticipants?.getParticipants) { if (!getParticipants?.getParticipants) {
throw new BadRequestException('The getParticipants needs to be informed in the query'); throw new BadRequestException('The getParticipants needs to be informed in the query');
} }
const instance = request.params as unknown as InstanceDto; const instance = request.params as unknown as InstanceDto;
const body = request.body; const body = request.body;
const ref = new ClassRef(); const ref = new ClassRef();
Object.assign(body, getParticipants); Object.assign(body, getParticipants);
Object.assign(ref, body); Object.assign(ref, body);
const v = validate(ref, schema); const v = validate(ref, schema);
if (!v.valid) { if (!v.valid) {
const message: any[] = v.errors.map(({ property, stack, schema }) => { const message: any[] = v.errors.map(({ property, stack, schema }) => {
let message: string; let message: string;
if (schema['description']) { if (schema['description']) {
message = schema['description']; message = schema['description'];
} else { } else {
message = stack.replace('instance.', ''); message = stack.replace('instance.', '');
} }
return { return {
property: property.replace('instance.', ''), property: property.replace('instance.', ''),
message, message,
}; };
}); });
logger.error([...message]); logger.error([...message]);
throw new BadRequestException(...message); throw new BadRequestException(...message);
} }
return await execute(instance, ref); return await execute(instance, ref);
} }
} }

58
src/whatsapp/controllers/chamaai.controller.ts Normal file → Executable file
View File

@ -1,29 +1,29 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { ChamaaiDto } from '../dto/chamaai.dto'; import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.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');
export class ChamaaiController { export class ChamaaiController {
constructor(private readonly chamaaiService: ChamaaiService) {} constructor(private readonly chamaaiService: ChamaaiService) {}
public async createChamaai(instance: InstanceDto, data: ChamaaiDto) { public async createChamaai(instance: InstanceDto, data: ChamaaiDto) {
logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance'); logger.verbose('requested createChamaai from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('chamaai disabled'); logger.verbose('chamaai disabled');
data.url = ''; data.url = '';
data.token = ''; data.token = '';
data.waNumber = ''; data.waNumber = '';
data.answerByAudio = false; data.answerByAudio = false;
} }
return this.chamaaiService.create(instance, data); return this.chamaaiService.create(instance, data);
} }
public async findChamaai(instance: InstanceDto) { public async findChamaai(instance: InstanceDto) {
logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance'); logger.verbose('requested findChamaai from ' + instance.instanceName + ' instance');
return this.chamaaiService.find(instance); return this.chamaaiService.find(instance);
} }
} }

228
src/whatsapp/controllers/chat.controller.ts Normal file → Executable file
View File

@ -1,114 +1,114 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { import {
ArchiveChatDto, ArchiveChatDto,
DeleteMessage, DeleteMessage,
getBase64FromMediaMessageDto, getBase64FromMediaMessageDto,
NumberDto, NumberDto,
PrivacySettingDto, PrivacySettingDto,
ProfileNameDto, ProfileNameDto,
ProfilePictureDto, ProfilePictureDto,
ProfileStatusDto, ProfileStatusDto,
ReadMessageDto, ReadMessageDto,
WhatsAppNumberDto, WhatsAppNumberDto,
} 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';
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 { WAMonitoringService } from '../services/monitor.service'; import { WAMonitoringService } from '../services/monitor.service';
const logger = new Logger('ChatController'); const logger = new Logger('ChatController');
export class ChatController { export class ChatController {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}
public async whatsappNumber({ instanceName }: InstanceDto, data: WhatsAppNumberDto) { public async whatsappNumber({ instanceName }: InstanceDto, data: WhatsAppNumberDto) {
logger.verbose('requested whatsappNumber from ' + instanceName + ' instance'); logger.verbose('requested whatsappNumber from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].whatsappNumber(data); return await this.waMonitor.waInstances[instanceName].whatsappNumber(data);
} }
public async readMessage({ instanceName }: InstanceDto, data: ReadMessageDto) { public async readMessage({ instanceName }: InstanceDto, data: ReadMessageDto) {
logger.verbose('requested readMessage from ' + instanceName + ' instance'); logger.verbose('requested readMessage from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].markMessageAsRead(data); return await this.waMonitor.waInstances[instanceName].markMessageAsRead(data);
} }
public async archiveChat({ instanceName }: InstanceDto, data: ArchiveChatDto) { public async archiveChat({ instanceName }: InstanceDto, data: ArchiveChatDto) {
logger.verbose('requested archiveChat from ' + instanceName + ' instance'); logger.verbose('requested archiveChat from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].archiveChat(data); return await this.waMonitor.waInstances[instanceName].archiveChat(data);
} }
public async deleteMessage({ instanceName }: InstanceDto, data: DeleteMessage) { public async deleteMessage({ instanceName }: InstanceDto, data: DeleteMessage) {
logger.verbose('requested deleteMessage from ' + instanceName + ' instance'); logger.verbose('requested deleteMessage from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].deleteMessage(data); return await this.waMonitor.waInstances[instanceName].deleteMessage(data);
} }
public async fetchProfilePicture({ instanceName }: InstanceDto, data: NumberDto) { public async fetchProfilePicture({ instanceName }: InstanceDto, data: NumberDto) {
logger.verbose('requested fetchProfilePicture from ' + instanceName + ' instance'); logger.verbose('requested fetchProfilePicture from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].profilePicture(data.number); return await this.waMonitor.waInstances[instanceName].profilePicture(data.number);
} }
public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) { public async fetchProfile({ instanceName }: InstanceDto, data: NumberDto) {
logger.verbose('requested fetchProfile from ' + instanceName + ' instance'); logger.verbose('requested fetchProfile from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number); return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number);
} }
public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) { public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) {
logger.verbose('requested fetchContacts from ' + instanceName + ' instance'); logger.verbose('requested fetchContacts from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchContacts(query); return await this.waMonitor.waInstances[instanceName].fetchContacts(query);
} }
public async getBase64FromMediaMessage({ instanceName }: InstanceDto, data: getBase64FromMediaMessageDto) { public async getBase64FromMediaMessage({ instanceName }: InstanceDto, data: getBase64FromMediaMessageDto) {
logger.verbose('requested getBase64FromMediaMessage from ' + instanceName + ' instance'); logger.verbose('requested getBase64FromMediaMessage from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data); return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data);
} }
public async fetchMessages({ instanceName }: InstanceDto, query: MessageQuery) { public async fetchMessages({ instanceName }: InstanceDto, query: MessageQuery) {
logger.verbose('requested fetchMessages from ' + instanceName + ' instance'); logger.verbose('requested fetchMessages from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchMessages(query); return await this.waMonitor.waInstances[instanceName].fetchMessages(query);
} }
public async fetchStatusMessage({ instanceName }: InstanceDto, query: MessageUpQuery) { public async fetchStatusMessage({ instanceName }: InstanceDto, query: MessageUpQuery) {
logger.verbose('requested fetchStatusMessage from ' + instanceName + ' instance'); logger.verbose('requested fetchStatusMessage from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchStatusMessage(query); return await this.waMonitor.waInstances[instanceName].fetchStatusMessage(query);
} }
public async fetchChats({ instanceName }: InstanceDto) { public async fetchChats({ instanceName }: InstanceDto) {
logger.verbose('requested fetchChats from ' + instanceName + ' instance'); logger.verbose('requested fetchChats from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchChats(); return await this.waMonitor.waInstances[instanceName].fetchChats();
} }
public async fetchPrivacySettings({ instanceName }: InstanceDto) { public async fetchPrivacySettings({ instanceName }: InstanceDto) {
logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance'); logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings(); return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings();
} }
public async updatePrivacySettings({ instanceName }: InstanceDto, data: PrivacySettingDto) { public async updatePrivacySettings({ instanceName }: InstanceDto, data: PrivacySettingDto) {
logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance'); logger.verbose('requested updatePrivacySettings from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data); return await this.waMonitor.waInstances[instanceName].updatePrivacySettings(data);
} }
public async fetchBusinessProfile({ instanceName }: InstanceDto, data: ProfilePictureDto) { public async fetchBusinessProfile({ instanceName }: InstanceDto, data: ProfilePictureDto) {
logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance'); logger.verbose('requested fetchBusinessProfile from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(data.number); return await this.waMonitor.waInstances[instanceName].fetchBusinessProfile(data.number);
} }
public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) { public async updateProfileName({ instanceName }: InstanceDto, data: ProfileNameDto) {
logger.verbose('requested updateProfileName from ' + instanceName + ' instance'); logger.verbose('requested updateProfileName from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name); return await this.waMonitor.waInstances[instanceName].updateProfileName(data.name);
} }
public async updateProfileStatus({ instanceName }: InstanceDto, data: ProfileStatusDto) { public async updateProfileStatus({ instanceName }: InstanceDto, data: ProfileStatusDto) {
logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance'); logger.verbose('requested updateProfileStatus from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].updateProfileStatus(data.status); return await this.waMonitor.waInstances[instanceName].updateProfileStatus(data.status);
} }
public async updateProfilePicture({ instanceName }: InstanceDto, data: ProfilePictureDto) { public async updateProfilePicture({ instanceName }: InstanceDto, data: ProfilePictureDto) {
logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance'); logger.verbose('requested updateProfilePicture from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].updateProfilePicture(data.picture); return await this.waMonitor.waInstances[instanceName].updateProfilePicture(data.picture);
} }
public async removeProfilePicture({ instanceName }: InstanceDto) { public async removeProfilePicture({ instanceName }: InstanceDto) {
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();
} }
} }

2
src/whatsapp/controllers/chatwoot.controller.ts Normal file → Executable file
View File

@ -72,6 +72,7 @@ export class ChatwootController {
token: '', token: '',
sign_msg: false, sign_msg: false,
name_inbox: '', name_inbox: '',
id_inbox: '',
webhook_url: '', webhook_url: '',
}; };
} }
@ -86,6 +87,7 @@ export class ChatwootController {
public async receiveWebhook(instance: InstanceDto, data: any) { public async receiveWebhook(instance: InstanceDto, data: any) {
logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance'); logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance');
const chatwootService = new ChatwootService(waMonitor, this.configService); const chatwootService = new ChatwootService(waMonitor, this.configService);
return chatwootService.receiveWebhook(instance, data); return chatwootService.receiveWebhook(instance, data);

194
src/whatsapp/controllers/group.controller.ts Normal file → Executable file
View File

@ -1,97 +1,97 @@
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { import {
CreateGroupDto, CreateGroupDto,
GetParticipant, GetParticipant,
GroupDescriptionDto, GroupDescriptionDto,
GroupInvite, GroupInvite,
GroupJid, GroupJid,
GroupPictureDto, GroupPictureDto,
GroupSendInvite, GroupSendInvite,
GroupSubjectDto, GroupSubjectDto,
GroupToggleEphemeralDto, GroupToggleEphemeralDto,
GroupUpdateParticipantDto, GroupUpdateParticipantDto,
GroupUpdateSettingDto, GroupUpdateSettingDto,
} from '../dto/group.dto'; } from '../dto/group.dto';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { WAMonitoringService } from '../services/monitor.service'; import { WAMonitoringService } from '../services/monitor.service';
const logger = new Logger('ChatController'); const logger = new Logger('ChatController');
export class GroupController { export class GroupController {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}
public async createGroup(instance: InstanceDto, create: CreateGroupDto) { public async createGroup(instance: InstanceDto, create: CreateGroupDto) {
logger.verbose('requested createGroup from ' + instance.instanceName + ' instance'); logger.verbose('requested createGroup from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].createGroup(create); return await this.waMonitor.waInstances[instance.instanceName].createGroup(create);
} }
public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) { public async updateGroupPicture(instance: InstanceDto, update: GroupPictureDto) {
logger.verbose('requested updateGroupPicture from ' + instance.instanceName + ' instance'); logger.verbose('requested updateGroupPicture from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(update); return await this.waMonitor.waInstances[instance.instanceName].updateGroupPicture(update);
} }
public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) { public async updateGroupSubject(instance: InstanceDto, update: GroupSubjectDto) {
logger.verbose('requested updateGroupSubject from ' + instance.instanceName + ' instance'); logger.verbose('requested updateGroupSubject from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(update); return await this.waMonitor.waInstances[instance.instanceName].updateGroupSubject(update);
} }
public async updateGroupDescription(instance: InstanceDto, update: GroupDescriptionDto) { public async updateGroupDescription(instance: InstanceDto, update: GroupDescriptionDto) {
logger.verbose('requested updateGroupDescription from ' + instance.instanceName + ' instance'); logger.verbose('requested updateGroupDescription from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(update); return await this.waMonitor.waInstances[instance.instanceName].updateGroupDescription(update);
} }
public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) { public async findGroupInfo(instance: InstanceDto, groupJid: GroupJid) {
logger.verbose('requested findGroupInfo from ' + instance.instanceName + ' instance'); logger.verbose('requested findGroupInfo from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].findGroup(groupJid); return await this.waMonitor.waInstances[instance.instanceName].findGroup(groupJid);
} }
public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) { public async fetchAllGroups(instance: InstanceDto, getPaticipants: GetParticipant) {
logger.verbose('requested fetchAllGroups from ' + instance.instanceName + ' instance'); logger.verbose('requested fetchAllGroups from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(getPaticipants); return await this.waMonitor.waInstances[instance.instanceName].fetchAllGroups(getPaticipants);
} }
public async inviteCode(instance: InstanceDto, groupJid: GroupJid) { public async inviteCode(instance: InstanceDto, groupJid: GroupJid) {
logger.verbose('requested inviteCode from ' + instance.instanceName + ' instance'); logger.verbose('requested inviteCode from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].inviteCode(groupJid); return await this.waMonitor.waInstances[instance.instanceName].inviteCode(groupJid);
} }
public async inviteInfo(instance: InstanceDto, inviteCode: GroupInvite) { public async inviteInfo(instance: InstanceDto, inviteCode: GroupInvite) {
logger.verbose('requested inviteInfo from ' + instance.instanceName + ' instance'); logger.verbose('requested inviteInfo from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].inviteInfo(inviteCode); return await this.waMonitor.waInstances[instance.instanceName].inviteInfo(inviteCode);
} }
public async sendInvite(instance: InstanceDto, data: GroupSendInvite) { public async sendInvite(instance: InstanceDto, data: GroupSendInvite) {
logger.verbose('requested sendInvite from ' + instance.instanceName + ' instance'); logger.verbose('requested sendInvite from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].sendInvite(data); return await this.waMonitor.waInstances[instance.instanceName].sendInvite(data);
} }
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) { public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
logger.verbose('requested revokeInviteCode from ' + instance.instanceName + ' instance'); logger.verbose('requested revokeInviteCode from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(groupJid); return await this.waMonitor.waInstances[instance.instanceName].revokeInviteCode(groupJid);
} }
public async findParticipants(instance: InstanceDto, groupJid: GroupJid) { public async findParticipants(instance: InstanceDto, groupJid: GroupJid) {
logger.verbose('requested findParticipants from ' + instance.instanceName + ' instance'); logger.verbose('requested findParticipants from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].findParticipants(groupJid); return await this.waMonitor.waInstances[instance.instanceName].findParticipants(groupJid);
} }
public async updateGParticipate(instance: InstanceDto, update: GroupUpdateParticipantDto) { public async updateGParticipate(instance: InstanceDto, update: GroupUpdateParticipantDto) {
logger.verbose('requested updateGParticipate from ' + instance.instanceName + ' instance'); logger.verbose('requested updateGParticipate from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(update); return await this.waMonitor.waInstances[instance.instanceName].updateGParticipant(update);
} }
public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) { public async updateGSetting(instance: InstanceDto, update: GroupUpdateSettingDto) {
logger.verbose('requested updateGSetting from ' + instance.instanceName + ' instance'); logger.verbose('requested updateGSetting from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update); return await this.waMonitor.waInstances[instance.instanceName].updateGSetting(update);
} }
public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) { public async toggleEphemeral(instance: InstanceDto, update: GroupToggleEphemeralDto) {
logger.verbose('requested toggleEphemeral from ' + instance.instanceName + ' instance'); logger.verbose('requested toggleEphemeral from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(update); return await this.waMonitor.waInstances[instance.instanceName].toggleEphemeral(update);
} }
public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) { public async leaveGroup(instance: InstanceDto, groupJid: GroupJid) {
logger.verbose('requested leaveGroup from ' + instance.instanceName + ' instance'); logger.verbose('requested leaveGroup from ' + instance.instanceName + ' instance');
return await this.waMonitor.waInstances[instance.instanceName].leaveGroup(groupJid); return await this.waMonitor.waInstances[instance.instanceName].leaveGroup(groupJid);
} }
} }

1392
src/whatsapp/controllers/instance.controller.ts Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
import { Logger } from '../../config/logger.config';
import { InstanceDto } from '../dto/instance.dto';
import { OpenaiDto } from '../dto/openai.dto';
import { ContactOpenaiDto } from '../dto/contactopenai.dto';
import { OpenaiService } from '../services/openai.service';
const logger = new Logger('OpenaiController');
export class OpenaiController {
constructor(private readonly openaiService: OpenaiService) {}
public async createOpenai(instance: InstanceDto, data: OpenaiDto) {
logger.verbose('requested createOpenai from ' + instance.instanceName + ' instance');
if (!data.chave) {
logger.verbose('openai sem chave');
data.chave = '';
}
if (!data.enabled) {
logger.verbose('openai disabled');
data.events = [];
}
if (data.events?.length === 0) {
logger.verbose('openai events empty');
data.events = [
'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',
'CALL',
'NEW_JWT_TOKEN',
'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION',
];
}
return this.openaiService.create(instance, data);
}
public async findOpenai(instance: InstanceDto) {
logger.verbose('requested findOpenai from ' + instance.instanceName + ' instance');
return this.openaiService.find(instance);
}
public async createContactOpenai(instance: InstanceDto, data: ContactOpenaiDto) {
logger.verbose('requested createOpenai from ' + instance.instanceName + ' instance');
if (!data.contact) {
logger.verbose('openai sem chave');
data.contact = '';
}
if (!data.enabled) {
logger.verbose('openai disabled');
data.enabled = false;
}
data.owner = instance.instanceName;
return this.openaiService.createContact(instance, data);
}
public async findContactOpenai(instance: InstanceDto) {
logger.verbose('requested findOpenai from ' + instance.instanceName + ' instance');
return this.openaiService.findContact(instance);
}
}

52
src/whatsapp/controllers/proxy.controller.ts Normal file → Executable file
View File

@ -1,26 +1,26 @@
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 { ProxyDto } from '../dto/proxy.dto'; import { ProxyDto } from '../dto/proxy.dto';
import { ProxyService } from '../services/proxy.service'; import { ProxyService } from '../services/proxy.service';
const logger = new Logger('ProxyController'); const logger = new Logger('ProxyController');
export class ProxyController { export class ProxyController {
constructor(private readonly proxyService: ProxyService) {} constructor(private readonly proxyService: ProxyService) {}
public async createProxy(instance: InstanceDto, data: ProxyDto) { public async createProxy(instance: InstanceDto, data: ProxyDto) {
logger.verbose('requested createProxy from ' + instance.instanceName + ' instance'); logger.verbose('requested createProxy from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('proxy disabled'); logger.verbose('proxy disabled');
data.proxy = ''; data.proxy = '';
} }
return this.proxyService.create(instance, data); return this.proxyService.create(instance, data);
} }
public async findProxy(instance: InstanceDto) { public async findProxy(instance: InstanceDto) {
logger.verbose('requested findProxy from ' + instance.instanceName + ' instance'); logger.verbose('requested findProxy from ' + instance.instanceName + ' instance');
return this.proxyService.find(instance); return this.proxyService.find(instance);
} }
} }

112
src/whatsapp/controllers/rabbitmq.controller.ts Normal file → Executable file
View File

@ -1,56 +1,56 @@
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';
const logger = new Logger('RabbitmqController'); const logger = new Logger('RabbitmqController');
export class RabbitmqController { export class RabbitmqController {
constructor(private readonly rabbitmqService: RabbitmqService) {} constructor(private readonly rabbitmqService: RabbitmqService) {}
public async createRabbitmq(instance: InstanceDto, data: RabbitmqDto) { public async createRabbitmq(instance: InstanceDto, data: RabbitmqDto) {
logger.verbose('requested createRabbitmq from ' + instance.instanceName + ' instance'); logger.verbose('requested createRabbitmq from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('rabbitmq disabled'); logger.verbose('rabbitmq disabled');
data.events = []; data.events = [];
} }
if (data.events.length === 0) { if (data.events.length === 0) {
logger.verbose('rabbitmq events empty'); logger.verbose('rabbitmq events empty');
data.events = [ data.events = [
'APPLICATION_STARTUP', 'APPLICATION_STARTUP',
'QRCODE_UPDATED', 'QRCODE_UPDATED',
'MESSAGES_SET', 'MESSAGES_SET',
'MESSAGES_UPSERT', 'MESSAGES_UPSERT',
'MESSAGES_UPDATE', 'MESSAGES_UPDATE',
'MESSAGES_DELETE', 'MESSAGES_DELETE',
'SEND_MESSAGE', 'SEND_MESSAGE',
'CONTACTS_SET', 'CONTACTS_SET',
'CONTACTS_UPSERT', 'CONTACTS_UPSERT',
'CONTACTS_UPDATE', 'CONTACTS_UPDATE',
'PRESENCE_UPDATE', 'PRESENCE_UPDATE',
'CHATS_SET', 'CHATS_SET',
'CHATS_UPSERT', 'CHATS_UPSERT',
'CHATS_UPDATE', 'CHATS_UPDATE',
'CHATS_DELETE', 'CHATS_DELETE',
'GROUPS_UPSERT', 'GROUPS_UPSERT',
'GROUP_UPDATE', 'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE', 'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE', 'CONNECTION_UPDATE',
'CALL', 'CALL',
'NEW_JWT_TOKEN', 'NEW_JWT_TOKEN',
'TYPEBOT_START', 'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS', 'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION', 'CHAMA_AI_ACTION',
]; ];
} }
return this.rabbitmqService.create(instance, data); return this.rabbitmqService.create(instance, data);
} }
public async findRabbitmq(instance: InstanceDto) { public async findRabbitmq(instance: InstanceDto) {
logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance'); logger.verbose('requested findRabbitmq from ' + instance.instanceName + ' instance');
return this.rabbitmqService.find(instance); return this.rabbitmqService.find(instance);
} }
} }

222
src/whatsapp/controllers/sendMessage.controller.ts Normal file → Executable file
View File

@ -1,111 +1,111 @@
import { isBase64, isURL } from 'class-validator'; import { isBase64, isURL } from 'class-validator';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { BadRequestException } from '../../exceptions'; import { BadRequestException } from '../../exceptions';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { import {
SendAudioDto, SendAudioDto,
SendButtonDto, SendButtonDto,
SendContactDto, SendContactDto,
SendListDto, SendListDto,
SendLocationDto, SendLocationDto,
SendMediaDto, SendMediaDto,
SendPollDto, SendPollDto,
SendReactionDto, SendReactionDto,
SendStatusDto, SendStatusDto,
SendStickerDto, SendStickerDto,
SendTextDto, SendTextDto,
} from '../dto/sendMessage.dto'; } from '../dto/sendMessage.dto';
import { WAMonitoringService } from '../services/monitor.service'; import { WAMonitoringService } from '../services/monitor.service';
const logger = new Logger('MessageRouter'); const logger = new Logger('MessageRouter');
export class SendMessageController { export class SendMessageController {
constructor(private readonly waMonitor: WAMonitoringService) {} constructor(private readonly waMonitor: WAMonitoringService) {}
public async sendText({ instanceName }: InstanceDto, data: SendTextDto) { public async sendText({ instanceName }: InstanceDto, data: SendTextDto) {
logger.verbose('requested sendText from ' + instanceName + ' instance'); logger.verbose('requested sendText from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].textMessage(data); return await this.waMonitor.waInstances[instanceName].textMessage(data);
} }
public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto) { public async sendMedia({ instanceName }: InstanceDto, data: SendMediaDto) {
logger.verbose('requested sendMedia from ' + instanceName + ' instance'); logger.verbose('requested sendMedia from ' + instanceName + ' instance');
if ( if (
isBase64(data?.mediaMessage?.media) && isBase64(data?.mediaMessage?.media) &&
!data?.mediaMessage?.fileName && !data?.mediaMessage?.fileName &&
data?.mediaMessage?.mediatype === 'document' data?.mediaMessage?.mediatype === 'document'
) { ) {
throw new BadRequestException('For base64 the file name must be informed.'); throw new BadRequestException('For base64 the file name must be informed.');
} }
logger.verbose('isURL: ' + isURL(data?.mediaMessage?.media) + ', isBase64: ' + isBase64(data?.mediaMessage?.media)); logger.verbose('isURL: ' + isURL(data?.mediaMessage?.media) + ', isBase64: ' + isBase64(data?.mediaMessage?.media));
if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) { if (isURL(data?.mediaMessage?.media) || isBase64(data?.mediaMessage?.media)) {
return await this.waMonitor.waInstances[instanceName].mediaMessage(data); return await this.waMonitor.waInstances[instanceName].mediaMessage(data);
} }
throw new BadRequestException('Owned media must be a url or base64'); throw new BadRequestException('Owned media must be a url or base64');
} }
public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto) { public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto) {
logger.verbose('requested sendSticker from ' + instanceName + ' instance'); logger.verbose('requested sendSticker from ' + instanceName + ' instance');
logger.verbose( logger.verbose(
'isURL: ' + isURL(data?.stickerMessage?.image) + ', isBase64: ' + isBase64(data?.stickerMessage?.image), 'isURL: ' + isURL(data?.stickerMessage?.image) + ', isBase64: ' + isBase64(data?.stickerMessage?.image),
); );
if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) { if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) {
return await this.waMonitor.waInstances[instanceName].mediaSticker(data); return await this.waMonitor.waInstances[instanceName].mediaSticker(data);
} }
throw new BadRequestException('Owned media must be a url or base64'); throw new BadRequestException('Owned media must be a url or base64');
} }
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) { public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance'); logger.verbose('requested sendWhatsAppAudio from ' + instanceName + ' instance');
logger.verbose('isURL: ' + isURL(data?.audioMessage?.audio) + ', isBase64: ' + isBase64(data?.audioMessage?.audio)); logger.verbose('isURL: ' + isURL(data?.audioMessage?.audio) + ', isBase64: ' + isBase64(data?.audioMessage?.audio));
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) { if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data); return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
} }
throw new BadRequestException('Owned media must be a url or base64'); throw new BadRequestException('Owned media must be a url or base64');
} }
public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) { public async sendButtons({ instanceName }: InstanceDto, data: SendButtonDto) {
logger.verbose('requested sendButtons from ' + instanceName + ' instance'); logger.verbose('requested sendButtons from ' + instanceName + ' instance');
if (isBase64(data.buttonMessage.mediaMessage?.media) && !data.buttonMessage.mediaMessage?.fileName) { if (isBase64(data.buttonMessage.mediaMessage?.media) && !data.buttonMessage.mediaMessage?.fileName) {
throw new BadRequestException('For bse64 the file name must be informed.'); throw new BadRequestException('For bse64 the file name must be informed.');
} }
return await this.waMonitor.waInstances[instanceName].buttonMessage(data); return await this.waMonitor.waInstances[instanceName].buttonMessage(data);
} }
public async sendLocation({ instanceName }: InstanceDto, data: SendLocationDto) { public async sendLocation({ instanceName }: InstanceDto, data: SendLocationDto) {
logger.verbose('requested sendLocation from ' + instanceName + ' instance'); logger.verbose('requested sendLocation from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].locationMessage(data); return await this.waMonitor.waInstances[instanceName].locationMessage(data);
} }
public async sendList({ instanceName }: InstanceDto, data: SendListDto) { public async sendList({ instanceName }: InstanceDto, data: SendListDto) {
logger.verbose('requested sendList from ' + instanceName + ' instance'); logger.verbose('requested sendList from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].listMessage(data); return await this.waMonitor.waInstances[instanceName].listMessage(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);
} }
public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) { public async sendReaction({ instanceName }: InstanceDto, data: SendReactionDto) {
logger.verbose('requested sendReaction from ' + instanceName + ' instance'); logger.verbose('requested sendReaction from ' + instanceName + ' instance');
if (!data.reactionMessage.reaction.match(/[^()\w\sà-ú"-+]+/)) { if (!data.reactionMessage.reaction.match(/[^()\w\sà-ú"-+]+/)) {
throw new BadRequestException('"reaction" must be an emoji'); throw new BadRequestException('"reaction" must be an emoji');
} }
return await this.waMonitor.waInstances[instanceName].reactionMessage(data); return await this.waMonitor.waInstances[instanceName].reactionMessage(data);
} }
public async sendPoll({ instanceName }: InstanceDto, data: SendPollDto) { public async sendPoll({ instanceName }: InstanceDto, data: SendPollDto) {
logger.verbose('requested sendPoll from ' + instanceName + ' instance'); logger.verbose('requested sendPoll from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].pollMessage(data); return await this.waMonitor.waInstances[instanceName].pollMessage(data);
} }
public async sendStatus({ instanceName }: InstanceDto, data: SendStatusDto) { public async sendStatus({ instanceName }: InstanceDto, data: SendStatusDto) {
logger.verbose('requested sendStatus from ' + instanceName + ' instance'); logger.verbose('requested sendStatus from ' + instanceName + ' instance');
return await this.waMonitor.waInstances[instanceName].statusMessage(data); return await this.waMonitor.waInstances[instanceName].statusMessage(data);
} }
} }

48
src/whatsapp/controllers/settings.controller.ts Normal file → Executable file
View File

@ -1,24 +1,24 @@
// import { isURL } from 'class-validator'; // import { isURL } from 'class-validator';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
// import { BadRequestException } from '../../exceptions'; // import { BadRequestException } from '../../exceptions';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { SettingsDto } from '../dto/settings.dto'; import { SettingsDto } from '../dto/settings.dto';
import { SettingsService } from '../services/settings.service'; import { SettingsService } from '../services/settings.service';
const logger = new Logger('SettingsController'); const logger = new Logger('SettingsController');
export class SettingsController { export class SettingsController {
constructor(private readonly settingsService: SettingsService) {} constructor(private readonly settingsService: SettingsService) {}
public async createSettings(instance: InstanceDto, data: SettingsDto) { public async createSettings(instance: InstanceDto, data: SettingsDto) {
logger.verbose('requested createSettings from ' + instance.instanceName + ' instance'); logger.verbose('requested createSettings from ' + instance.instanceName + ' instance');
return this.settingsService.create(instance, data); return this.settingsService.create(instance, data);
} }
public async findSettings(instance: InstanceDto) { public async findSettings(instance: InstanceDto) {
logger.verbose('requested findSettings from ' + instance.instanceName + ' instance'); logger.verbose('requested findSettings from ' + instance.instanceName + ' instance');
return this.settingsService.find(instance); return this.settingsService.find(instance);
} }
} }

112
src/whatsapp/controllers/sqs.controller.ts Normal file → Executable file
View File

@ -1,56 +1,56 @@
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';
const logger = new Logger('SqsController'); const logger = new Logger('SqsController');
export class SqsController { export class SqsController {
constructor(private readonly sqsService: SqsService) {} constructor(private readonly sqsService: SqsService) { }
public async createSqs(instance: InstanceDto, data: SqsDto) { public async createSqs(instance: InstanceDto, data: SqsDto) {
logger.verbose('requested createSqs from ' + instance.instanceName + ' instance'); logger.verbose('requested createSqs from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('sqs disabled'); logger.verbose('sqs disabled');
data.events = []; data.events = [];
} }
if (data.events.length === 0) { if (data.events.length === 0) {
logger.verbose('sqs events empty'); logger.verbose('sqs events empty');
data.events = [ data.events = [
'APPLICATION_STARTUP', 'APPLICATION_STARTUP',
'QRCODE_UPDATED', 'QRCODE_UPDATED',
'MESSAGES_SET', 'MESSAGES_SET',
'MESSAGES_UPSERT', 'MESSAGES_UPSERT',
'MESSAGES_UPDATE', 'MESSAGES_UPDATE',
'MESSAGES_DELETE', 'MESSAGES_DELETE',
'SEND_MESSAGE', 'SEND_MESSAGE',
'CONTACTS_SET', 'CONTACTS_SET',
'CONTACTS_UPSERT', 'CONTACTS_UPSERT',
'CONTACTS_UPDATE', 'CONTACTS_UPDATE',
'PRESENCE_UPDATE', 'PRESENCE_UPDATE',
'CHATS_SET', 'CHATS_SET',
'CHATS_UPSERT', 'CHATS_UPSERT',
'CHATS_UPDATE', 'CHATS_UPDATE',
'CHATS_DELETE', 'CHATS_DELETE',
'GROUPS_UPSERT', 'GROUPS_UPSERT',
'GROUP_UPDATE', 'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE', 'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE', 'CONNECTION_UPDATE',
'CALL', 'CALL',
'NEW_JWT_TOKEN', 'NEW_JWT_TOKEN',
'TYPEBOT_START', 'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS', 'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION', 'CHAMA_AI_ACTION',
]; ];
} }
return this.sqsService.create(instance, data); return this.sqsService.create(instance, data);
} }
public async findSqs(instance: InstanceDto) { public async findSqs(instance: InstanceDto) {
logger.verbose('requested findSqs from ' + instance.instanceName + ' instance'); logger.verbose('requested findSqs from ' + instance.instanceName + ' instance');
return this.sqsService.find(instance); return this.sqsService.find(instance);
} }
} }

92
src/whatsapp/controllers/typebot.controller.ts Normal file → Executable file
View File

@ -1,46 +1,46 @@
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';
const logger = new Logger('TypebotController'); const logger = new Logger('TypebotController');
export class TypebotController { export class TypebotController {
constructor(private readonly typebotService: TypebotService) {} constructor(private readonly typebotService: TypebotService) {}
public async createTypebot(instance: InstanceDto, data: TypebotDto) { public async createTypebot(instance: InstanceDto, data: TypebotDto) {
logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance'); logger.verbose('requested createTypebot from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('typebot disabled'); logger.verbose('typebot disabled');
data.url = ''; data.url = '';
data.typebot = ''; data.typebot = '';
data.expire = 0; data.expire = 0;
data.sessions = []; data.sessions = [];
} else { } else {
const saveData = await this.typebotService.find(instance); const saveData = await this.typebotService.find(instance);
if (saveData.enabled) { if (saveData.enabled) {
logger.verbose('typebot enabled'); logger.verbose('typebot enabled');
data.sessions = saveData.sessions; data.sessions = saveData.sessions;
} }
} }
return this.typebotService.create(instance, data); return this.typebotService.create(instance, data);
} }
public async findTypebot(instance: InstanceDto) { public async findTypebot(instance: InstanceDto) {
logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance'); logger.verbose('requested findTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.find(instance); return this.typebotService.find(instance);
} }
public async changeStatus(instance: InstanceDto, data: any) { public async changeStatus(instance: InstanceDto, data: any) {
logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance'); logger.verbose('requested changeStatus from ' + instance.instanceName + ' instance');
return this.typebotService.changeStatus(instance, data); return this.typebotService.changeStatus(instance, data);
} }
public async startTypebot(instance: InstanceDto, data: any) { public async startTypebot(instance: InstanceDto, data: any) {
logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance'); logger.verbose('requested startTypebot from ' + instance.instanceName + ' instance');
return this.typebotService.startTypebot(instance, data); return this.typebotService.startTypebot(instance, data);
} }
} }

46
src/whatsapp/controllers/views.controller.ts Normal file → Executable file
View File

@ -1,23 +1,23 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Auth, ConfigService, HttpServer } from '../../config/env.config'; import { Auth, ConfigService, HttpServer } from '../../config/env.config';
import { HttpStatus } from '../routers/index.router'; import { HttpStatus } from '../routers/index.router';
import { WAMonitoringService } from '../services/monitor.service'; import { WAMonitoringService } from '../services/monitor.service';
export class ViewsController { export class ViewsController {
constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {} constructor(private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService) {}
public async manager(request: Request, response: Response) { public async manager(request: Request, response: Response) {
try { try {
const token = this.configService.get<Auth>('AUTHENTICATION').API_KEY.KEY; const token = this.configService.get<Auth>('AUTHENTICATION').API_KEY.KEY;
const port = this.configService.get<HttpServer>('SERVER').PORT; const port = this.configService.get<HttpServer>('SERVER').PORT;
const instances = await this.waMonitor.instanceInfo(); const instances = await this.waMonitor.instanceInfo();
console.log('INSTANCES: ', instances); console.log('INSTANCES: ', instances);
return response.status(HttpStatus.OK).render('manager', { token, port, instances }); return response.status(HttpStatus.OK).render('manager', { token, port, instances });
} catch (error) { } catch (error) {
console.log('ERROR: ', error); console.log('ERROR: ', error);
} }
} }
} }

128
src/whatsapp/controllers/webhook.controller.ts Normal file → Executable file
View File

@ -1,64 +1,64 @@
import { isURL } from 'class-validator'; import { isURL } from 'class-validator';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { BadRequestException } from '../../exceptions'; 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';
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) {}
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');
if (!isURL(data.url, { require_tld: false })) { if (!isURL(data.url, { require_tld: false })) {
throw new BadRequestException('Invalid "url" property'); throw new BadRequestException('Invalid "url" property');
} }
data.enabled = data.enabled ?? true; data.enabled = data.enabled ?? true;
if (!data.enabled) { if (!data.enabled) {
logger.verbose('webhook disabled'); logger.verbose('webhook disabled');
data.url = ''; data.url = '';
data.events = []; data.events = [];
} else if (data.events.length === 0) { } else if (data.events.length === 0) {
logger.verbose('webhook events empty'); logger.verbose('webhook events empty');
data.events = [ data.events = [
'APPLICATION_STARTUP', 'APPLICATION_STARTUP',
'QRCODE_UPDATED', 'QRCODE_UPDATED',
'MESSAGES_SET', 'MESSAGES_SET',
'MESSAGES_UPSERT', 'MESSAGES_UPSERT',
'MESSAGES_UPDATE', 'MESSAGES_UPDATE',
'MESSAGES_DELETE', 'MESSAGES_DELETE',
'SEND_MESSAGE', 'SEND_MESSAGE',
'CONTACTS_SET', 'CONTACTS_SET',
'CONTACTS_UPSERT', 'CONTACTS_UPSERT',
'CONTACTS_UPDATE', 'CONTACTS_UPDATE',
'PRESENCE_UPDATE', 'PRESENCE_UPDATE',
'CHATS_SET', 'CHATS_SET',
'CHATS_UPSERT', 'CHATS_UPSERT',
'CHATS_UPDATE', 'CHATS_UPDATE',
'CHATS_DELETE', 'CHATS_DELETE',
'GROUPS_UPSERT', 'GROUPS_UPSERT',
'GROUP_UPDATE', 'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE', 'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE', 'CONNECTION_UPDATE',
'CALL', 'CALL',
'NEW_JWT_TOKEN', 'NEW_JWT_TOKEN',
'TYPEBOT_START', 'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS', 'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION', 'CHAMA_AI_ACTION',
]; ];
} }
return this.webhookService.create(instance, data); return this.webhookService.create(instance, data);
} }
public async findWebhook(instance: InstanceDto) { public async findWebhook(instance: InstanceDto) {
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);
} }
} }

112
src/whatsapp/controllers/websocket.controller.ts Normal file → Executable file
View File

@ -1,56 +1,56 @@
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';
const logger = new Logger('WebsocketController'); const logger = new Logger('WebsocketController');
export class WebsocketController { export class WebsocketController {
constructor(private readonly websocketService: WebsocketService) {} constructor(private readonly websocketService: WebsocketService) {}
public async createWebsocket(instance: InstanceDto, data: WebsocketDto) { public async createWebsocket(instance: InstanceDto, data: WebsocketDto) {
logger.verbose('requested createWebsocket from ' + instance.instanceName + ' instance'); logger.verbose('requested createWebsocket from ' + instance.instanceName + ' instance');
if (!data.enabled) { if (!data.enabled) {
logger.verbose('websocket disabled'); logger.verbose('websocket disabled');
data.events = []; data.events = [];
} }
if (data.events.length === 0) { if (data.events.length === 0) {
logger.verbose('websocket events empty'); logger.verbose('websocket events empty');
data.events = [ data.events = [
'APPLICATION_STARTUP', 'APPLICATION_STARTUP',
'QRCODE_UPDATED', 'QRCODE_UPDATED',
'MESSAGES_SET', 'MESSAGES_SET',
'MESSAGES_UPSERT', 'MESSAGES_UPSERT',
'MESSAGES_UPDATE', 'MESSAGES_UPDATE',
'MESSAGES_DELETE', 'MESSAGES_DELETE',
'SEND_MESSAGE', 'SEND_MESSAGE',
'CONTACTS_SET', 'CONTACTS_SET',
'CONTACTS_UPSERT', 'CONTACTS_UPSERT',
'CONTACTS_UPDATE', 'CONTACTS_UPDATE',
'PRESENCE_UPDATE', 'PRESENCE_UPDATE',
'CHATS_SET', 'CHATS_SET',
'CHATS_UPSERT', 'CHATS_UPSERT',
'CHATS_UPDATE', 'CHATS_UPDATE',
'CHATS_DELETE', 'CHATS_DELETE',
'GROUPS_UPSERT', 'GROUPS_UPSERT',
'GROUP_UPDATE', 'GROUP_UPDATE',
'GROUP_PARTICIPANTS_UPDATE', 'GROUP_PARTICIPANTS_UPDATE',
'CONNECTION_UPDATE', 'CONNECTION_UPDATE',
'CALL', 'CALL',
'NEW_JWT_TOKEN', 'NEW_JWT_TOKEN',
'TYPEBOT_START', 'TYPEBOT_START',
'TYPEBOT_CHANGE_STATUS', 'TYPEBOT_CHANGE_STATUS',
'CHAMA_AI_ACTION', 'CHAMA_AI_ACTION',
]; ];
} }
return this.websocketService.create(instance, data); return this.websocketService.create(instance, data);
} }
public async findWebsocket(instance: InstanceDto) { public async findWebsocket(instance: InstanceDto) {
logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance'); logger.verbose('requested findWebsocket from ' + instance.instanceName + ' instance');
return this.websocketService.find(instance); return this.websocketService.find(instance);
} }
} }

14
src/whatsapp/dto/chamaai.dto.ts Normal file → Executable file
View File

@ -1,7 +1,7 @@
export class ChamaaiDto { export class ChamaaiDto {
enabled: boolean; enabled: boolean;
url: string; url: string;
token: string; token: string;
waNumber: string; waNumber: string;
answerByAudio: boolean; answerByAudio: boolean;
} }

170
src/whatsapp/dto/chat.dto.ts Normal file → Executable file
View File

@ -1,85 +1,85 @@
import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys'; import { proto, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '@whiskeysockets/baileys';
export class OnWhatsAppDto { export class OnWhatsAppDto {
constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {} constructor(public readonly jid: string, public readonly exists: boolean, public readonly name?: string) {}
} }
export class getBase64FromMediaMessageDto { export class getBase64FromMediaMessageDto {
message: proto.WebMessageInfo; message: proto.WebMessageInfo;
convertToMp4?: boolean; convertToMp4?: boolean;
} }
export class WhatsAppNumberDto { export class WhatsAppNumberDto {
numbers: string[]; numbers: string[];
} }
export class NumberDto { export class NumberDto {
number: string; number: string;
} }
export class NumberBusiness { export class NumberBusiness {
wid?: string; wid?: string;
jid?: string; jid?: string;
exists?: boolean; exists?: boolean;
isBusiness: boolean; isBusiness: boolean;
name?: string; name?: string;
message?: string; message?: string;
description?: string; description?: string;
email?: string; email?: string;
website?: string[]; website?: string[];
address?: string; address?: string;
} }
export class ProfileNameDto { export class ProfileNameDto {
name: string; name: string;
} }
export class ProfileStatusDto { export class ProfileStatusDto {
status: string; status: string;
} }
export class ProfilePictureDto { export class ProfilePictureDto {
number?: string; number?: string;
// url or base64 // url or base64
picture?: string; picture?: string;
} }
class Key { class Key {
id: string; id: string;
fromMe: boolean; fromMe: boolean;
remoteJid: string; remoteJid: string;
} }
export class ReadMessageDto { export class ReadMessageDto {
read_messages: Key[]; read_messages: Key[];
} }
export class LastMessage { export class LastMessage {
key: Key; key: Key;
messageTimestamp?: number; messageTimestamp?: number;
} }
export class ArchiveChatDto { export class ArchiveChatDto {
lastMessage?: LastMessage; lastMessage?: LastMessage;
chat?: string; chat?: string;
archive: boolean; archive: boolean;
} }
class PrivacySetting { class PrivacySetting {
readreceipts: WAReadReceiptsValue; readreceipts: WAReadReceiptsValue;
profile: WAPrivacyValue; profile: WAPrivacyValue;
status: WAPrivacyValue; status: WAPrivacyValue;
online: WAPrivacyOnlineValue; online: WAPrivacyOnlineValue;
last: WAPrivacyValue; last: WAPrivacyValue;
groupadd: WAPrivacyValue; groupadd: WAPrivacyValue;
} }
export class PrivacySettingDto { export class PrivacySettingDto {
privacySettings: PrivacySetting; privacySettings: PrivacySetting;
} }
export class DeleteMessage { export class DeleteMessage {
id: string; id: string;
fromMe: boolean; fromMe: boolean;
remoteJid: string; remoteJid: string;
participant?: string; participant?: string;
} }

1
src/whatsapp/dto/chatwoot.dto.ts Normal file → Executable file
View File

@ -4,6 +4,7 @@ export class ChatwootDto {
token?: string; token?: string;
url?: string; url?: string;
name_inbox?: string; name_inbox?: string;
id_inbox?: string;
sign_msg?: boolean; sign_msg?: boolean;
number?: string; number?: string;
reopen_conversation?: boolean; reopen_conversation?: boolean;

View File

@ -0,0 +1,5 @@
export class ContactOpenaiDto {
contact?: string;
enabled: boolean;
owner: string;
}

104
src/whatsapp/dto/group.dto.ts Normal file → Executable file
View File

@ -1,52 +1,52 @@
export class CreateGroupDto { export class CreateGroupDto {
subject: string; subject: string;
participants: string[]; participants: string[];
description?: string; description?: string;
promoteParticipants?: boolean; promoteParticipants?: boolean;
} }
export class GroupPictureDto { export class GroupPictureDto {
groupJid: string; groupJid: string;
image: string; image: string;
} }
export class GroupSubjectDto { export class GroupSubjectDto {
groupJid: string; groupJid: string;
subject: string; subject: string;
} }
export class GroupDescriptionDto { export class GroupDescriptionDto {
groupJid: string; groupJid: string;
description: string; description: string;
} }
export class GroupJid { export class GroupJid {
groupJid: string; groupJid: string;
} }
export class GetParticipant { export class GetParticipant {
getParticipants: string; getParticipants: string;
} }
export class GroupInvite { export class GroupInvite {
inviteCode: string; inviteCode: string;
} }
export class GroupSendInvite { export class GroupSendInvite {
groupJid: string; groupJid: string;
description: string; description: string;
numbers: string[]; numbers: string[];
} }
export class GroupUpdateParticipantDto extends GroupJid { export class GroupUpdateParticipantDto extends GroupJid {
action: 'add' | 'remove' | 'promote' | 'demote'; action: 'add' | 'remove' | 'promote' | 'demote';
participants: string[]; participants: string[];
} }
export class GroupUpdateSettingDto extends GroupJid { export class GroupUpdateSettingDto extends GroupJid {
action: 'announcement' | 'not_announcement' | 'unlocked' | 'locked'; action: 'announcement' | 'not_announcement' | 'unlocked' | 'locked';
} }
export class GroupToggleEphemeralDto extends GroupJid { export class GroupToggleEphemeralDto extends GroupJid {
expiration: 0 | 86400 | 604800 | 7776000; expiration: 0 | 86400 | 604800 | 7776000;
} }

80
src/whatsapp/dto/instance.dto.ts Normal file → Executable file
View File

@ -1,36 +1,44 @@
export class InstanceDto { export class InstanceDto {
instanceName: string; instanceName: string;
qrcode?: boolean; qrcode?: boolean;
number?: string; number?: string;
token?: string; token?: string;
webhook?: string; webhook?: string;
webhook_by_events?: boolean; webhook_by_events?: boolean;
webhook_base64?: boolean; webhook_base64?: boolean;
events?: string[]; events?: string[];
reject_call?: boolean; reject_call?: boolean;
msg_call?: string; msg_call?: string;
groups_ignore?: boolean; groups_ignore?: boolean;
always_online?: boolean; always_online?: boolean;
read_messages?: boolean; read_messages?: boolean;
read_status?: boolean; read_status?: boolean;
chatwoot_account_id?: string; chatwoot_account_id?: string;
chatwoot_token?: string; chatwoot_token?: string;
chatwoot_url?: string; chatwoot_url?: string;
chatwoot_sign_msg?: boolean; chatwoot_sign_msg?: boolean;
chatwoot_reopen_conversation?: boolean; chatwoot_reopen_conversation?: boolean;
chatwoot_conversation_pending?: boolean; chatwoot_conversation_pending?: boolean;
websocket_enabled?: boolean; websocket_enabled?: boolean;
websocket_events?: string[]; websocket_events?: string[];
rabbitmq_enabled?: boolean; rabbitmq_enabled?: boolean;
rabbitmq_events?: string[]; rabbitmq_events?: string[];
sqs_enabled?: boolean;
sqs_events?: string[]; openai_chave?: boolean;
typebot_url?: string; openai_prompts?: string;
typebot?: string; openai_enabled?: boolean;
typebot_expire?: number; openai_events?: string[];
typebot_keyword_finish?: string;
typebot_delay_message?: number; sqs_enabled?: boolean;
typebot_unknown_message?: string; sqs_events?: string[];
typebot_listening_from_me?: boolean;
proxy?: string; typebot_url?: string;
} typebot?: string;
typebot_expire?: number;
typebot_keyword_finish?: string;
typebot_delay_message?: number;
typebot_unknown_message?: string;
typebot_listening_from_me?: boolean;
proxy_enabled?: boolean;
proxy?: string;
}

6
src/whatsapp/dto/openai.dto.ts Executable file
View File

@ -0,0 +1,6 @@
export class OpenaiDto {
chave?: string;
enabled: boolean;
prompts?: string;
events?: string[];
}

8
src/whatsapp/dto/proxy.dto.ts Normal file → Executable file
View File

@ -1,4 +1,4 @@
export class ProxyDto { export class ProxyDto {
enabled: boolean; enabled: boolean;
proxy: string; proxy: string;
} }

8
src/whatsapp/dto/rabbitmq.dto.ts Normal file → Executable file
View File

@ -1,4 +1,4 @@
export class RabbitmqDto { export class RabbitmqDto {
enabled: boolean; enabled: boolean;
events?: string[]; events?: string[];
} }

0
src/whatsapp/dto/sendMessage.dto.ts Normal file → Executable file
View File

16
src/whatsapp/dto/settings.dto.ts Normal file → Executable file
View File

@ -1,8 +1,8 @@
export class SettingsDto { export class SettingsDto {
reject_call?: boolean; reject_call?: boolean;
msg_call?: string; msg_call?: string;
groups_ignore?: boolean; groups_ignore?: boolean;
always_online?: boolean; always_online?: boolean;
read_messages?: boolean; read_messages?: boolean;
read_status?: boolean; read_status?: boolean;
} }

8
src/whatsapp/dto/sqs.dto.ts Normal file → Executable file
View File

@ -1,4 +1,4 @@
export class SqsDto { export class SqsDto {
enabled: boolean; enabled: boolean;
events?: string[]; events?: string[];
} }

52
src/whatsapp/dto/typebot.dto.ts Normal file → Executable file
View File

@ -1,26 +1,26 @@
export class Session { export class Session {
remoteJid?: string; remoteJid?: string;
sessionId?: string; sessionId?: string;
status?: string; status?: string;
createdAt?: number; createdAt?: number;
updateAt?: number; updateAt?: number;
prefilledVariables?: PrefilledVariables; prefilledVariables?: PrefilledVariables;
} }
export class PrefilledVariables { export class PrefilledVariables {
remoteJid?: string; remoteJid?: string;
pushName?: string; pushName?: string;
additionalData?: { [key: string]: any }; additionalData?: { [key: string]: any };
} }
export class TypebotDto { export class TypebotDto {
enabled?: boolean; enabled?: boolean;
url: string; url: string;
typebot?: string; typebot?: string;
expire?: number; expire?: number;
keyword_finish?: string; keyword_finish?: string;
delay_message?: number; delay_message?: number;
unknown_message?: string; unknown_message?: string;
listening_from_me?: boolean; listening_from_me?: boolean;
sessions?: Session[]; sessions?: Session[];
} }

14
src/whatsapp/dto/webhook.dto.ts Normal file → Executable file
View File

@ -1,7 +1,7 @@
export class WebhookDto { export class WebhookDto {
enabled?: boolean; enabled?: boolean;
url?: string; url?: string;
events?: string[]; events?: string[];
webhook_by_events?: boolean; webhook_by_events?: boolean;
webhook_base64?: boolean; webhook_base64?: boolean;
} }

8
src/whatsapp/dto/websocket.dto.ts Normal file → Executable file
View File

@ -1,4 +1,4 @@
export class WebsocketDto { export class WebsocketDto {
enabled: boolean; enabled: boolean;
events?: string[]; events?: string[];
} }

166
src/whatsapp/guards/auth.guard.ts Normal file → Executable file
View File

@ -1,83 +1,83 @@
import { isJWT } from 'class-validator'; import { isJWT } from 'class-validator';
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import { name } from '../../../package.json'; import { name } from '../../../package.json';
import { Auth, configService } from '../../config/env.config'; 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 { JwtPayload } from '../services/auth.service'; import { JwtPayload } from '../services/auth.service';
import { repository } from '../whatsapp.module'; import { repository } from '../whatsapp.module';
const logger = new Logger('GUARD'); const logger = new Logger('GUARD');
async function jwtGuard(req: Request, res: Response, next: NextFunction) { async function jwtGuard(req: Request, res: Response, next: NextFunction) {
const key = req.get('apikey'); const key = req.get('apikey');
if (key && configService.get<Auth>('AUTHENTICATION').API_KEY.KEY !== key) { if (key && configService.get<Auth>('AUTHENTICATION').API_KEY.KEY !== key) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
if (configService.get<Auth>('AUTHENTICATION').API_KEY.KEY === key) { if (configService.get<Auth>('AUTHENTICATION').API_KEY.KEY === key) {
return next(); return next();
} }
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) { if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
throw new ForbiddenException('Missing global api key', 'The global api key must be set'); throw new ForbiddenException('Missing global api key', 'The global api key must be set');
} }
const jwtOpts = configService.get<Auth>('AUTHENTICATION').JWT; const jwtOpts = configService.get<Auth>('AUTHENTICATION').JWT;
try { try {
const [bearer, token] = req.get('authorization').split(' '); const [bearer, token] = req.get('authorization').split(' ');
if (bearer.toLowerCase() !== 'bearer') { if (bearer.toLowerCase() !== 'bearer') {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
if (!isJWT(token)) { if (!isJWT(token)) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
const param = req.params as unknown as InstanceDto; const param = req.params as unknown as InstanceDto;
const decode = jwt.verify(token, jwtOpts.SECRET, { const decode = jwt.verify(token, jwtOpts.SECRET, {
ignoreExpiration: jwtOpts.EXPIRIN_IN === 0, ignoreExpiration: jwtOpts.EXPIRIN_IN === 0,
}) as JwtPayload; }) as JwtPayload;
if (param.instanceName !== decode.instanceName || name !== decode.apiName) { if (param.instanceName !== decode.instanceName || name !== decode.apiName) {
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
return next(); return next();
} catch (error) { } catch (error) {
logger.error(error); logger.error(error);
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
} }
async function apikey(req: Request, _: Response, next: NextFunction) { async function apikey(req: Request, _: Response, next: NextFunction) {
const env = configService.get<Auth>('AUTHENTICATION').API_KEY; const env = configService.get<Auth>('AUTHENTICATION').API_KEY;
const key = req.get('apikey'); const key = req.get('apikey');
if (env.KEY === key) { if (env.KEY === key) {
return next(); return next();
} }
if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) { if ((req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) && !key) {
throw new ForbiddenException('Missing global api key', 'The global api key must be set'); throw new ForbiddenException('Missing global api key', 'The global api key must be set');
} }
try { try {
const param = req.params as unknown as InstanceDto; const param = req.params as unknown as InstanceDto;
const instanceKey = await repository.auth.find(param.instanceName); const instanceKey = await repository.auth.find(param.instanceName);
if (instanceKey.apikey === key) { if (instanceKey.apikey === key) {
return next(); return next();
} }
} catch (error) { } catch (error) {
logger.error(error); logger.error(error);
} }
throw new UnauthorizedException(); throw new UnauthorizedException();
} }
export const authGuard = { jwt: jwtGuard, apikey }; export const authGuard = { jwt: jwtGuard, apikey };

150
src/whatsapp/guards/instance.guard.ts Normal file → Executable file
View File

@ -1,74 +1,76 @@
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import { existsSync } from 'fs'; import { existsSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { configService, Database, Redis } from '../../config/env.config'; import { configService, Database, Redis } from '../../config/env.config';
import { INSTANCE_DIR } from '../../config/path.config'; import { INSTANCE_DIR } from '../../config/path.config';
import { import {
BadRequestException, BadRequestException,
ForbiddenException, ForbiddenException,
InternalServerErrorException, InternalServerErrorException,
NotFoundException, NotFoundException,
} 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 '../whatsapp.module';
async function getInstance(instanceName: string) { async function getInstance(instanceName: string) {
try { try {
const db = configService.get<Database>('DATABASE'); const db = configService.get<Database>('DATABASE');
const redisConf = configService.get<Redis>('REDIS'); const redisConf = configService.get<Redis>('REDIS');
const exists = !!waMonitor.waInstances[instanceName]; const exists = !!waMonitor.waInstances[instanceName];
if (redisConf.ENABLED) { if (redisConf.ENABLED) {
const keyExists = await cache.keyExists(); const keyExists = await cache.keyExists();
return exists || keyExists; return exists || keyExists;
} }
if (db.ENABLED) { if (db.ENABLED) {
const collection = dbserver const collection = dbserver
.getClient() .getClient()
.db(db.CONNECTION.DB_PREFIX_NAME + '-instances') .db(
.collection(instanceName); db.CONNECTION.DB_PREFIX_NAME +
return exists || (await collection.find({}).toArray()).length > 0; db.CONNECTION.DB_PREFIX_FINAL_NAME)
} .collection(instanceName);
return exists || (await collection.find({}).toArray()).length > 0;
return exists || existsSync(join(INSTANCE_DIR, instanceName)); }
} catch (error) {
throw new InternalServerErrorException(error?.toString()); return exists || existsSync(join(INSTANCE_DIR, instanceName));
} } catch (error) {
} throw new InternalServerErrorException(error?.toString());
}
export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) { }
if (req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) {
return next(); export async function instanceExistsGuard(req: Request, _: Response, next: NextFunction) {
} if (req.originalUrl.includes('/instance/create') || req.originalUrl.includes('/instance/fetchInstances')) {
return next();
const param = req.params as unknown as InstanceDto; }
if (!param?.instanceName) {
throw new BadRequestException('"instanceName" not provided.'); const param = req.params as unknown as InstanceDto;
} if (!param?.instanceName) {
throw new BadRequestException('"instanceName" not provided.');
if (!(await getInstance(param.instanceName))) { }
throw new NotFoundException(`The "${param.instanceName}" instance does not exist`);
} if (!(await getInstance(param.instanceName))) {
throw new NotFoundException(`The "${param.instanceName}" instance does not exist`);
next(); }
}
next();
export async function instanceLoggedGuard(req: Request, _: Response, next: NextFunction) { }
if (req.originalUrl.includes('/instance/create')) {
const instance = req.body as InstanceDto; export async function instanceLoggedGuard(req: Request, _: Response, next: NextFunction) {
if (await getInstance(instance.instanceName)) { if (req.originalUrl.includes('/instance/create')) {
throw new ForbiddenException(`This name "${instance.instanceName}" is already in use.`); const instance = req.body as InstanceDto;
} if (await getInstance(instance.instanceName)) {
throw new ForbiddenException(`This name "${instance.instanceName}" is already in use.`);
if (waMonitor.waInstances[instance.instanceName]) { }
waMonitor.waInstances[instance.instanceName]?.removeRabbitmqQueues();
delete waMonitor.waInstances[instance.instanceName]; if (waMonitor.waInstances[instance.instanceName]) {
} waMonitor.waInstances[instance.instanceName]?.removeRabbitmqQueues();
} delete waMonitor.waInstances[instance.instanceName];
}
next(); }
}
next();
}

36
src/whatsapp/models/auth.model.ts Normal file → Executable file
View File

@ -1,18 +1,18 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class AuthRaw { export class AuthRaw {
_id?: string; _id?: string;
jwt?: string; jwt?: string;
apikey?: string; apikey?: string;
} }
const authSchema = new Schema<AuthRaw>({ const authSchema = new Schema<AuthRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
jwt: { type: String, minlength: 1 }, jwt: { type: String, minlength: 1 },
apikey: { type: String, minlength: 1 }, apikey: { type: String, minlength: 1 },
}); });
export const AuthModel = dbserver?.model(AuthRaw.name, authSchema, 'authentication'); export const AuthModel = dbserver?.model(AuthRaw.name, authSchema, 'authentication');
export type IAuthModel = typeof AuthModel; export type IAuthModel = typeof AuthModel;

48
src/whatsapp/models/chamaai.model.ts Normal file → Executable file
View File

@ -1,24 +1,24 @@
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;
enabled?: boolean; enabled?: boolean;
url?: string; url?: string;
token?: string; token?: string;
waNumber?: string; waNumber?: string;
answerByAudio?: boolean; answerByAudio?: boolean;
} }
const chamaaiSchema = new Schema<ChamaaiRaw>({ const chamaaiSchema = new Schema<ChamaaiRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
url: { type: String, required: true }, url: { type: String, required: true },
token: { type: String, required: true }, token: { type: String, required: true },
waNumber: { type: String, required: true }, waNumber: { type: String, required: true },
answerByAudio: { type: Boolean, required: true }, answerByAudio: { type: Boolean, required: true },
}); });
export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai'); export const ChamaaiModel = dbserver?.model(ChamaaiRaw.name, chamaaiSchema, 'chamaai');
export type IChamaaiModel = typeof ChamaaiModel; export type IChamaaiModel = typeof ChamaaiModel;

38
src/whatsapp/models/chat.model.ts Normal file → Executable file
View File

@ -1,19 +1,19 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class ChatRaw { export class ChatRaw {
_id?: string; _id?: string;
id?: string; id?: string;
owner: string; owner: string;
lastMsgTimestamp?: number; lastMsgTimestamp?: number;
} }
const chatSchema = new Schema<ChatRaw>({ const chatSchema = new Schema<ChatRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
id: { type: String, required: true, minlength: 1 }, id: { type: String, required: true, minlength: 1 },
owner: { type: String, required: true, minlength: 1 }, owner: { type: String, required: true, minlength: 1 },
}); });
export const ChatModel = dbserver?.model(ChatRaw.name, chatSchema, 'chats'); export const ChatModel = dbserver?.model(ChatRaw.name, chatSchema, 'chats');
export type IChatModel = typeof ChatModel; export type IChatModel = typeof ChatModel;

2
src/whatsapp/models/chatwoot.model.ts Normal file → Executable file
View File

@ -9,6 +9,7 @@ export class ChatwootRaw {
token?: string; token?: string;
url?: string; url?: string;
name_inbox?: string; name_inbox?: string;
id_inbox?: string;
sign_msg?: boolean; sign_msg?: boolean;
number?: string; number?: string;
reopen_conversation?: boolean; reopen_conversation?: boolean;
@ -22,6 +23,7 @@ const chatwootSchema = new Schema<ChatwootRaw>({
token: { type: String, required: true }, token: { type: String, required: true },
url: { type: String, required: true }, url: { type: String, required: true },
name_inbox: { type: String, required: true }, name_inbox: { type: String, required: true },
id_inbox: { type: String, required: true },
sign_msg: { type: Boolean, required: true }, sign_msg: { type: Boolean, required: true },
number: { type: String, required: true }, number: { type: String, required: true },
reopen_conversation: { type: Boolean, required: true }, reopen_conversation: { type: Boolean, required: true },

44
src/whatsapp/models/contact.model.ts Normal file → Executable file
View File

@ -1,22 +1,22 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class ContactRaw { export class ContactRaw {
_id?: string; _id?: string;
pushName?: string; pushName?: string;
id?: string; id?: string;
profilePictureUrl?: string; profilePictureUrl?: string;
owner: string; owner: string;
} }
const contactSchema = new Schema<ContactRaw>({ const contactSchema = new Schema<ContactRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
pushName: { type: String, minlength: 1 }, pushName: { type: String, minlength: 1 },
id: { type: String, required: true, minlength: 1 }, id: { type: String, required: true, minlength: 1 },
profilePictureUrl: { type: String, minlength: 1 }, profilePictureUrl: { type: String, minlength: 1 },
owner: { type: String, required: true, minlength: 1 }, owner: { type: String, required: true, minlength: 1 },
}); });
export const ContactModel = dbserver?.model(ContactRaw.name, contactSchema, 'contacts'); export const ContactModel = dbserver?.model(ContactRaw.name, contactSchema, 'contacts');
export type IContactModel = typeof ContactModel; export type IContactModel = typeof ContactModel;

View File

@ -0,0 +1,20 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class ContactOpenaiRaw {
_id?: string;
contact?: string;
enabled?: boolean;
owner: string;
}
const contactOpenaiSchema = new Schema<ContactOpenaiRaw>({
_id: { type: String, _id: true },
contact: { type: String, required: true, minlength: 1 },
enabled: { type: Boolean, required: true },
owner: { type: String, required: true, minlength: 1 },
});
export const ContactOpenaiModel = dbserver?.model(ContactOpenaiRaw.name, contactOpenaiSchema, 'openai_contacts');
export type IContactOpenaiModel = typeof ContactOpenaiModel;

28
src/whatsapp/models/index.ts Normal file → Executable file
View File

@ -1,13 +1,15 @@
export * from './auth.model'; export * from './auth.model';
export * from './chamaai.model'; export * from './chamaai.model';
export * from './chat.model'; export * from './chat.model';
export * from './chatwoot.model'; export * from './chatwoot.model';
export * from './contact.model'; export * from './contact.model';
export * from './message.model'; export * from './message.model';
export * from './proxy.model'; export * from './proxy.model';
export * from './rabbitmq.model'; export * from './rabbitmq.model';
export * from './settings.model'; export * from './settings.model';
export * from './sqs.model'; export * from './sqs.model';
export * from './typebot.model'; export * from './typebot.model';
export * from './webhook.model'; export * from './webhook.model';
export * from './websocket.model'; export * from './websocket.model';
export * from './openai.model';
export * from './contactOpenai.model';

142
src/whatsapp/models/message.model.ts Normal file → Executable file
View File

@ -1,71 +1,71 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
import { wa } from '../types/wa.types'; import { wa } from '../types/wa.types';
class Key { class Key {
id?: string; id?: string;
remoteJid?: string; remoteJid?: string;
fromMe?: boolean; fromMe?: boolean;
participant?: string; participant?: string;
} }
export class MessageRaw { export class MessageRaw {
_id?: string; _id?: string;
key?: Key; key?: Key;
pushName?: string; pushName?: string;
participant?: string; participant?: string;
message?: object; message?: object;
messageType?: string; messageType?: string;
messageTimestamp?: number | Long.Long; messageTimestamp?: number | Long.Long;
owner: string; owner: string;
source?: 'android' | 'web' | 'ios'; source?: 'android' | 'web' | 'ios';
source_id?: string; source_id?: string;
source_reply_id?: string; source_reply_id?: string;
} }
const messageSchema = new Schema<MessageRaw>({ const messageSchema = new Schema<MessageRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
key: { key: {
id: { type: String, required: true, minlength: 1 }, id: { type: String, required: true, minlength: 1 },
remoteJid: { type: String, required: true, minlength: 1 }, remoteJid: { type: String, required: true, minlength: 1 },
fromMe: { type: Boolean, required: true }, fromMe: { type: Boolean, required: true },
participant: { type: String, minlength: 1 }, participant: { type: String, minlength: 1 },
}, },
pushName: { type: String }, pushName: { type: String },
participant: { type: String }, participant: { type: String },
messageType: { type: String }, messageType: { type: String },
message: { type: Object }, message: { type: Object },
source: { type: String, minlength: 3, enum: ['android', 'web', 'ios'] }, source: { type: String, minlength: 3, enum: ['android', 'web', 'ios'] },
messageTimestamp: { type: Number, required: true }, messageTimestamp: { type: Number, required: true },
owner: { type: String, required: true, minlength: 1 }, owner: { type: String, required: true, minlength: 1 },
}); });
export const MessageModel = dbserver?.model(MessageRaw.name, messageSchema, 'messages'); export const MessageModel = dbserver?.model(MessageRaw.name, messageSchema, 'messages');
export type IMessageModel = typeof MessageModel; export type IMessageModel = typeof MessageModel;
export class MessageUpdateRaw { export class MessageUpdateRaw {
_id?: string; _id?: string;
remoteJid?: string; remoteJid?: string;
id?: string; id?: string;
fromMe?: boolean; fromMe?: boolean;
participant?: string; participant?: string;
datetime?: number; datetime?: number;
status?: wa.StatusMessage; status?: wa.StatusMessage;
owner: string; owner: string;
pollUpdates?: any; pollUpdates?: any;
} }
const messageUpdateSchema = new Schema<MessageUpdateRaw>({ const messageUpdateSchema = new Schema<MessageUpdateRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
remoteJid: { type: String, required: true, min: 1 }, remoteJid: { type: String, required: true, min: 1 },
id: { type: String, required: true, min: 1 }, id: { type: String, required: true, min: 1 },
fromMe: { type: Boolean, required: true }, fromMe: { type: Boolean, required: true },
participant: { type: String, min: 1 }, participant: { type: String, min: 1 },
datetime: { type: Number, required: true, min: 1 }, datetime: { type: Number, required: true, min: 1 },
status: { type: String, required: true }, status: { type: String, required: true },
owner: { type: String, required: true, min: 1 }, owner: { type: String, required: true, min: 1 },
}); });
export const MessageUpModel = dbserver?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate'); export const MessageUpModel = dbserver?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate');
export type IMessageUpModel = typeof MessageUpModel; export type IMessageUpModel = typeof MessageUpModel;

View File

@ -0,0 +1,22 @@
import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect';
export class OpenaiRaw {
_id?: string;
chave?: string;
prompts?: string;
enabled?: boolean;
events?: string[];
}
const openaiSchema = new Schema<OpenaiRaw>({
_id: { type: String, _id: true },
chave: { type: String, required: true },
prompts: { type: String, required: false },
enabled: { type: Boolean, required: true },
events: { type: [String], required: true },
});
export const OpenaiModel = dbserver?.model(OpenaiRaw.name, openaiSchema, 'openai');
export type IOpenaiModel = typeof OpenaiModel;

36
src/whatsapp/models/proxy.model.ts Normal file → Executable file
View File

@ -1,18 +1,18 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class ProxyRaw { export class ProxyRaw {
_id?: string; _id?: string;
enabled?: boolean; enabled?: boolean;
proxy?: string; proxy?: string;
} }
const proxySchema = new Schema<ProxyRaw>({ const proxySchema = new Schema<ProxyRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
proxy: { type: String, required: true }, proxy: { type: String, required: true },
}); });
export const ProxyModel = dbserver?.model(ProxyRaw.name, proxySchema, 'proxy'); export const ProxyModel = dbserver?.model(ProxyRaw.name, proxySchema, 'proxy');
export type IProxyModel = typeof ProxyModel; export type IProxyModel = typeof ProxyModel;

36
src/whatsapp/models/rabbitmq.model.ts Normal file → Executable file
View File

@ -1,18 +1,18 @@
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;
enabled?: boolean; enabled?: boolean;
events?: string[]; events?: string[];
} }
const rabbitmqSchema = new Schema<RabbitmqRaw>({ const rabbitmqSchema = new Schema<RabbitmqRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
events: { type: [String], required: true }, events: { type: [String], required: true },
}); });
export const RabbitmqModel = dbserver?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq'); export const RabbitmqModel = dbserver?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq');
export type IRabbitmqModel = typeof RabbitmqModel; export type IRabbitmqModel = typeof RabbitmqModel;

52
src/whatsapp/models/settings.model.ts Normal file → Executable file
View File

@ -1,26 +1,26 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class SettingsRaw { export class SettingsRaw {
_id?: string; _id?: string;
reject_call?: boolean; reject_call?: boolean;
msg_call?: string; msg_call?: string;
groups_ignore?: boolean; groups_ignore?: boolean;
always_online?: boolean; always_online?: boolean;
read_messages?: boolean; read_messages?: boolean;
read_status?: boolean; read_status?: boolean;
} }
const settingsSchema = new Schema<SettingsRaw>({ const settingsSchema = new Schema<SettingsRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
reject_call: { type: Boolean, required: true }, reject_call: { type: Boolean, required: true },
msg_call: { type: String, required: true }, msg_call: { type: String, required: true },
groups_ignore: { type: Boolean, required: true }, groups_ignore: { type: Boolean, required: true },
always_online: { type: Boolean, required: true }, always_online: { type: Boolean, required: true },
read_messages: { type: Boolean, required: true }, read_messages: { type: Boolean, required: true },
read_status: { type: Boolean, required: true }, read_status: { type: Boolean, required: true },
}); });
export const SettingsModel = dbserver?.model(SettingsRaw.name, settingsSchema, 'settings'); export const SettingsModel = dbserver?.model(SettingsRaw.name, settingsSchema, 'settings');
export type ISettingsModel = typeof SettingsModel; export type ISettingsModel = typeof SettingsModel;

36
src/whatsapp/models/sqs.model.ts Normal file → Executable file
View File

@ -1,18 +1,18 @@
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;
enabled?: boolean; enabled?: boolean;
events?: string[]; events?: string[];
} }
const sqsSchema = new Schema<SqsRaw>({ const sqsSchema = new Schema<SqsRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
events: { type: [String], required: true }, events: { type: [String], required: true },
}); });
export const SqsModel = dbserver?.model(SqsRaw.name, sqsSchema, 'sqs'); export const SqsModel = dbserver?.model(SqsRaw.name, sqsSchema, 'sqs');
export type ISqsModel = typeof SqsModel; export type ISqsModel = typeof SqsModel;

116
src/whatsapp/models/typebot.model.ts Normal file → Executable file
View File

@ -1,58 +1,58 @@
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;
sessionId?: string; sessionId?: string;
status?: string; status?: string;
createdAt?: number; createdAt?: number;
updateAt?: number; updateAt?: number;
prefilledVariables?: { prefilledVariables?: {
remoteJid?: string; remoteJid?: string;
pushName?: string; pushName?: string;
additionalData?: { [key: string]: any }; additionalData?: { [key: string]: any };
}; };
} }
export class TypebotRaw { export class TypebotRaw {
_id?: string; _id?: string;
enabled?: boolean; enabled?: boolean;
url: string; url: string;
typebot?: string; typebot?: string;
expire?: number; expire?: number;
keyword_finish?: string; keyword_finish?: string;
delay_message?: number; delay_message?: number;
unknown_message?: string; unknown_message?: string;
listening_from_me?: boolean; listening_from_me?: boolean;
sessions?: Session[]; sessions?: Session[];
} }
const typebotSchema = new Schema<TypebotRaw>({ const typebotSchema = new Schema<TypebotRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
url: { type: String, required: true }, url: { type: String, required: true },
typebot: { type: String, required: true }, typebot: { type: String, required: true },
expire: { type: Number, required: true }, expire: { type: Number, required: true },
keyword_finish: { type: String, required: true }, keyword_finish: { type: String, required: true },
delay_message: { type: Number, required: true }, delay_message: { type: Number, required: true },
unknown_message: { type: String, required: true }, unknown_message: { type: String, required: true },
listening_from_me: { type: Boolean, required: true }, listening_from_me: { type: Boolean, required: true },
sessions: [ sessions: [
{ {
remoteJid: { type: String, required: true }, remoteJid: { type: String, required: true },
sessionId: { type: String, required: true }, sessionId: { type: String, required: true },
status: { type: String, required: true }, status: { type: String, required: true },
createdAt: { type: Number, required: true }, createdAt: { type: Number, required: true },
updateAt: { type: Number, required: true }, updateAt: { type: Number, required: true },
prefilledVariables: { prefilledVariables: {
remoteJid: { type: String, required: false }, remoteJid: { type: String, required: false },
pushName: { type: String, required: false }, pushName: { type: String, required: false },
additionalData: { type: Schema.Types.Mixed, required: false }, additionalData: { type: Schema.Types.Mixed, required: false },
}, },
}, },
], ],
}); });
export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot'); export const TypebotModel = dbserver?.model(TypebotRaw.name, typebotSchema, 'typebot');
export type ITypebotModel = typeof TypebotModel; export type ITypebotModel = typeof TypebotModel;

48
src/whatsapp/models/webhook.model.ts Normal file → Executable file
View File

@ -1,24 +1,24 @@
import { Schema } from 'mongoose'; import { Schema } from 'mongoose';
import { dbserver } from '../../libs/db.connect'; import { dbserver } from '../../libs/db.connect';
export class WebhookRaw { export class WebhookRaw {
_id?: string; _id?: string;
url?: string; url?: string;
enabled?: boolean; enabled?: boolean;
events?: string[]; events?: string[];
webhook_by_events?: boolean; webhook_by_events?: boolean;
webhook_base64?: boolean; webhook_base64?: boolean;
} }
const webhookSchema = new Schema<WebhookRaw>({ const webhookSchema = new Schema<WebhookRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
url: { type: String, required: true }, url: { type: String, required: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
events: { type: [String], required: true }, events: { type: [String], required: true },
webhook_by_events: { type: Boolean, required: true }, webhook_by_events: { type: Boolean, required: true },
webhook_base64: { type: Boolean, required: true }, webhook_base64: { type: Boolean, required: true },
}); });
export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook'); export const WebhookModel = dbserver?.model(WebhookRaw.name, webhookSchema, 'webhook');
export type IWebhookModel = typeof WebhookModel; export type IWebhookModel = typeof WebhookModel;

36
src/whatsapp/models/websocket.model.ts Normal file → Executable file
View File

@ -1,18 +1,18 @@
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;
enabled?: boolean; enabled?: boolean;
events?: string[]; events?: string[];
} }
const websocketSchema = new Schema<WebsocketRaw>({ const websocketSchema = new Schema<WebsocketRaw>({
_id: { type: String, _id: true }, _id: { type: String, _id: true },
enabled: { type: Boolean, required: true }, enabled: { type: Boolean, required: true },
events: { type: [String], required: true }, events: { type: [String], required: true },
}); });
export const WebsocketModel = dbserver?.model(WebsocketRaw.name, websocketSchema, 'websocket'); export const WebsocketModel = dbserver?.model(WebsocketRaw.name, websocketSchema, 'websocket');
export type IWebsocketModel = typeof WebsocketModel; export type IWebsocketModel = typeof WebsocketModel;

130
src/whatsapp/repository/auth.repository.ts Normal file → Executable file
View File

@ -1,65 +1,65 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { Auth, ConfigService } from '../../config/env.config'; import { Auth, ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { AUTH_DIR } from '../../config/path.config'; import { AUTH_DIR } from '../../config/path.config';
import { IInsert, Repository } from '../abstract/abstract.repository'; import { IInsert, Repository } from '../abstract/abstract.repository';
import { AuthRaw, IAuthModel } from '../models'; import { AuthRaw, IAuthModel } from '../models';
export class AuthRepository extends Repository { export class AuthRepository extends Repository {
constructor(private readonly authModel: IAuthModel, readonly configService: ConfigService) { constructor(private readonly authModel: IAuthModel, readonly configService: ConfigService) {
super(configService); super(configService);
this.auth = configService.get<Auth>('AUTHENTICATION'); this.auth = configService.get<Auth>('AUTHENTICATION');
} }
private readonly auth: Auth; private readonly auth: Auth;
private readonly logger = new Logger('AuthRepository'); private readonly logger = new Logger('AuthRepository');
public async create(data: AuthRaw, instance: string): Promise<IInsert> { public async create(data: AuthRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating auth'); this.logger.verbose('creating auth');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving auth to db'); this.logger.verbose('saving auth to db');
const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth'); this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving auth to store'); this.logger.verbose('saving auth to store');
this.writeStore<AuthRaw>({ this.writeStore<AuthRaw>({
path: join(AUTH_DIR, this.auth.TYPE), path: join(AUTH_DIR, this.auth.TYPE),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance); this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, this.auth.TYPE) + '/' + instance);
this.logger.verbose('auth created'); this.logger.verbose('auth created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return { error } as any; return { error } as any;
} }
} }
public async find(instance: string): Promise<AuthRaw> { public async find(instance: string): Promise<AuthRaw> {
try { try {
this.logger.verbose('finding auth'); this.logger.verbose('finding auth');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding auth in db'); this.logger.verbose('finding auth in db');
return await this.authModel.findOne({ _id: instance }); return await this.authModel.findOne({ _id: instance });
} }
this.logger.verbose('finding auth in store'); this.logger.verbose('finding auth in store');
return JSON.parse( return JSON.parse(
readFileSync(join(AUTH_DIR, this.auth.TYPE, instance + '.json'), { readFileSync(join(AUTH_DIR, this.auth.TYPE, instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as AuthRaw; ) as AuthRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

124
src/whatsapp/repository/chamaai.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('ChamaaiRepository'); private readonly logger = new Logger('ChamaaiRepository');
public async create(data: ChamaaiRaw, instance: string): Promise<IInsert> { public async create(data: ChamaaiRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating chamaai'); this.logger.verbose('creating chamaai');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving chamaai to db'); this.logger.verbose('saving chamaai to db');
const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.chamaaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai'); this.logger.verbose('chamaai saved to db: ' + insert.modifiedCount + ' chamaai');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving chamaai to store'); this.logger.verbose('saving chamaai to store');
this.writeStore<ChamaaiRaw>({ this.writeStore<ChamaaiRaw>({
path: join(this.storePath, 'chamaai'), path: join(this.storePath, 'chamaai'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance); this.logger.verbose('chamaai saved to store in path: ' + join(this.storePath, 'chamaai') + '/' + instance);
this.logger.verbose('chamaai created'); this.logger.verbose('chamaai created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<ChamaaiRaw> { public async find(instance: string): Promise<ChamaaiRaw> {
try { try {
this.logger.verbose('finding chamaai'); this.logger.verbose('finding chamaai');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding chamaai in db'); this.logger.verbose('finding chamaai in db');
return await this.chamaaiModel.findOne({ _id: instance }); return await this.chamaaiModel.findOne({ _id: instance });
} }
this.logger.verbose('finding chamaai in store'); this.logger.verbose('finding chamaai in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'chamaai', instance + '.json'), { readFileSync(join(this.storePath, 'chamaai', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as ChamaaiRaw; ) as ChamaaiRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

234
src/whatsapp/repository/chat.repository.ts Normal file → Executable file
View File

@ -1,117 +1,117 @@
import { opendirSync, readFileSync, rmSync } from 'fs'; import { opendirSync, readFileSync, rmSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService, StoreConf } from '../../config/env.config'; import { ConfigService, StoreConf } 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 { ChatRaw, IChatModel } from '../models'; import { ChatRaw, IChatModel } from '../models';
export class ChatQuery { export class ChatQuery {
where: ChatRaw; where: ChatRaw;
} }
export class ChatRepository extends Repository { export class ChatRepository extends Repository {
constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) { constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('ChatRepository'); private readonly logger = new Logger('ChatRepository');
public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise<IInsert> { public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
this.logger.verbose('inserting chats'); this.logger.verbose('inserting chats');
if (data.length === 0) { if (data.length === 0) {
this.logger.verbose('no chats to insert'); this.logger.verbose('no chats to insert');
return; return;
} }
try { try {
this.logger.verbose('saving chats to store'); this.logger.verbose('saving chats to store');
if (this.dbSettings.ENABLED && saveDb) { if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('saving chats to db'); this.logger.verbose('saving chats to db');
const insert = await this.chatModel.insertMany([...data]); const insert = await this.chatModel.insertMany([...data]);
this.logger.verbose('chats saved to db: ' + insert.length + ' chats'); this.logger.verbose('chats saved to db: ' + insert.length + ' chats');
return { insertCount: insert.length }; return { insertCount: insert.length };
} }
this.logger.verbose('saving chats to store'); this.logger.verbose('saving chats to store');
const store = this.configService.get<StoreConf>('STORE'); const store = this.configService.get<StoreConf>('STORE');
if (store.CHATS) { if (store.CHATS) {
this.logger.verbose('saving chats to store'); this.logger.verbose('saving chats to store');
data.forEach((chat) => { data.forEach((chat) => {
this.writeStore<ChatRaw>({ this.writeStore<ChatRaw>({
path: join(this.storePath, 'chats', instanceName), path: join(this.storePath, 'chats', instanceName),
fileName: chat.id, fileName: chat.id,
data: chat, data: chat,
}); });
this.logger.verbose( this.logger.verbose(
'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id, 'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id,
); );
}); });
this.logger.verbose('chats saved to store'); this.logger.verbose('chats saved to store');
return { insertCount: data.length }; return { insertCount: data.length };
} }
this.logger.verbose('chats not saved to store'); this.logger.verbose('chats not saved to store');
return { insertCount: 0 }; return { insertCount: 0 };
} catch (error) { } catch (error) {
return error; return error;
} finally { } finally {
data = undefined; data = undefined;
} }
} }
public async find(query: ChatQuery): Promise<ChatRaw[]> { public async find(query: ChatQuery): Promise<ChatRaw[]> {
try { try {
this.logger.verbose('finding chats'); this.logger.verbose('finding chats');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding chats in db'); this.logger.verbose('finding chats in db');
return await this.chatModel.find({ owner: query.where.owner }); return await this.chatModel.find({ owner: query.where.owner });
} }
this.logger.verbose('finding chats in store'); this.logger.verbose('finding chats in store');
const chats: ChatRaw[] = []; const chats: ChatRaw[] = [];
const openDir = opendirSync(join(this.storePath, 'chats', query.where.owner)); const openDir = opendirSync(join(this.storePath, 'chats', query.where.owner));
for await (const dirent of openDir) { for await (const dirent of openDir) {
if (dirent.isFile()) { if (dirent.isFile()) {
chats.push( chats.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), { readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} }
} }
this.logger.verbose('chats found in store: ' + chats.length + ' chats'); this.logger.verbose('chats found in store: ' + chats.length + ' chats');
return chats; return chats;
} catch (error) { } catch (error) {
return []; return [];
} }
} }
public async delete(query: ChatQuery) { public async delete(query: ChatQuery) {
try { try {
this.logger.verbose('deleting chats'); this.logger.verbose('deleting chats');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('deleting chats in db'); this.logger.verbose('deleting chats in db');
return await this.chatModel.deleteOne({ ...query.where }); return await this.chatModel.deleteOne({ ...query.where });
} }
this.logger.verbose('deleting chats in store'); this.logger.verbose('deleting chats in store');
rmSync(join(this.storePath, 'chats', query.where.owner, query.where.id + '.josn'), { rmSync(join(this.storePath, 'chats', query.where.owner, query.where.id + '.josn'), {
force: true, force: true,
recursive: true, recursive: true,
}); });
return { deleted: { chatId: query.where.id } }; return { deleted: { chatId: query.where.id } };
} catch (error) { } catch (error) {
return { error: error?.toString() }; return { error: error?.toString() };
} }
} }
} }

124
src/whatsapp/repository/chatwoot.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('ChatwootRepository'); private readonly logger = new Logger('ChatwootRepository');
public async create(data: ChatwootRaw, instance: string): Promise<IInsert> { public async create(data: ChatwootRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating chatwoot'); this.logger.verbose('creating chatwoot');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving chatwoot to db'); this.logger.verbose('saving chatwoot to db');
const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot'); this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving chatwoot to store'); this.logger.verbose('saving chatwoot to store');
this.writeStore<ChatwootRaw>({ this.writeStore<ChatwootRaw>({
path: join(this.storePath, 'chatwoot'), path: join(this.storePath, 'chatwoot'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance); this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance);
this.logger.verbose('chatwoot created'); this.logger.verbose('chatwoot created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<ChatwootRaw> { public async find(instance: string): Promise<ChatwootRaw> {
try { try {
this.logger.verbose('finding chatwoot'); this.logger.verbose('finding chatwoot');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding chatwoot in db'); this.logger.verbose('finding chatwoot in db');
return await this.chatwootModel.findOne({ _id: instance }); return await this.chatwootModel.findOne({ _id: instance });
} }
this.logger.verbose('finding chatwoot in store'); this.logger.verbose('finding chatwoot in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'chatwoot', instance + '.json'), { readFileSync(join(this.storePath, 'chatwoot', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as ChatwootRaw; ) as ChatwootRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

342
src/whatsapp/repository/contact.repository.ts Normal file → Executable file
View File

@ -1,171 +1,171 @@
import { opendirSync, readFileSync } from 'fs'; import { opendirSync, readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService, StoreConf } from '../../config/env.config'; import { ConfigService, StoreConf } 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 { ContactRaw, IContactModel } from '../models'; import { ContactRaw, IContactModel } from '../models';
export class ContactQuery { export class ContactQuery {
where: ContactRaw; where: ContactRaw;
} }
export class ContactRepository extends Repository { export class ContactRepository extends Repository {
constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) { constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('ContactRepository'); private readonly logger = new Logger('ContactRepository');
public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> { public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
this.logger.verbose('inserting contacts'); this.logger.verbose('inserting contacts');
if (data.length === 0) { if (data.length === 0) {
this.logger.verbose('no contacts to insert'); this.logger.verbose('no contacts to insert');
return; return;
} }
try { try {
if (this.dbSettings.ENABLED && saveDb) { if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('saving contacts to db'); this.logger.verbose('saving contacts to db');
const insert = await this.contactModel.insertMany([...data]); const insert = await this.contactModel.insertMany([...data]);
this.logger.verbose('contacts saved to db: ' + insert.length + ' contacts'); this.logger.verbose('contacts saved to db: ' + insert.length + ' contacts');
return { insertCount: insert.length }; return { insertCount: insert.length };
} }
this.logger.verbose('saving contacts to store'); this.logger.verbose('saving contacts to store');
const store = this.configService.get<StoreConf>('STORE'); const store = this.configService.get<StoreConf>('STORE');
if (store.CONTACTS) { if (store.CONTACTS) {
this.logger.verbose('saving contacts to store'); this.logger.verbose('saving contacts to store');
data.forEach((contact) => { data.forEach((contact) => {
this.writeStore({ this.writeStore({
path: join(this.storePath, 'contacts', instanceName), path: join(this.storePath, 'contacts', instanceName),
fileName: contact.id, fileName: contact.id,
data: contact, data: contact,
}); });
this.logger.verbose( this.logger.verbose(
'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, 'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
); );
}); });
this.logger.verbose('contacts saved to store: ' + data.length + ' contacts'); this.logger.verbose('contacts saved to store: ' + data.length + ' contacts');
return { insertCount: data.length }; return { insertCount: data.length };
} }
this.logger.verbose('contacts not saved'); this.logger.verbose('contacts not saved');
return { insertCount: 0 }; return { insertCount: 0 };
} catch (error) { } catch (error) {
return error; return error;
} finally { } finally {
data = undefined; data = undefined;
} }
} }
public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> { public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
try { try {
this.logger.verbose('updating contacts'); this.logger.verbose('updating contacts');
if (data.length === 0) { if (data.length === 0) {
this.logger.verbose('no contacts to update'); this.logger.verbose('no contacts to update');
return; return;
} }
if (this.dbSettings.ENABLED && saveDb) { if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('updating contacts in db'); this.logger.verbose('updating contacts in db');
const contacts = data.map((contact) => { const contacts = data.map((contact) => {
return { return {
updateOne: { updateOne: {
filter: { id: contact.id }, filter: { id: contact.id },
update: { ...contact }, update: { ...contact },
upsert: true, upsert: true,
}, },
}; };
}); });
const { nModified } = await this.contactModel.bulkWrite(contacts); const { nModified } = await this.contactModel.bulkWrite(contacts);
this.logger.verbose('contacts updated in db: ' + nModified + ' contacts'); this.logger.verbose('contacts updated in db: ' + nModified + ' contacts');
return { insertCount: nModified }; return { insertCount: nModified };
} }
this.logger.verbose('updating contacts in store'); this.logger.verbose('updating contacts in store');
const store = this.configService.get<StoreConf>('STORE'); const store = this.configService.get<StoreConf>('STORE');
if (store.CONTACTS) { if (store.CONTACTS) {
this.logger.verbose('updating contacts in store'); this.logger.verbose('updating contacts in store');
data.forEach((contact) => { data.forEach((contact) => {
this.writeStore({ this.writeStore({
path: join(this.storePath, 'contacts', instanceName), path: join(this.storePath, 'contacts', instanceName),
fileName: contact.id, fileName: contact.id,
data: contact, data: contact,
}); });
this.logger.verbose( this.logger.verbose(
'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, 'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id,
); );
}); });
this.logger.verbose('contacts updated in store: ' + data.length + ' contacts'); this.logger.verbose('contacts updated in store: ' + data.length + ' contacts');
return { insertCount: data.length }; return { insertCount: data.length };
} }
this.logger.verbose('contacts not updated'); this.logger.verbose('contacts not updated');
return { insertCount: 0 }; return { insertCount: 0 };
} catch (error) { } catch (error) {
return error; return error;
} finally { } finally {
data = undefined; data = undefined;
} }
} }
public async find(query: ContactQuery): Promise<ContactRaw[]> { public async find(query: ContactQuery): Promise<ContactRaw[]> {
try { try {
this.logger.verbose('finding contacts'); this.logger.verbose('finding contacts');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding contacts in db'); this.logger.verbose('finding contacts in db');
return await this.contactModel.find({ ...query.where }); return await this.contactModel.find({ ...query.where });
} }
this.logger.verbose('finding contacts in store'); this.logger.verbose('finding contacts in store');
const contacts: ContactRaw[] = []; const contacts: ContactRaw[] = [];
if (query?.where?.id) { if (query?.where?.id) {
this.logger.verbose('finding contacts in store by id'); this.logger.verbose('finding contacts in store by id');
contacts.push( contacts.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), { readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} else { } else {
this.logger.verbose('finding contacts in store by owner'); this.logger.verbose('finding contacts in store by owner');
const openDir = opendirSync(join(this.storePath, 'contacts', query.where.owner), { const openDir = opendirSync(join(this.storePath, 'contacts', query.where.owner), {
encoding: 'utf-8', encoding: 'utf-8',
}); });
for await (const dirent of openDir) { for await (const dirent of openDir) {
if (dirent.isFile()) { if (dirent.isFile()) {
contacts.push( contacts.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), { readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} }
} }
} }
this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts'); this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts');
return contacts; return contacts;
} catch (error) { } catch (error) {
return []; return [];
} }
} }
} }

294
src/whatsapp/repository/message.repository.ts Normal file → Executable file
View File

@ -1,147 +1,147 @@
import { opendirSync, readFileSync } from 'fs'; import { opendirSync, readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService, StoreConf } from '../../config/env.config'; import { ConfigService, StoreConf } 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 { IMessageModel, MessageRaw } from '../models'; import { IMessageModel, MessageRaw } from '../models';
export class MessageQuery { export class MessageQuery {
where: MessageRaw; where: MessageRaw;
limit?: number; limit?: number;
} }
export class MessageRepository extends Repository { export class MessageRepository extends Repository {
constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) { constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('MessageRepository'); private readonly logger = new Logger('MessageRepository');
public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise<IInsert> { public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise<IInsert> {
this.logger.verbose('inserting messages'); this.logger.verbose('inserting messages');
if (!Array.isArray(data) || data.length === 0) { if (!Array.isArray(data) || data.length === 0) {
this.logger.verbose('no messages to insert'); this.logger.verbose('no messages to insert');
return; return;
} }
try { try {
if (this.dbSettings.ENABLED && saveDb) { if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('saving messages to db'); this.logger.verbose('saving messages to db');
const cleanedData = data.map((obj) => { const cleanedData = data.map((obj) => {
const cleanedObj = { ...obj }; const cleanedObj = { ...obj };
if ('extendedTextMessage' in obj.message) { if ('extendedTextMessage' in obj.message) {
const extendedTextMessage = obj.message.extendedTextMessage as { const extendedTextMessage = obj.message.extendedTextMessage as {
contextInfo?: { contextInfo?: {
mentionedJid?: any; mentionedJid?: any;
}; };
}; };
if (typeof extendedTextMessage === 'object' && extendedTextMessage !== null) { if (typeof extendedTextMessage === 'object' && extendedTextMessage !== null) {
if ('contextInfo' in extendedTextMessage) { if ('contextInfo' in extendedTextMessage) {
delete extendedTextMessage.contextInfo?.mentionedJid; delete extendedTextMessage.contextInfo?.mentionedJid;
extendedTextMessage.contextInfo = {}; extendedTextMessage.contextInfo = {};
} }
} }
} }
return cleanedObj; return cleanedObj;
}); });
const insert = await this.messageModel.insertMany([...cleanedData]); const insert = await this.messageModel.insertMany([...cleanedData]);
this.logger.verbose('messages saved to db: ' + insert.length + ' messages'); this.logger.verbose('messages saved to db: ' + insert.length + ' messages');
return { insertCount: insert.length }; return { insertCount: insert.length };
} }
this.logger.verbose('saving messages to store'); this.logger.verbose('saving messages to store');
const store = this.configService.get<StoreConf>('STORE'); const store = this.configService.get<StoreConf>('STORE');
if (store.MESSAGES) { if (store.MESSAGES) {
this.logger.verbose('saving messages to store'); this.logger.verbose('saving messages to store');
data.forEach((message) => { data.forEach((message) => {
this.writeStore({ this.writeStore({
path: join(this.storePath, 'messages', instanceName), path: join(this.storePath, 'messages', instanceName),
fileName: message.key.id, fileName: message.key.id,
data: message, data: message,
}); });
this.logger.verbose( this.logger.verbose(
'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id, 'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id,
); );
}); });
this.logger.verbose('messages saved to store: ' + data.length + ' messages'); this.logger.verbose('messages saved to store: ' + data.length + ' messages');
return { insertCount: data.length }; return { insertCount: data.length };
} }
this.logger.verbose('messages not saved to store'); this.logger.verbose('messages not saved to store');
return { insertCount: 0 }; return { insertCount: 0 };
} catch (error) { } catch (error) {
console.log('ERROR: ', error); console.log('ERROR: ', error);
return error; return error;
} finally { } finally {
data = undefined; data = undefined;
} }
} }
public async find(query: MessageQuery) { public async find(query: MessageQuery) {
try { try {
this.logger.verbose('finding messages'); this.logger.verbose('finding messages');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding messages in db'); this.logger.verbose('finding messages in db');
if (query?.where?.key) { if (query?.where?.key) {
for (const [k, v] of Object.entries(query.where.key)) { for (const [k, v] of Object.entries(query.where.key)) {
query.where['key.' + k] = v; query.where['key.' + k] = v;
} }
delete query?.where?.key; delete query?.where?.key;
} }
return await this.messageModel return await this.messageModel
.find({ ...query.where }) .find({ ...query.where })
.sort({ messageTimestamp: -1 }) .sort({ messageTimestamp: -1 })
.limit(query?.limit ?? 0); .limit(query?.limit ?? 0);
} }
this.logger.verbose('finding messages in store'); this.logger.verbose('finding messages in store');
const messages: MessageRaw[] = []; const messages: MessageRaw[] = [];
if (query?.where?.key?.id) { if (query?.where?.key?.id) {
this.logger.verbose('finding messages in store by id'); this.logger.verbose('finding messages in store by id');
messages.push( messages.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), { readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} else { } else {
this.logger.verbose('finding messages in store by owner'); this.logger.verbose('finding messages in store by owner');
const openDir = opendirSync(join(this.storePath, 'messages', query.where.owner), { const openDir = opendirSync(join(this.storePath, 'messages', query.where.owner), {
encoding: 'utf-8', encoding: 'utf-8',
}); });
for await (const dirent of openDir) { for await (const dirent of openDir) {
if (dirent.isFile()) { if (dirent.isFile()) {
messages.push( messages.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), { readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} }
} }
} }
this.logger.verbose('messages found in store: ' + messages.length + ' messages'); this.logger.verbose('messages found in store: ' + messages.length + ' messages');
return messages return messages
.sort((x, y) => { .sort((x, y) => {
return (y.messageTimestamp as number) - (x.messageTimestamp as number); return (y.messageTimestamp as number) - (x.messageTimestamp as number);
}) })
.splice(0, query?.limit ?? messages.length); .splice(0, query?.limit ?? messages.length);
} catch (error) { } catch (error) {
return []; return [];
} }
} }
} }

240
src/whatsapp/repository/messageUp.repository.ts Normal file → Executable file
View File

@ -1,120 +1,120 @@
import { opendirSync, readFileSync } from 'fs'; import { opendirSync, readFileSync } from 'fs';
import { join } from 'path'; import { join } from 'path';
import { ConfigService, StoreConf } from '../../config/env.config'; import { ConfigService, StoreConf } 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 { IMessageUpModel, MessageUpdateRaw } from '../models'; import { IMessageUpModel, MessageUpdateRaw } from '../models';
export class MessageUpQuery { export class MessageUpQuery {
where: MessageUpdateRaw; where: MessageUpdateRaw;
limit?: number; limit?: number;
} }
export class MessageUpRepository extends Repository { export class MessageUpRepository extends Repository {
constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) { constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('MessageUpRepository'); private readonly logger = new Logger('MessageUpRepository');
public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise<IInsert> { public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise<IInsert> {
this.logger.verbose('inserting message up'); this.logger.verbose('inserting message up');
if (data.length === 0) { if (data.length === 0) {
this.logger.verbose('no message up to insert'); this.logger.verbose('no message up to insert');
return; return;
} }
try { try {
if (this.dbSettings.ENABLED && saveDb) { if (this.dbSettings.ENABLED && saveDb) {
this.logger.verbose('saving message up to db'); this.logger.verbose('saving message up to db');
const insert = await this.messageUpModel.insertMany([...data]); const insert = await this.messageUpModel.insertMany([...data]);
this.logger.verbose('message up saved to db: ' + insert.length + ' message up'); this.logger.verbose('message up saved to db: ' + insert.length + ' message up');
return { insertCount: insert.length }; return { insertCount: insert.length };
} }
this.logger.verbose('saving message up to store'); this.logger.verbose('saving message up to store');
const store = this.configService.get<StoreConf>('STORE'); const store = this.configService.get<StoreConf>('STORE');
if (store.MESSAGE_UP) { if (store.MESSAGE_UP) {
this.logger.verbose('saving message up to store'); this.logger.verbose('saving message up to store');
data.forEach((update) => { data.forEach((update) => {
this.writeStore<MessageUpdateRaw>({ this.writeStore<MessageUpdateRaw>({
path: join(this.storePath, 'message-up', instanceName), path: join(this.storePath, 'message-up', instanceName),
fileName: update.id, fileName: update.id,
data: update, data: update,
}); });
this.logger.verbose( this.logger.verbose(
'message up saved to store in path: ' + join(this.storePath, 'message-up', instanceName) + '/' + update.id, 'message up saved to store in path: ' + join(this.storePath, 'message-up', instanceName) + '/' + update.id,
); );
}); });
this.logger.verbose('message up saved to store: ' + data.length + ' message up'); this.logger.verbose('message up saved to store: ' + data.length + ' message up');
return { insertCount: data.length }; return { insertCount: data.length };
} }
this.logger.verbose('message up not saved to store'); this.logger.verbose('message up not saved to store');
return { insertCount: 0 }; return { insertCount: 0 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(query: MessageUpQuery) { public async find(query: MessageUpQuery) {
try { try {
this.logger.verbose('finding message up'); this.logger.verbose('finding message up');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding message up in db'); this.logger.verbose('finding message up in db');
return await this.messageUpModel return await this.messageUpModel
.find({ ...query.where }) .find({ ...query.where })
.sort({ datetime: -1 }) .sort({ datetime: -1 })
.limit(query?.limit ?? 0); .limit(query?.limit ?? 0);
} }
this.logger.verbose('finding message up in store'); this.logger.verbose('finding message up in store');
const messageUpdate: MessageUpdateRaw[] = []; const messageUpdate: MessageUpdateRaw[] = [];
if (query?.where?.id) { if (query?.where?.id) {
this.logger.verbose('finding message up in store by id'); this.logger.verbose('finding message up in store by id');
messageUpdate.push( messageUpdate.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), { readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} else { } else {
this.logger.verbose('finding message up in store by owner'); this.logger.verbose('finding message up in store by owner');
const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), { const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), {
encoding: 'utf-8', encoding: 'utf-8',
}); });
for await (const dirent of openDir) { for await (const dirent of openDir) {
if (dirent.isFile()) { if (dirent.isFile()) {
messageUpdate.push( messageUpdate.push(
JSON.parse( JSON.parse(
readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), { readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
), ),
); );
} }
} }
} }
this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up'); this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up');
return messageUpdate return messageUpdate
.sort((x, y) => { .sort((x, y) => {
return y.datetime - x.datetime; return y.datetime - x.datetime;
}) })
.splice(0, query?.limit ?? messageUpdate.length); .splice(0, query?.limit ?? messageUpdate.length);
} catch (error) { } catch (error) {
return []; return [];
} }
} }
} }

View File

@ -0,0 +1,153 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { ConfigService } from '../../config/env.config';
import { Logger } from '../../config/logger.config';
import { IInsert, Repository } from '../abstract/abstract.repository';
import { IContactOpenaiModel, ContactOpenaiRaw, IOpenaiModel, OpenaiRaw } from '../models';
export class OpenaiRepository extends Repository {
constructor(
private readonly openaiModel: IOpenaiModel,
private readonly contactopenaiModel: IContactOpenaiModel,
private readonly configService: ConfigService
) {
super(configService);
}
private readonly logger = new Logger('OpenaiRepository');
public async create(data: OpenaiRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating openai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving openai to db');
const insert = await this.openaiModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('openai saved to db: ' + insert.modifiedCount + ' openai');
return { insertCount: insert.modifiedCount };
}
this.logger.verbose('saving openai to store');
this.writeStore<OpenaiRaw>({
path: join(this.storePath, 'openai'),
fileName: instance,
data,
});
this.logger.verbose('openai saved to store in path: ' + join(this.storePath, 'openai') + '/' + instance);
this.logger.verbose('openai created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async createContact(data: ContactOpenaiRaw, instance: string): Promise<IInsert> {
try {
this.logger.verbose('creating contact openai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('saving openai to db');
var resultado = await this.openaiModel.findOne({ owner: instance, contact: data.contact });
if(!resultado){
const insert = await this.contactopenaiModel.insertMany({ ...data });
this.logger.verbose('openai saved to db: ' + insert.length + ' openai_contacts');
return { insertCount: insert.length };
}else{
const contacts = []
contacts[0] = {
updateOne: {
filter: { owner: data.owner, contact: data.contact },
update: { ...data },
upsert: true,
},
};
const { nModified } = await this.contactopenaiModel.bulkWrite(contacts);
this.logger.verbose('contacts updated in db: ' + nModified + ' contacts');
return { insertCount: nModified };
}
}
this.logger.verbose('saving openai to store');
this.writeStore<OpenaiRaw>({
path: join(this.storePath, 'openai_contact'),
fileName: instance,
data,
});
this.logger.verbose('openai contact saved to store in path: ' + join(this.storePath, 'openai_contact') + '/' + instance);
this.logger.verbose('openai contact created');
return { insertCount: 1 };
} catch (error) {
return error;
}
}
public async find(instance: string): Promise<OpenaiRaw> {
try {
this.logger.verbose('finding openai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding openai in db');
return await this.openaiModel.findOne({ _id: instance });
}
this.logger.verbose('finding openai in store');
return JSON.parse(
readFileSync(join(this.storePath, 'openai', instance + '.json'), {
encoding: 'utf-8',
}),
) as OpenaiRaw;
} catch (error) {
return {};
}
}
public async findContact(instance: string, contact: string): Promise<ContactOpenaiRaw> {
try {
this.logger.verbose('finding openai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding openai in db');
return await this.contactopenaiModel.findOne({ owner: instance,contact: contact});
}
this.logger.verbose('finding openai in store');
return JSON.parse(
readFileSync(join(this.storePath, 'openai_contact', instance + '.json'), {
encoding: 'utf-8',
}),
) as ContactOpenaiRaw;
} catch (error) {
return ;
}
}
public async findContactAll(instance: string): Promise<any> {
try {
this.logger.verbose('finding openai');
if (this.dbSettings.ENABLED) {
this.logger.verbose('finding openai in db');
return await this.contactopenaiModel.find({ owner: instance });
}
this.logger.verbose('finding openai in store');
return JSON.parse(
readFileSync(join(this.storePath, 'openai_contact', instance + '.json'), {
encoding: 'utf-8',
}),
) as ContactOpenaiRaw;
} catch (error) {
return;
}
}
}

124
src/whatsapp/repository/proxy.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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 { IProxyModel, ProxyRaw } from '../models'; import { IProxyModel, ProxyRaw } from '../models';
export class ProxyRepository extends Repository { export class ProxyRepository extends Repository {
constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) { constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('ProxyRepository'); private readonly logger = new Logger('ProxyRepository');
public async create(data: ProxyRaw, instance: string): Promise<IInsert> { public async create(data: ProxyRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating proxy'); this.logger.verbose('creating proxy');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving proxy to db'); this.logger.verbose('saving proxy to db');
const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy'); this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving proxy to store'); this.logger.verbose('saving proxy to store');
this.writeStore<ProxyRaw>({ this.writeStore<ProxyRaw>({
path: join(this.storePath, 'proxy'), path: join(this.storePath, 'proxy'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance); this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance);
this.logger.verbose('proxy created'); this.logger.verbose('proxy created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<ProxyRaw> { public async find(instance: string): Promise<ProxyRaw> {
try { try {
this.logger.verbose('finding proxy'); this.logger.verbose('finding proxy');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding proxy in db'); this.logger.verbose('finding proxy in db');
return await this.proxyModel.findOne({ _id: instance }); return await this.proxyModel.findOne({ _id: instance });
} }
this.logger.verbose('finding proxy in store'); this.logger.verbose('finding proxy in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'proxy', instance + '.json'), { readFileSync(join(this.storePath, 'proxy', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as ProxyRaw; ) as ProxyRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

124
src/whatsapp/repository/rabbitmq.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('RabbitmqRepository'); private readonly logger = new Logger('RabbitmqRepository');
public async create(data: RabbitmqRaw, instance: string): Promise<IInsert> { public async create(data: RabbitmqRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating rabbitmq'); this.logger.verbose('creating rabbitmq');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving rabbitmq to db'); this.logger.verbose('saving rabbitmq to db');
const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq'); this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving rabbitmq to store'); this.logger.verbose('saving rabbitmq to store');
this.writeStore<RabbitmqRaw>({ this.writeStore<RabbitmqRaw>({
path: join(this.storePath, 'rabbitmq'), path: join(this.storePath, 'rabbitmq'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance); this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance);
this.logger.verbose('rabbitmq created'); this.logger.verbose('rabbitmq created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<RabbitmqRaw> { public async find(instance: string): Promise<RabbitmqRaw> {
try { try {
this.logger.verbose('finding rabbitmq'); this.logger.verbose('finding rabbitmq');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding rabbitmq in db'); this.logger.verbose('finding rabbitmq in db');
return await this.rabbitmqModel.findOne({ _id: instance }); return await this.rabbitmqModel.findOne({ _id: instance });
} }
this.logger.verbose('finding rabbitmq in store'); this.logger.verbose('finding rabbitmq in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), { readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as RabbitmqRaw; ) as RabbitmqRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

328
src/whatsapp/repository/repository.manager.ts Normal file → Executable file
View File

@ -1,159 +1,169 @@
import fs from 'fs'; import fs from 'fs';
import { MongoClient } from 'mongodb'; import { MongoClient } from 'mongodb';
import { join } from 'path'; 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 { AuthRepository } from './auth.repository'; import { AuthRepository } from './auth.repository';
import { ChamaaiRepository } from './chamaai.repository'; import { ChamaaiRepository } from './chamaai.repository';
import { ChatRepository } from './chat.repository'; import { ChatRepository } from './chat.repository';
import { ChatwootRepository } from './chatwoot.repository'; import { ChatwootRepository } from './chatwoot.repository';
import { ContactRepository } from './contact.repository'; import { ContactRepository } from './contact.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 { RabbitmqRepository } from './rabbitmq.repository';
import { SettingsRepository } from './settings.repository'; import { OpenaiRepository } from './openai.repository';
import { SqsRepository } from './sqs.repository'; import { SettingsRepository } from './settings.repository';
import { TypebotRepository } from './typebot.repository'; import { SqsRepository } from './sqs.repository';
import { WebhookRepository } from './webhook.repository'; import { TypebotRepository } from './typebot.repository';
import { WebsocketRepository } from './websocket.repository'; import { WebhookRepository } from './webhook.repository';
export class RepositoryBroker { import { WebsocketRepository } from './websocket.repository';
constructor( export class RepositoryBroker {
public readonly message: MessageRepository, constructor(
public readonly chat: ChatRepository, public readonly message: MessageRepository,
public readonly contact: ContactRepository, public readonly chat: ChatRepository,
public readonly messageUpdate: MessageUpRepository, public readonly contact: ContactRepository,
public readonly webhook: WebhookRepository, public readonly messageUpdate: MessageUpRepository,
public readonly chatwoot: ChatwootRepository, public readonly webhook: WebhookRepository,
public readonly settings: SettingsRepository, public readonly chatwoot: ChatwootRepository,
public readonly websocket: WebsocketRepository, public readonly settings: SettingsRepository,
public readonly rabbitmq: RabbitmqRepository, public readonly websocket: WebsocketRepository,
public readonly sqs: SqsRepository, public readonly rabbitmq: RabbitmqRepository,
public readonly typebot: TypebotRepository, public readonly openai: OpenaiRepository,
public readonly proxy: ProxyRepository, public readonly openai_contact: OpenaiRepository,
public readonly chamaai: ChamaaiRepository, public readonly sqs: SqsRepository,
public readonly auth: AuthRepository, public readonly typebot: TypebotRepository,
private configService: ConfigService, public readonly proxy: ProxyRepository,
dbServer?: MongoClient, public readonly chamaai: ChamaaiRepository,
) { public readonly auth: AuthRepository,
this.dbClient = dbServer; private configService: ConfigService,
this.__init_repo_without_db__(); dbServer?: MongoClient,
} ) {
this.dbClient = dbServer;
private dbClient?: MongoClient; this.__init_repo_without_db__();
private readonly logger = new Logger('RepositoryBroker'); }
public get dbServer() { private dbClient?: MongoClient;
return this.dbClient; private readonly logger = new Logger('RepositoryBroker');
}
public get dbServer() {
private __init_repo_without_db__() { return this.dbClient;
this.logger.verbose('initializing repository without db'); }
if (!this.configService.get<Database>('DATABASE').ENABLED) {
const storePath = join(process.cwd(), 'store'); private __init_repo_without_db__() {
this.logger.verbose('initializing repository without db');
this.logger.verbose('creating store path: ' + storePath); if (!this.configService.get<Database>('DATABASE').ENABLED) {
try { const storePath = join(process.cwd(), 'store');
const authDir = join(storePath, 'auth', this.configService.get<Auth>('AUTHENTICATION').TYPE);
const chatsDir = join(storePath, 'chats'); this.logger.verbose('creating store path: ' + storePath);
const contactsDir = join(storePath, 'contacts'); try {
const messagesDir = join(storePath, 'messages'); const authDir = join(storePath, 'auth', this.configService.get<Auth>('AUTHENTICATION').TYPE);
const messageUpDir = join(storePath, 'message-up'); const chatsDir = join(storePath, 'chats');
const webhookDir = join(storePath, 'webhook'); const contactsDir = join(storePath, 'contacts');
const chatwootDir = join(storePath, 'chatwoot'); const messagesDir = join(storePath, 'messages');
const settingsDir = join(storePath, 'settings'); const messageUpDir = join(storePath, 'message-up');
const websocketDir = join(storePath, 'websocket'); const webhookDir = join(storePath, 'webhook');
const rabbitmqDir = join(storePath, 'rabbitmq'); const chatwootDir = join(storePath, 'chatwoot');
const sqsDir = join(storePath, 'sqs'); const settingsDir = join(storePath, 'settings');
const typebotDir = join(storePath, 'typebot'); const sqsDir = join(storePath, 'sqs');
const proxyDir = join(storePath, 'proxy'); const websocketDir = join(storePath, 'websocket');
const chamaaiDir = join(storePath, 'chamaai'); const rabbitmqDir = join(storePath, 'rabbitmq');
const tempDir = join(storePath, 'temp'); const openaiDir = join(storePath, 'openai');
const typebotDir = join(storePath, 'typebot');
if (!fs.existsSync(authDir)) { const proxyDir = join(storePath, 'proxy');
this.logger.verbose('creating auth dir: ' + authDir); const chamaaiDir = join(storePath, 'chamaai');
fs.mkdirSync(authDir, { recursive: true }); const tempDir = join(storePath, 'temp');
}
if (!fs.existsSync(chatsDir)) { if (!fs.existsSync(authDir)) {
this.logger.verbose('creating chats dir: ' + chatsDir); this.logger.verbose('creating auth dir: ' + authDir);
fs.mkdirSync(chatsDir, { recursive: true }); fs.mkdirSync(authDir, { recursive: true });
} }
if (!fs.existsSync(contactsDir)) { if (!fs.existsSync(chatsDir)) {
this.logger.verbose('creating contacts dir: ' + contactsDir); this.logger.verbose('creating chats dir: ' + chatsDir);
fs.mkdirSync(contactsDir, { recursive: true }); fs.mkdirSync(chatsDir, { recursive: true });
} }
if (!fs.existsSync(messagesDir)) { if (!fs.existsSync(contactsDir)) {
this.logger.verbose('creating messages dir: ' + messagesDir); this.logger.verbose('creating contacts dir: ' + contactsDir);
fs.mkdirSync(messagesDir, { recursive: true }); fs.mkdirSync(contactsDir, { recursive: true });
} }
if (!fs.existsSync(messageUpDir)) { if (!fs.existsSync(messagesDir)) {
this.logger.verbose('creating message-up dir: ' + messageUpDir); this.logger.verbose('creating messages dir: ' + messagesDir);
fs.mkdirSync(messageUpDir, { recursive: true }); fs.mkdirSync(messagesDir, { recursive: true });
} }
if (!fs.existsSync(webhookDir)) { if (!fs.existsSync(messageUpDir)) {
this.logger.verbose('creating webhook dir: ' + webhookDir); this.logger.verbose('creating message-up dir: ' + messageUpDir);
fs.mkdirSync(webhookDir, { recursive: true }); fs.mkdirSync(messageUpDir, { recursive: true });
} }
if (!fs.existsSync(chatwootDir)) { if (!fs.existsSync(webhookDir)) {
this.logger.verbose('creating chatwoot dir: ' + chatwootDir); this.logger.verbose('creating webhook dir: ' + webhookDir);
fs.mkdirSync(chatwootDir, { recursive: true }); fs.mkdirSync(webhookDir, { recursive: true });
} }
if (!fs.existsSync(settingsDir)) { if (!fs.existsSync(chatwootDir)) {
this.logger.verbose('creating settings dir: ' + settingsDir); this.logger.verbose('creating chatwoot dir: ' + chatwootDir);
fs.mkdirSync(settingsDir, { recursive: true }); fs.mkdirSync(chatwootDir, { recursive: true });
} }
if (!fs.existsSync(websocketDir)) { if (!fs.existsSync(settingsDir)) {
this.logger.verbose('creating websocket dir: ' + websocketDir); this.logger.verbose('creating settings dir: ' + settingsDir);
fs.mkdirSync(websocketDir, { recursive: true }); fs.mkdirSync(settingsDir, { recursive: true });
} }
if (!fs.existsSync(rabbitmqDir)) {
this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir); if (!fs.existsSync(sqsDir)) {
fs.mkdirSync(rabbitmqDir, { recursive: true }); this.logger.verbose('creating sqs dir: ' + sqsDir);
} fs.mkdirSync(sqsDir, { recursive: true });
if (!fs.existsSync(sqsDir)) { }
this.logger.verbose('creating sqs dir: ' + sqsDir);
fs.mkdirSync(sqsDir, { recursive: true }); if (!fs.existsSync(websocketDir)) {
} this.logger.verbose('creating websocket dir: ' + websocketDir);
if (!fs.existsSync(typebotDir)) { fs.mkdirSync(websocketDir, { recursive: true });
this.logger.verbose('creating typebot dir: ' + typebotDir); }
fs.mkdirSync(typebotDir, { recursive: true }); if (!fs.existsSync(rabbitmqDir)) {
} this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir);
if (!fs.existsSync(proxyDir)) { fs.mkdirSync(rabbitmqDir, { recursive: true });
this.logger.verbose('creating proxy dir: ' + proxyDir); }
fs.mkdirSync(proxyDir, { recursive: true }); if (!fs.existsSync(openaiDir)) {
} this.logger.verbose('creating openai dir: ' + openaiDir);
if (!fs.existsSync(chamaaiDir)) { fs.mkdirSync(openaiDir, { recursive: true });
this.logger.verbose('creating chamaai dir: ' + chamaaiDir); }
fs.mkdirSync(chamaaiDir, { recursive: true }); if (!fs.existsSync(typebotDir)) {
} this.logger.verbose('creating typebot dir: ' + typebotDir);
if (!fs.existsSync(tempDir)) { fs.mkdirSync(typebotDir, { recursive: true });
this.logger.verbose('creating temp dir: ' + tempDir); }
fs.mkdirSync(tempDir, { recursive: true }); if (!fs.existsSync(proxyDir)) {
} this.logger.verbose('creating proxy dir: ' + proxyDir);
} catch (error) { fs.mkdirSync(proxyDir, { recursive: true });
this.logger.error(error); }
} if (!fs.existsSync(chamaaiDir)) {
} else { this.logger.verbose('creating chamaai dir: ' + chamaaiDir);
try { fs.mkdirSync(chamaaiDir, { recursive: true });
const storePath = join(process.cwd(), 'store'); }
if (!fs.existsSync(tempDir)) {
this.logger.verbose('creating store path: ' + storePath); this.logger.verbose('creating temp dir: ' + tempDir);
fs.mkdirSync(tempDir, { recursive: true });
const tempDir = join(storePath, 'temp'); }
const chatwootDir = join(storePath, 'chatwoot'); } catch (error) {
this.logger.error(error);
if (!fs.existsSync(chatwootDir)) { }
this.logger.verbose('creating chatwoot dir: ' + chatwootDir); } else {
fs.mkdirSync(chatwootDir, { recursive: true }); try {
} const storePath = join(process.cwd(), 'store');
if (!fs.existsSync(tempDir)) {
this.logger.verbose('creating temp dir: ' + tempDir); this.logger.verbose('creating store path: ' + storePath);
fs.mkdirSync(tempDir, { recursive: true });
} const tempDir = join(storePath, 'temp');
} catch (error) { const chatwootDir = join(storePath, 'chatwoot');
this.logger.error(error);
} if (!fs.existsSync(chatwootDir)) {
} this.logger.verbose('creating chatwoot dir: ' + chatwootDir);
} fs.mkdirSync(chatwootDir, { recursive: true });
} }
if (!fs.existsSync(tempDir)) {
this.logger.verbose('creating temp dir: ' + tempDir);
fs.mkdirSync(tempDir, { recursive: true });
}
} catch (error) {
this.logger.error(error);
}
}
}
}

124
src/whatsapp/repository/settings.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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 { ISettingsModel, SettingsRaw } from '../models'; import { ISettingsModel, SettingsRaw } from '../models';
export class SettingsRepository extends Repository { export class SettingsRepository extends Repository {
constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) { constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('SettingsRepository'); private readonly logger = new Logger('SettingsRepository');
public async create(data: SettingsRaw, instance: string): Promise<IInsert> { public async create(data: SettingsRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating settings'); this.logger.verbose('creating settings');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving settings to db'); this.logger.verbose('saving settings to db');
const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings'); this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving settings to store'); this.logger.verbose('saving settings to store');
this.writeStore<SettingsRaw>({ this.writeStore<SettingsRaw>({
path: join(this.storePath, 'settings'), path: join(this.storePath, 'settings'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance); this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance);
this.logger.verbose('settings created'); this.logger.verbose('settings created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<SettingsRaw> { public async find(instance: string): Promise<SettingsRaw> {
try { try {
this.logger.verbose('finding settings'); this.logger.verbose('finding settings');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding settings in db'); this.logger.verbose('finding settings in db');
return await this.settingsModel.findOne({ _id: instance }); return await this.settingsModel.findOne({ _id: instance });
} }
this.logger.verbose('finding settings in store'); this.logger.verbose('finding settings in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'settings', instance + '.json'), { readFileSync(join(this.storePath, 'settings', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as SettingsRaw; ) as SettingsRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

124
src/whatsapp/repository/sqs.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('SqsRepository'); private readonly logger = new Logger('SqsRepository');
public async create(data: SqsRaw, instance: string): Promise<IInsert> { public async create(data: SqsRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating sqs'); this.logger.verbose('creating sqs');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving sqs to db'); this.logger.verbose('saving sqs to db');
const insert = await this.sqsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.sqsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('sqs saved to db: ' + insert.modifiedCount + ' sqs'); this.logger.verbose('sqs saved to db: ' + insert.modifiedCount + ' sqs');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving sqs to store'); this.logger.verbose('saving sqs to store');
this.writeStore<SqsRaw>({ this.writeStore<SqsRaw>({
path: join(this.storePath, 'sqs'), path: join(this.storePath, 'sqs'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('sqs saved to store in path: ' + join(this.storePath, 'sqs') + '/' + instance); this.logger.verbose('sqs saved to store in path: ' + join(this.storePath, 'sqs') + '/' + instance);
this.logger.verbose('sqs created'); this.logger.verbose('sqs created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<SqsRaw> { public async find(instance: string): Promise<SqsRaw> {
try { try {
this.logger.verbose('finding sqs'); this.logger.verbose('finding sqs');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding sqs in db'); this.logger.verbose('finding sqs in db');
return await this.sqsModel.findOne({ _id: instance }); return await this.sqsModel.findOne({ _id: instance });
} }
this.logger.verbose('finding sqs in store'); this.logger.verbose('finding sqs in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'sqs', instance + '.json'), { readFileSync(join(this.storePath, 'sqs', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as SqsRaw; ) as SqsRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

136
src/whatsapp/repository/typebot.repository.ts Normal file → Executable file
View File

@ -1,68 +1,68 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('TypebotRepository'); private readonly logger = new Logger('TypebotRepository');
public async create(data: TypebotRaw, instance: string): Promise<IInsert> { public async create(data: TypebotRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating typebot'); this.logger.verbose('creating typebot');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving typebot to db'); this.logger.verbose('saving typebot to db');
const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot'); this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving typebot to store'); this.logger.verbose('saving typebot to store');
this.writeStore<TypebotRaw>({ this.writeStore<TypebotRaw>({
path: join(this.storePath, 'typebot'), path: join(this.storePath, 'typebot'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance); this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance);
this.logger.verbose('typebot created'); this.logger.verbose('typebot created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<TypebotRaw> { public async find(instance: string): Promise<TypebotRaw> {
try { try {
this.logger.verbose('finding typebot'); this.logger.verbose('finding typebot');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding typebot in db'); this.logger.verbose('finding typebot in db');
return await this.typebotModel.findOne({ _id: instance }); return await this.typebotModel.findOne({ _id: instance });
} }
this.logger.verbose('finding typebot in store'); this.logger.verbose('finding typebot in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'typebot', instance + '.json'), { readFileSync(join(this.storePath, 'typebot', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as TypebotRaw; ) as TypebotRaw;
} catch (error) { } catch (error) {
return { return {
enabled: false, enabled: false,
url: '', url: '',
typebot: '', typebot: '',
expire: 0, expire: 0,
sessions: [], sessions: [],
}; };
} }
} }
} }

124
src/whatsapp/repository/webhook.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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 { IWebhookModel, WebhookRaw } from '../models'; import { IWebhookModel, WebhookRaw } from '../models';
export class WebhookRepository extends Repository { export class WebhookRepository extends Repository {
constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) { constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) {
super(configService); super(configService);
} }
private readonly logger = new Logger('WebhookRepository'); private readonly logger = new Logger('WebhookRepository');
public async create(data: WebhookRaw, instance: string): Promise<IInsert> { public async create(data: WebhookRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating webhook'); this.logger.verbose('creating webhook');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving webhook to db'); this.logger.verbose('saving webhook to db');
const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook'); this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving webhook to store'); this.logger.verbose('saving webhook to store');
this.writeStore<WebhookRaw>({ this.writeStore<WebhookRaw>({
path: join(this.storePath, 'webhook'), path: join(this.storePath, 'webhook'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance); this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance);
this.logger.verbose('webhook created'); this.logger.verbose('webhook created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<WebhookRaw> { public async find(instance: string): Promise<WebhookRaw> {
try { try {
this.logger.verbose('finding webhook'); this.logger.verbose('finding webhook');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding webhook in db'); this.logger.verbose('finding webhook in db');
return await this.webhookModel.findOne({ _id: instance }); return await this.webhookModel.findOne({ _id: instance });
} }
this.logger.verbose('finding webhook in store'); this.logger.verbose('finding webhook in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'webhook', instance + '.json'), { readFileSync(join(this.storePath, 'webhook', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as WebhookRaw; ) as WebhookRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

124
src/whatsapp/repository/websocket.repository.ts Normal file → Executable file
View File

@ -1,62 +1,62 @@
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) {
super(configService); super(configService);
} }
private readonly logger = new Logger('WebsocketRepository'); private readonly logger = new Logger('WebsocketRepository');
public async create(data: WebsocketRaw, instance: string): Promise<IInsert> { public async create(data: WebsocketRaw, instance: string): Promise<IInsert> {
try { try {
this.logger.verbose('creating websocket'); this.logger.verbose('creating websocket');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('saving websocket to db'); this.logger.verbose('saving websocket to db');
const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true });
this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket'); this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket');
return { insertCount: insert.modifiedCount }; return { insertCount: insert.modifiedCount };
} }
this.logger.verbose('saving websocket to store'); this.logger.verbose('saving websocket to store');
this.writeStore<WebsocketRaw>({ this.writeStore<WebsocketRaw>({
path: join(this.storePath, 'websocket'), path: join(this.storePath, 'websocket'),
fileName: instance, fileName: instance,
data, data,
}); });
this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance); this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance);
this.logger.verbose('websocket created'); this.logger.verbose('websocket created');
return { insertCount: 1 }; return { insertCount: 1 };
} catch (error) { } catch (error) {
return error; return error;
} }
} }
public async find(instance: string): Promise<WebsocketRaw> { public async find(instance: string): Promise<WebsocketRaw> {
try { try {
this.logger.verbose('finding websocket'); this.logger.verbose('finding websocket');
if (this.dbSettings.ENABLED) { if (this.dbSettings.ENABLED) {
this.logger.verbose('finding websocket in db'); this.logger.verbose('finding websocket in db');
return await this.websocketModel.findOne({ _id: instance }); return await this.websocketModel.findOne({ _id: instance });
} }
this.logger.verbose('finding websocket in store'); this.logger.verbose('finding websocket in store');
return JSON.parse( return JSON.parse(
readFileSync(join(this.storePath, 'websocket', instance + '.json'), { readFileSync(join(this.storePath, 'websocket', instance + '.json'), {
encoding: 'utf-8', encoding: 'utf-8',
}), }),
) as WebsocketRaw; ) as WebsocketRaw;
} catch (error) { } catch (error) {
return {}; return {};
} }
} }
} }

104
src/whatsapp/routers/chamaai.router.ts Normal file → Executable file
View File

@ -1,52 +1,52 @@
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 { ChamaaiDto } from '../dto/chamaai.dto'; import { ChamaaiDto } from '../dto/chamaai.dto';
import { InstanceDto } from '../dto/instance.dto'; import { InstanceDto } from '../dto/instance.dto';
import { chamaaiController } from '../whatsapp.module'; import { chamaaiController } from '../whatsapp.module';
import { HttpStatus } from './index.router'; import { HttpStatus } from './index.router';
const logger = new Logger('ChamaaiRouter'); const logger = new Logger('ChamaaiRouter');
export class ChamaaiRouter extends RouterBroker { export class ChamaaiRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) { constructor(...guards: RequestHandler[]) {
super(); super();
this.router this.router
.post(this.routerPath('set'), ...guards, async (req, res) => { .post(this.routerPath('set'), ...guards, async (req, res) => {
logger.verbose('request received in setChamaai'); logger.verbose('request received in setChamaai');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ChamaaiDto>({ const response = await this.dataValidate<ChamaaiDto>({
request: req, request: req,
schema: chamaaiSchema, schema: chamaaiSchema,
ClassRef: ChamaaiDto, ClassRef: ChamaaiDto,
execute: (instance, data) => chamaaiController.createChamaai(instance, data), execute: (instance, data) => chamaaiController.createChamaai(instance, data),
}); });
res.status(HttpStatus.CREATED).json(response); res.status(HttpStatus.CREATED).json(response);
}) })
.get(this.routerPath('find'), ...guards, async (req, res) => { .get(this.routerPath('find'), ...guards, async (req, res) => {
logger.verbose('request received in findChamaai'); logger.verbose('request received in findChamaai');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({ const response = await this.dataValidate<InstanceDto>({
request: req, request: req,
schema: instanceNameSchema, schema: instanceNameSchema,
ClassRef: InstanceDto, ClassRef: InstanceDto,
execute: (instance) => chamaaiController.findChamaai(instance), execute: (instance) => chamaaiController.findChamaai(instance),
}); });
res.status(HttpStatus.OK).json(response); res.status(HttpStatus.OK).json(response);
}); });
} }
public readonly router = Router(); public readonly router = Router();
} }

708
src/whatsapp/routers/chat.router.ts Normal file → Executable file
View File

@ -1,354 +1,354 @@
import { RequestHandler, Router } from 'express'; import { RequestHandler, Router } from 'express';
import { Logger } from '../../config/logger.config'; import { Logger } from '../../config/logger.config';
import { import {
archiveChatSchema, archiveChatSchema,
contactValidateSchema, contactValidateSchema,
deleteMessageSchema, deleteMessageSchema,
messageUpSchema, messageUpSchema,
messageValidateSchema, messageValidateSchema,
privacySettingsSchema, privacySettingsSchema,
profileNameSchema, profileNameSchema,
profilePictureSchema, profilePictureSchema,
profileSchema, profileSchema,
profileStatusSchema, profileStatusSchema,
readMessageSchema, readMessageSchema,
whatsappNumberSchema, whatsappNumberSchema,
} from '../../validate/validate.schema'; } from '../../validate/validate.schema';
import { RouterBroker } from '../abstract/abstract.router'; import { RouterBroker } from '../abstract/abstract.router';
import { import {
ArchiveChatDto, ArchiveChatDto,
DeleteMessage, DeleteMessage,
getBase64FromMediaMessageDto, getBase64FromMediaMessageDto,
NumberDto, NumberDto,
PrivacySettingDto, PrivacySettingDto,
ProfileNameDto, ProfileNameDto,
ProfilePictureDto, ProfilePictureDto,
ProfileStatusDto, ProfileStatusDto,
ReadMessageDto, ReadMessageDto,
WhatsAppNumberDto, WhatsAppNumberDto,
} 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';
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 '../whatsapp.module';
import { HttpStatus } from './index.router'; import { HttpStatus } from './index.router';
const logger = new Logger('ChatRouter'); const logger = new Logger('ChatRouter');
export class ChatRouter extends RouterBroker { export class ChatRouter extends RouterBroker {
constructor(...guards: RequestHandler[]) { constructor(...guards: RequestHandler[]) {
super(); super();
this.router this.router
.post(this.routerPath('whatsappNumbers'), ...guards, async (req, res) => { .post(this.routerPath('whatsappNumbers'), ...guards, async (req, res) => {
logger.verbose('request received in whatsappNumbers'); logger.verbose('request received in whatsappNumbers');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<WhatsAppNumberDto>({ const response = await this.dataValidate<WhatsAppNumberDto>({
request: req, request: req,
schema: whatsappNumberSchema, schema: whatsappNumberSchema,
ClassRef: WhatsAppNumberDto, ClassRef: WhatsAppNumberDto,
execute: (instance, data) => chatController.whatsappNumber(instance, data), execute: (instance, data) => chatController.whatsappNumber(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.put(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => { .put(this.routerPath('markMessageAsRead'), ...guards, async (req, res) => {
logger.verbose('request received in markMessageAsRead'); logger.verbose('request received in markMessageAsRead');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ReadMessageDto>({ const response = await this.dataValidate<ReadMessageDto>({
request: req, request: req,
schema: readMessageSchema, schema: readMessageSchema,
ClassRef: ReadMessageDto, ClassRef: ReadMessageDto,
execute: (instance, data) => chatController.readMessage(instance, data), execute: (instance, data) => chatController.readMessage(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.put(this.routerPath('archiveChat'), ...guards, async (req, res) => { .put(this.routerPath('archiveChat'), ...guards, async (req, res) => {
logger.verbose('request received in archiveChat'); logger.verbose('request received in archiveChat');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ArchiveChatDto>({ const response = await this.dataValidate<ArchiveChatDto>({
request: req, request: req,
schema: archiveChatSchema, schema: archiveChatSchema,
ClassRef: ArchiveChatDto, ClassRef: ArchiveChatDto,
execute: (instance, data) => chatController.archiveChat(instance, data), execute: (instance, data) => chatController.archiveChat(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.delete(this.routerPath('deleteMessageForEveryone'), ...guards, async (req, res) => { .delete(this.routerPath('deleteMessageForEveryone'), ...guards, async (req, res) => {
logger.verbose('request received in deleteMessageForEveryone'); logger.verbose('request received in deleteMessageForEveryone');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<DeleteMessage>({ const response = await this.dataValidate<DeleteMessage>({
request: req, request: req,
schema: deleteMessageSchema, schema: deleteMessageSchema,
ClassRef: DeleteMessage, ClassRef: DeleteMessage,
execute: (instance, data) => chatController.deleteMessage(instance, data), execute: (instance, data) => chatController.deleteMessage(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => { .post(this.routerPath('fetchProfilePictureUrl'), ...guards, async (req, res) => {
logger.verbose('request received in fetchProfilePictureUrl'); logger.verbose('request received in fetchProfilePictureUrl');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<NumberDto>({ const response = await this.dataValidate<NumberDto>({
request: req, request: req,
schema: profilePictureSchema, schema: profilePictureSchema,
ClassRef: NumberDto, ClassRef: NumberDto,
execute: (instance, data) => chatController.fetchProfilePicture(instance, data), execute: (instance, data) => chatController.fetchProfilePicture(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('fetchProfile'), ...guards, async (req, res) => { .post(this.routerPath('fetchProfile'), ...guards, async (req, res) => {
logger.verbose('request received in fetchProfile'); logger.verbose('request received in fetchProfile');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<NumberDto>({ const response = await this.dataValidate<NumberDto>({
request: req, request: req,
schema: profileSchema, schema: profileSchema,
ClassRef: NumberDto, ClassRef: NumberDto,
execute: (instance, data) => chatController.fetchProfile(instance, data), execute: (instance, data) => chatController.fetchProfile(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('findContacts'), ...guards, async (req, res) => { .post(this.routerPath('findContacts'), ...guards, async (req, res) => {
logger.verbose('request received in findContacts'); logger.verbose('request received in findContacts');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ContactQuery>({ const response = await this.dataValidate<ContactQuery>({
request: req, request: req,
schema: contactValidateSchema, schema: contactValidateSchema,
ClassRef: ContactQuery, ClassRef: ContactQuery,
execute: (instance, data) => chatController.fetchContacts(instance, data), execute: (instance, data) => chatController.fetchContacts(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('getBase64FromMediaMessage'), ...guards, async (req, res) => { .post(this.routerPath('getBase64FromMediaMessage'), ...guards, async (req, res) => {
logger.verbose('request received in getBase64FromMediaMessage'); logger.verbose('request received in getBase64FromMediaMessage');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<getBase64FromMediaMessageDto>({ const response = await this.dataValidate<getBase64FromMediaMessageDto>({
request: req, request: req,
schema: null, schema: null,
ClassRef: getBase64FromMediaMessageDto, ClassRef: getBase64FromMediaMessageDto,
execute: (instance, data) => chatController.getBase64FromMediaMessage(instance, data), execute: (instance, data) => chatController.getBase64FromMediaMessage(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.post(this.routerPath('findMessages'), ...guards, async (req, res) => { .post(this.routerPath('findMessages'), ...guards, async (req, res) => {
logger.verbose('request received in findMessages'); logger.verbose('request received in findMessages');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<MessageQuery>({ const response = await this.dataValidate<MessageQuery>({
request: req, request: req,
schema: messageValidateSchema, schema: messageValidateSchema,
ClassRef: MessageQuery, ClassRef: MessageQuery,
execute: (instance, data) => chatController.fetchMessages(instance, data), execute: (instance, data) => chatController.fetchMessages(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('findStatusMessage'), ...guards, async (req, res) => { .post(this.routerPath('findStatusMessage'), ...guards, async (req, res) => {
logger.verbose('request received in findStatusMessage'); logger.verbose('request received in findStatusMessage');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<MessageUpQuery>({ const response = await this.dataValidate<MessageUpQuery>({
request: req, request: req,
schema: messageUpSchema, schema: messageUpSchema,
ClassRef: MessageUpQuery, ClassRef: MessageUpQuery,
execute: (instance, data) => chatController.fetchStatusMessage(instance, data), execute: (instance, data) => chatController.fetchStatusMessage(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); 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: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({ const response = await this.dataValidate<InstanceDto>({
request: req, request: req,
schema: null, schema: null,
ClassRef: InstanceDto, ClassRef: InstanceDto,
execute: (instance) => chatController.fetchChats(instance), execute: (instance) => chatController.fetchChats(instance),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
// Profile routes // Profile routes
.get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => {
logger.verbose('request received in fetchPrivacySettings'); logger.verbose('request received in fetchPrivacySettings');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<InstanceDto>({ const response = await this.dataValidate<InstanceDto>({
request: req, request: req,
schema: null, schema: null,
ClassRef: InstanceDto, ClassRef: InstanceDto,
execute: (instance) => chatController.fetchPrivacySettings(instance), execute: (instance) => chatController.fetchPrivacySettings(instance),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.put(this.routerPath('updatePrivacySettings'), ...guards, async (req, res) => { .put(this.routerPath('updatePrivacySettings'), ...guards, async (req, res) => {
logger.verbose('request received in updatePrivacySettings'); logger.verbose('request received in updatePrivacySettings');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<PrivacySettingDto>({ const response = await this.dataValidate<PrivacySettingDto>({
request: req, request: req,
schema: privacySettingsSchema, schema: privacySettingsSchema,
ClassRef: PrivacySettingDto, ClassRef: PrivacySettingDto,
execute: (instance, data) => chatController.updatePrivacySettings(instance, data), execute: (instance, data) => chatController.updatePrivacySettings(instance, data),
}); });
return res.status(HttpStatus.CREATED).json(response); return res.status(HttpStatus.CREATED).json(response);
}) })
.post(this.routerPath('fetchBusinessProfile'), ...guards, async (req, res) => { .post(this.routerPath('fetchBusinessProfile'), ...guards, async (req, res) => {
logger.verbose('request received in fetchBusinessProfile'); logger.verbose('request received in fetchBusinessProfile');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ProfilePictureDto>({ const response = await this.dataValidate<ProfilePictureDto>({
request: req, request: req,
schema: profilePictureSchema, schema: profilePictureSchema,
ClassRef: ProfilePictureDto, ClassRef: ProfilePictureDto,
execute: (instance, data) => chatController.fetchBusinessProfile(instance, data), execute: (instance, data) => chatController.fetchBusinessProfile(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('updateProfileName'), ...guards, async (req, res) => { .post(this.routerPath('updateProfileName'), ...guards, async (req, res) => {
logger.verbose('request received in updateProfileName'); logger.verbose('request received in updateProfileName');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ProfileNameDto>({ const response = await this.dataValidate<ProfileNameDto>({
request: req, request: req,
schema: profileNameSchema, schema: profileNameSchema,
ClassRef: ProfileNameDto, ClassRef: ProfileNameDto,
execute: (instance, data) => chatController.updateProfileName(instance, data), execute: (instance, data) => chatController.updateProfileName(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.post(this.routerPath('updateProfileStatus'), ...guards, async (req, res) => { .post(this.routerPath('updateProfileStatus'), ...guards, async (req, res) => {
logger.verbose('request received in updateProfileStatus'); logger.verbose('request received in updateProfileStatus');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ProfileStatusDto>({ const response = await this.dataValidate<ProfileStatusDto>({
request: req, request: req,
schema: profileStatusSchema, schema: profileStatusSchema,
ClassRef: ProfileStatusDto, ClassRef: ProfileStatusDto,
execute: (instance, data) => chatController.updateProfileStatus(instance, data), execute: (instance, data) => chatController.updateProfileStatus(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.put(this.routerPath('updateProfilePicture'), ...guards, async (req, res) => { .put(this.routerPath('updateProfilePicture'), ...guards, async (req, res) => {
logger.verbose('request received in updateProfilePicture'); logger.verbose('request received in updateProfilePicture');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ProfilePictureDto>({ const response = await this.dataValidate<ProfilePictureDto>({
request: req, request: req,
schema: profilePictureSchema, schema: profilePictureSchema,
ClassRef: ProfilePictureDto, ClassRef: ProfilePictureDto,
execute: (instance, data) => chatController.updateProfilePicture(instance, data), execute: (instance, data) => chatController.updateProfilePicture(instance, data),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}) })
.delete(this.routerPath('removeProfilePicture'), ...guards, async (req, res) => { .delete(this.routerPath('removeProfilePicture'), ...guards, async (req, res) => {
logger.verbose('request received in removeProfilePicture'); logger.verbose('request received in removeProfilePicture');
logger.verbose('request body: '); logger.verbose('request body: ');
logger.verbose(req.body); logger.verbose(req.body);
logger.verbose('request query: '); logger.verbose('request query: ');
logger.verbose(req.query); logger.verbose(req.query);
const response = await this.dataValidate<ProfilePictureDto>({ const response = await this.dataValidate<ProfilePictureDto>({
request: req, request: req,
schema: profilePictureSchema, schema: profilePictureSchema,
ClassRef: ProfilePictureDto, ClassRef: ProfilePictureDto,
execute: (instance) => chatController.removeProfilePicture(instance), execute: (instance) => chatController.removeProfilePicture(instance),
}); });
return res.status(HttpStatus.OK).json(response); return res.status(HttpStatus.OK).json(response);
}); });
} }
public readonly router = Router(); public readonly router = Router();
} }

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