diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b96f10d..9aa6c9ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,17 @@ -# 1.8.1 (develop) +# 2.0.0 (develop) ### Feature * New method of saving sessions to a file using worker, made in partnership with [codechat](https://github.com/code-chat-br/whatsapp-api) +* Added prism orm, connection to postgres and mysql + +### Fixed +* + +### Break changes +* jwt authentication removed +* Connection to mongodb removed +* Standardized all request bodies to use camelCase +* Change in webhook information from owner to instanceId # 1.8.0 (2024-05-27 16:10) diff --git a/package.json b/package.json index 2433ea8f..2e050616 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "jsonwebtoken": "^9.0.2", "libphonenumber-js": "^1.10.39", "link-preview-js": "^3.0.4", - "mongoose": "^6.10.5", "node-cache": "^5.1.2", "node-mime-types": "^1.1.0", "node-windows": "^1.0.0-beta.8", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e4937bdf..ec5747df 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,9 +34,8 @@ enum TypebotSessionStatus { } model Instance { - id Int @id @default(autoincrement()) + id String @id @default(cuid()) name String @unique @db.VarChar(255) - description String? @db.VarChar(255) connectionStatus InstanceConnectionStatus @default(open) ownerJid String? @db.VarChar(100) profilePicUrl String? @db.VarChar(500) @@ -60,33 +59,31 @@ model Instance { } model Session { - id Int @id @unique @default(autoincrement()) - sessionId String @unique @default(cuid()) - creds String? @db.Text - createdAt DateTime @default(now()) - Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique @db.Integer - - @@map("sessions") + id Int @id @unique @default(autoincrement()) + sessionId String @unique + creds String? @db.Text + createdAt DateTime @default(now()) + Instance Instance @relation(fields: [sessionId], references: [id], onDelete: Cascade) } model Auth { id Int @id @default(autoincrement()) - apiKey String @unique + apikey String @unique createdAt DateTime? @default(now()) @db.Date updatedAt DateTime? @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique @db.Integer + instanceId String @unique } model Chat { id Int @id @default(autoincrement()) - lastMsgTimestamp DateTime? @db.Timestamp + remoteJid String @db.VarChar(100) + lastMsgTimestamp String? @db.VarChar(100) labels Json? @db.JsonB createdAt DateTime? @default(now()) @db.Date updatedAt DateTime? @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int + instanceId String } model Contact { @@ -97,79 +94,77 @@ model Contact { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime? @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int + instanceId String } model Message { id Int @id @default(autoincrement()) - keyId String @db.VarChar(100) - keyRemoteJid String @db.VarChar(100) - keyFromMe Boolean @db.Boolean - keyParticipant String? @db.VarChar(100) + key Json @db.JsonB pushName String? @db.VarChar(100) participant String? @db.VarChar(100) messageType String @db.VarChar(100) message Json @db.JsonB + contextInfo Json? @db.JsonB source DeviceMessage - messageTimestamp Int @db.Integer + messageTimestamp String @db.VarChar(100) chatwootMessageId Int? @db.Integer chatwootInboxId Int? @db.Integer chatwootConversationId Int? @db.Integer chatwootContactInboxSourceId String? @db.VarChar(100) - chatwotIsRead Boolean? @db.Boolean + chatwootIsRead Boolean? @db.Boolean Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int + instanceId String typebotSessionId Int? MessageUpdate MessageUpdate[] TypebotSession TypebotSession? @relation(fields: [typebotSessionId], references: [id]) - - @@index([keyId], name: "keyId") } model MessageUpdate { id Int @id @default(autoincrement()) + keyId String @db.VarChar(100) remoteJid String @db.VarChar(100) fromMe Boolean @db.Boolean participant String? @db.VarChar(100) dateTime DateTime @db.Date + pollUpdates Json? @db.JsonB status String @db.VarChar(30) Message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) messageId Int } model Webhook { - id Int @id @default(autoincrement()) - url String @db.VarChar(500) - enabled Boolean? @default(true) @db.Boolean - events Json? @db.JsonB - webhook_by_events Boolean? @default(false) @db.Boolean - webhook_base64 Boolean? @default(false) @db.Boolean - createdAt DateTime? @default(now()) @db.Date - updatedAt DateTime @updatedAt @db.Date - Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + id Int @id @default(autoincrement()) + url String @db.VarChar(500) + enabled Boolean? @default(true) @db.Boolean + events Json? @db.JsonB + webhookByEvents Boolean? @default(false) @db.Boolean + webhookBase64 Boolean? @default(false) @db.Boolean + createdAt DateTime? @default(now()) @db.Date + updatedAt DateTime @updatedAt @db.Date + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique } model Chatwoot { - id Int @id @default(autoincrement()) - enabled Boolean? @default(true) @db.Boolean - account_id String? @db.VarChar(100) - token String? @db.VarChar(100) - url String? @db.VarChar(500) - name_inbox String? @db.VarChar(100) - sign_msg Boolean? @default(false) @db.Boolean - sign_delimiter String? @db.VarChar(100) - number String? @db.VarChar(100) - reopen_conversation Boolean? @default(false) @db.Boolean - conversation_pending Boolean? @default(false) @db.Boolean - merge_brazil_contacts Boolean? @default(false) @db.Boolean - import_contacts Boolean? @default(false) @db.Boolean - import_messages Boolean? @default(false) @db.Boolean - days_limit_import_messages Int? @db.Integer - createdAt DateTime? @default(now()) @db.Date - updatedAt DateTime @updatedAt @db.Date - Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + id Int @id @default(autoincrement()) + enabled Boolean? @default(true) @db.Boolean + accountId String? @db.VarChar(100) + token String? @db.VarChar(100) + url String? @db.VarChar(500) + nameInbox String? @db.VarChar(100) + signMsg Boolean? @default(false) @db.Boolean + signDelimiter String? @db.VarChar(100) + number String? @db.VarChar(100) + reopenConversation Boolean? @default(false) @db.Boolean + conversationPending Boolean? @default(false) @db.Boolean + mergeBrazilContacts Boolean? @default(false) @db.Boolean + importContacts Boolean? @default(false) @db.Boolean + importMessages Boolean? @default(false) @db.Boolean + daysLimitImportMessages Int? @db.Integer + createdAt DateTime? @default(now()) @db.Date + updatedAt DateTime @updatedAt @db.Date + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique } model Integration { @@ -180,7 +175,7 @@ model Integration { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique } model Label { @@ -192,20 +187,20 @@ model Label { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int + instanceId String } model Proxy { - id Int @id @default(autoincrement()) - enabled Boolean? @default(true) @db.Boolean - proxyHost String? @db.VarChar(100) - proxyPort Int? @db.Integer - proxyUsername String? @db.VarChar(100) - proxyPassword String? @db.VarChar(100) - createdAt DateTime? @default(now()) @db.Date - updatedAt DateTime @updatedAt @db.Date - Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + id Int @id @default(autoincrement()) + enabled Boolean? @default(true) @db.Boolean + host String? @db.VarChar(100) + port String? @db.VarChar(100) + username String? @db.VarChar(100) + password String? @db.VarChar(100) + createdAt DateTime? @default(now()) @db.Date + updatedAt DateTime @updatedAt @db.Date + Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) + instanceId String @unique } model Setting { @@ -220,7 +215,7 @@ model Setting { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique } model Rabbitmq { @@ -230,7 +225,7 @@ model Rabbitmq { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique } model Sqs { @@ -240,7 +235,7 @@ model Sqs { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique } model Websocket { @@ -250,7 +245,7 @@ model Websocket { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique } model Typebot { @@ -266,7 +261,7 @@ model Typebot { createdAt DateTime? @default(now()) @db.Date updatedAt DateTime? @updatedAt @db.Date Instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade) - instanceId Int @unique + instanceId String @unique sessions TypebotSession[] } diff --git a/src/api/controllers/chat.controller.ts b/src/api/controllers/chat.controller.ts index c0a87e2e..e26bf54c 100644 --- a/src/api/controllers/chat.controller.ts +++ b/src/api/controllers/chat.controller.ts @@ -1,3 +1,5 @@ +import { Contact, Message, MessageUpdate } from '@prisma/client'; + import { Logger } from '../../config/logger.config'; import { ArchiveChatDto, @@ -16,9 +18,7 @@ import { WhatsAppNumberDto, } from '../dto/chat.dto'; import { InstanceDto } from '../dto/instance.dto'; -import { ContactQuery } from '../repository/mongodb/contact.repository'; -import { MessageQuery } from '../repository/mongodb/message.repository'; -import { MessageUpQuery } from '../repository/mongodb/messageUp.repository'; +import { Query } from '../repository/repository.service'; import { WAMonitoringService } from '../services/monitor.service'; const logger = new Logger('ChatController'); @@ -61,7 +61,7 @@ export class ChatController { return await this.waMonitor.waInstances[instanceName].fetchProfile(instanceName, data.number); } - public async fetchContacts({ instanceName }: InstanceDto, query: ContactQuery) { + public async fetchContacts({ instanceName }: InstanceDto, query: Query) { logger.verbose('requested fetchContacts from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchContacts(query); } @@ -71,12 +71,12 @@ export class ChatController { return await this.waMonitor.waInstances[instanceName].getBase64FromMediaMessage(data); } - public async fetchMessages({ instanceName }: InstanceDto, query: MessageQuery) { + public async fetchMessages({ instanceName }: InstanceDto, query: Query) { logger.verbose('requested fetchMessages from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchMessages(query); } - public async fetchStatusMessage({ instanceName }: InstanceDto, query: MessageUpQuery) { + public async fetchStatusMessage({ instanceName }: InstanceDto, query: Query) { logger.verbose('requested fetchStatusMessage from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchStatusMessage(query); } diff --git a/src/api/controllers/instance.controller.ts b/src/api/controllers/instance.controller.ts index 1a2700e7..b801ac95 100644 --- a/src/api/controllers/instance.controller.ts +++ b/src/api/controllers/instance.controller.ts @@ -1,3 +1,4 @@ +import { JsonValue } from '@prisma/client/runtime/library'; import { delay } from '@whiskeysockets/baileys'; import { isURL } from 'class-validator'; import EventEmitter2 from 'eventemitter2'; @@ -13,8 +14,7 @@ import { SqsService } from '../integrations/sqs/services/sqs.service'; import { TypebotService } from '../integrations/typebot/services/typebot.service'; import { WebsocketService } from '../integrations/websocket/services/websocket.service'; import { ProviderFiles } from '../provider/sessions'; -import { MongodbRepository } from '../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../repository/prisma/repository.service'; +import { PrismaRepository } from '../repository/repository.service'; import { AuthService } from '../services/auth.service'; import { CacheService } from '../services/cache.service'; import { BaileysStartupService } from '../services/channels/whatsapp.baileys.service'; @@ -30,7 +30,6 @@ export class InstanceController { constructor( private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService, - private readonly mongodbRepository: MongodbRepository, private readonly prismaRepository: PrismaRepository, private readonly eventEmitter: EventEmitter2, private readonly authService: AuthService, @@ -54,45 +53,45 @@ export class InstanceController { public async createInstance({ instanceName, webhook, - webhook_by_events, - webhook_base64, - events, + webhookByEvents, + webhookBase64, + webhookEvents, qrcode, number, mobile, integration, token, - chatwoot_account_id, - chatwoot_token, - chatwoot_url, - chatwoot_sign_msg, - chatwoot_reopen_conversation, - chatwoot_conversation_pending, - chatwoot_import_contacts, - chatwoot_name_inbox, - chatwoot_merge_brazil_contacts, - chatwoot_import_messages, - chatwoot_days_limit_import_messages, - reject_call, - msg_call, - groups_ignore, - always_online, - read_messages, - read_status, - sync_full_history, - websocket_enabled, - websocket_events, - rabbitmq_enabled, - rabbitmq_events, - sqs_enabled, - sqs_events, - typebot_url, + chatwootAccountId, + chatwootToken, + chatwootUrl, + chatwootSignMsg, + chatwootReopenConversation, + chatwootConversationPending, + chatwootImportContacts, + chatwootNameInbox, + chatwootMergeBrazilContacts, + chatwootImportMessages, + chatwootDaysLimitImportMessages, + rejectCall, + msgCall, + groupsIgnore, + alwaysOnline, + readMessages, + readStatus, + syncFullHistory, + websocketEnabled, + websocketEvents, + rabbitmqEnabled, + rabbitmqEvents, + sqsEnabled, + sqsEvents, + typebotUrl, typebot, - typebot_expire, - typebot_keyword_finish, - typebot_delay_message, - typebot_unknown_message, - typebot_listening_from_me, + typebotExpire, + typebotKeywordFinish, + typebotDelayMessage, + typebotUnknownMessage, + typebotListeningFromMe, proxy, }: InstanceDto) { try { @@ -111,7 +110,6 @@ export class InstanceController { instance = new BusinessStartupService( this.configService, this.eventEmitter, - this.mongodbRepository, this.prismaRepository, this.cache, this.chatwootCache, @@ -122,7 +120,6 @@ export class InstanceController { instance = new BaileysStartupService( this.configService, this.eventEmitter, - this.mongodbRepository, this.prismaRepository, this.cache, this.chatwootCache, @@ -131,11 +128,12 @@ export class InstanceController { ); } - await this.waMonitor.saveInstance({ integration, instanceName, token, number, mobile }); + const instanceId = v4(); + + await this.waMonitor.saveInstance({ instanceId, integration, instanceName, token, number, mobile }); instance.instanceName = instanceName; - - const instanceId = v4(); + instance.instanceId = instanceId; instance.sendDataWebhook(Events.INSTANCE_CREATE, { instanceName, @@ -158,7 +156,7 @@ export class InstanceController { this.logger.verbose('hash: ' + hash + ' generated'); - let webhookEvents: string[]; + let getWebhookEvents: string[]; if (webhook) { if (!isURL(webhook, { require_tld: false })) { @@ -168,7 +166,7 @@ export class InstanceController { this.logger.verbose('creating webhook'); try { let newEvents: string[] = []; - if (events.length === 0) { + if (webhookEvents.length === 0) { newEvents = [ 'APPLICATION_STARTUP', 'QRCODE_UPDATED', @@ -196,29 +194,31 @@ export class InstanceController { 'TYPEBOT_CHANGE_STATUS', ]; } else { - newEvents = events; + newEvents = webhookEvents; } this.webhookService.create(instance, { enabled: true, url: webhook, events: newEvents, - webhook_by_events, - webhook_base64, + webhookByEvents, + webhookBase64, }); - webhookEvents = (await this.webhookService.find(instance)).events; + const webhookEventsJson: JsonValue = (await this.webhookService.find(instance)).events; + + getWebhookEvents = Array.isArray(webhookEventsJson) ? webhookEventsJson.map((event) => String(event)) : []; } catch (error) { this.logger.log(error); } } - let websocketEvents: string[]; + let getWebsocketEvents: string[]; - if (websocket_enabled) { + if (websocketEnabled) { this.logger.verbose('creating websocket'); try { let newEvents: string[] = []; - if (websocket_events.length === 0) { + if (websocketEvents.length === 0) { newEvents = [ 'APPLICATION_STARTUP', 'QRCODE_UPDATED', @@ -246,26 +246,31 @@ export class InstanceController { 'TYPEBOT_CHANGE_STATUS', ]; } else { - newEvents = websocket_events; + newEvents = websocketEvents; } this.websocketService.create(instance, { enabled: true, events: newEvents, }); - websocketEvents = (await this.websocketService.find(instance)).events; + const websocketEventsJson: JsonValue = (await this.websocketService.find(instance)).events; + + // websocketEvents = (await this.websocketService.find(instance)).events; + getWebsocketEvents = Array.isArray(websocketEventsJson) + ? websocketEventsJson.map((event) => String(event)) + : []; } catch (error) { this.logger.log(error); } } - let rabbitmqEvents: string[]; + let getRabbitmqEvents: string[]; - if (rabbitmq_enabled) { + if (rabbitmqEnabled) { this.logger.verbose('creating rabbitmq'); try { let newEvents: string[] = []; - if (rabbitmq_events.length === 0) { + if (rabbitmqEvents.length === 0) { newEvents = [ 'APPLICATION_STARTUP', 'QRCODE_UPDATED', @@ -293,26 +298,30 @@ export class InstanceController { 'TYPEBOT_CHANGE_STATUS', ]; } else { - newEvents = rabbitmq_events; + newEvents = rabbitmqEvents; } this.rabbitmqService.create(instance, { enabled: true, events: newEvents, }); - rabbitmqEvents = (await this.rabbitmqService.find(instance)).events; + const rabbitmqEventsJson: JsonValue = (await this.rabbitmqService.find(instance)).events; + + getRabbitmqEvents = Array.isArray(rabbitmqEventsJson) ? rabbitmqEventsJson.map((event) => String(event)) : []; + + // rabbitmqEvents = (await this.rabbitmqService.find(instance)).events; } catch (error) { this.logger.log(error); } } - let sqsEvents: string[]; + let getSqsEvents: string[]; - if (sqs_enabled) { + if (sqsEnabled) { this.logger.verbose('creating sqs'); try { let newEvents: string[] = []; - if (sqs_events.length === 0) { + if (sqsEvents.length === 0) { newEvents = [ 'APPLICATION_STARTUP', 'QRCODE_UPDATED', @@ -340,14 +349,18 @@ export class InstanceController { 'TYPEBOT_CHANGE_STATUS', ]; } else { - newEvents = sqs_events; + newEvents = sqsEvents; } this.sqsService.create(instance, { enabled: true, events: newEvents, }); - sqsEvents = (await this.sqsService.find(instance)).events; + const sqsEventsJson: JsonValue = (await this.sqsService.find(instance)).events; + + getSqsEvents = Array.isArray(sqsEventsJson) ? sqsEventsJson.map((event) => String(event)) : []; + + // sqsEvents = (await this.sqsService.find(instance)).events; } catch (error) { this.logger.log(error); } @@ -361,27 +374,31 @@ export class InstanceController { await this.proxyService.createProxy(instance, { enabled: true, - proxy, + host: proxy.host, + port: proxy.port, + protocol: proxy.protocol, + username: proxy.username, + password: proxy.password, }); } - if (typebot_url) { + if (typebotUrl) { try { - if (!isURL(typebot_url, { require_tld: false })) { - throw new BadRequestException('Invalid "url" property in typebot_url'); + if (!isURL(typebotUrl, { require_tld: false })) { + throw new BadRequestException('Invalid "url" property in typebotUrl'); } this.logger.verbose('creating typebot'); this.typebotService.create(instance, { enabled: true, - url: typebot_url, + url: typebotUrl, typebot: typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, + expire: typebotExpire, + keywordFinish: typebotKeywordFinish, + delayMessage: typebotDelayMessage, + unknownMessage: typebotUnknownMessage, + listeningFromMe: typebotListeningFromMe, }); } catch (error) { this.logger.log(error); @@ -390,29 +407,29 @@ export class InstanceController { this.logger.verbose('creating settings'); const settings: wa.LocalSettings = { - reject_call: reject_call || false, - msg_call: msg_call || '', - groups_ignore: groups_ignore || true, - always_online: always_online || false, - read_messages: read_messages || false, - read_status: read_status || false, - sync_full_history: sync_full_history ?? false, + rejectCall: rejectCall || false, + msgCall: msgCall || '', + groupsIgnore: groupsIgnore || true, + alwaysOnline: alwaysOnline || false, + readMessages: readMessages || false, + readStatus: readStatus || false, + syncFullHistory: syncFullHistory ?? false, }; this.logger.verbose('settings: ' + JSON.stringify(settings)); this.settingsService.create(instance, settings); - let webhook_wa_business = null, - access_token_wa_business = ''; + let webhookWaBusiness = null, + accessTokenWaBusiness = ''; if (integration === Integration.WHATSAPP_BUSINESS) { if (!number) { throw new BadRequestException('number is required'); } const urlServer = this.configService.get('SERVER').URL; - webhook_wa_business = `${urlServer}/webhook/whatsapp/${encodeURIComponent(instance.instanceName)}`; - access_token_wa_business = this.configService.get('WA_BUSINESS').TOKEN_WEBHOOK; + webhookWaBusiness = `${urlServer}/webhook/whatsapp/${encodeURIComponent(instance.instanceName)}`; + accessTokenWaBusiness = this.configService.get('WA_BUSINESS').TOKEN_WEBHOOK; } this.integrationService.create(instance, { @@ -420,7 +437,7 @@ export class InstanceController { number, token, }); - if (!chatwoot_account_id || !chatwoot_token || !chatwoot_url) { + if (!chatwootAccountId || !chatwootToken || !chatwootUrl) { let getQrcode: wa.QrCode; if (qrcode) { @@ -435,38 +452,38 @@ export class InstanceController { instanceName: instance.instanceName, instanceId: instanceId, integration: integration, - webhook_wa_business, - access_token_wa_business, + webhookWaBusiness, + accessTokenWaBusiness, status: 'created', }, hash, webhook: { webhook, - webhook_by_events, - webhook_base64, - events: webhookEvents, + webhookByEvents, + webhookBase64, + events: getWebhookEvents, }, websocket: { - enabled: websocket_enabled, - events: websocketEvents, + enabled: websocketEnabled, + events: getWebsocketEvents, }, rabbitmq: { - enabled: rabbitmq_enabled, - events: rabbitmqEvents, + enabled: rabbitmqEnabled, + events: getRabbitmqEvents, }, sqs: { - enabled: sqs_enabled, - events: sqsEvents, + enabled: sqsEnabled, + events: getSqsEvents, }, typebot: { - enabled: typebot_url ? true : false, - url: typebot_url, + enabled: typebotUrl ? true : false, + url: typebotUrl, typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, + expire: typebotExpire, + keywordFinish: typebotKeywordFinish, + delayMessage: typebotDelayMessage, + unknownMessage: typebotUnknownMessage, + listeningFromMe: typebotListeningFromMe, }, settings, qrcode: getQrcode, @@ -478,32 +495,32 @@ export class InstanceController { return result; } - if (!chatwoot_account_id) { - throw new BadRequestException('account_id is required'); + if (!chatwootAccountId) { + throw new BadRequestException('accountId is required'); } - if (!chatwoot_token) { + if (!chatwootToken) { throw new BadRequestException('token is required'); } - if (!chatwoot_url) { + if (!chatwootUrl) { throw new BadRequestException('url is required'); } - if (!isURL(chatwoot_url, { require_tld: false })) { + if (!isURL(chatwootUrl, { require_tld: false })) { throw new BadRequestException('Invalid "url" property in chatwoot'); } - if (chatwoot_sign_msg !== true && chatwoot_sign_msg !== false) { - throw new BadRequestException('sign_msg is required'); + if (chatwootSignMsg !== true && chatwootSignMsg !== false) { + throw new BadRequestException('signMsg is required'); } - if (chatwoot_reopen_conversation !== true && chatwoot_reopen_conversation !== false) { - throw new BadRequestException('reopen_conversation is required'); + if (chatwootReopenConversation !== true && chatwootReopenConversation !== false) { + throw new BadRequestException('reopenConversation is required'); } - if (chatwoot_conversation_pending !== true && chatwoot_conversation_pending !== false) { - throw new BadRequestException('conversation_pending is required'); + if (chatwootConversationPending !== true && chatwootConversationPending !== false) { + throw new BadRequestException('conversationPending is required'); } const urlServer = this.configService.get('SERVER').URL; @@ -511,19 +528,19 @@ export class InstanceController { try { this.chatwootService.create(instance, { enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - name_inbox: chatwoot_name_inbox ?? instance.instanceName.split('-cwId-')[0], + accountId: chatwootAccountId, + token: chatwootToken, + url: chatwootUrl, + signMsg: chatwootSignMsg || false, + nameInbox: chatwootNameInbox ?? instance.instanceName.split('-cwId-')[0], number, - reopen_conversation: chatwoot_reopen_conversation || false, - conversation_pending: chatwoot_conversation_pending || false, - import_contacts: chatwoot_import_contacts ?? true, - merge_brazil_contacts: chatwoot_merge_brazil_contacts ?? false, - import_messages: chatwoot_import_messages ?? true, - days_limit_import_messages: chatwoot_days_limit_import_messages ?? 60, - auto_create: true, + reopenConversation: chatwootReopenConversation || false, + conversationPending: chatwootConversationPending || false, + importContacts: chatwootImportContacts ?? true, + mergeBrazilContacts: chatwootMergeBrazilContacts ?? false, + importMessages: chatwootImportMessages ?? true, + daysLimitImportMessages: chatwootDaysLimitImportMessages ?? 60, + autoCreate: true, }); } catch (error) { this.logger.log(error); @@ -534,55 +551,55 @@ export class InstanceController { instanceName: instance.instanceName, instanceId: instanceId, integration: integration, - webhook_wa_business, - access_token_wa_business, + webhookWaBusiness, + accessTokenWaBusiness, status: 'created', }, hash, webhook: { webhook, - webhook_by_events, - webhook_base64, - events: webhookEvents, + webhookByEvents, + webhookBase64, + events: getWebhookEvents, }, websocket: { - enabled: websocket_enabled, - events: websocketEvents, + enabled: websocketEnabled, + events: getWebsocketEvents, }, rabbitmq: { - enabled: rabbitmq_enabled, - events: rabbitmqEvents, + enabled: rabbitmqEnabled, + events: getRabbitmqEvents, }, sqs: { - enabled: sqs_enabled, - events: sqsEvents, + enabled: sqsEnabled, + events: getSqsEvents, }, typebot: { - enabled: typebot_url ? true : false, - url: typebot_url, + enabled: typebotUrl ? true : false, + url: typebotUrl, typebot, - expire: typebot_expire, - keyword_finish: typebot_keyword_finish, - delay_message: typebot_delay_message, - unknown_message: typebot_unknown_message, - listening_from_me: typebot_listening_from_me, + expire: typebotExpire, + keywordFinish: typebotKeywordFinish, + delayMessage: typebotDelayMessage, + unknownMessage: typebotUnknownMessage, + listeningFromMe: typebotListeningFromMe, }, settings, chatwoot: { enabled: true, - account_id: chatwoot_account_id, - token: chatwoot_token, - url: chatwoot_url, - sign_msg: chatwoot_sign_msg || false, - reopen_conversation: chatwoot_reopen_conversation || false, - conversation_pending: chatwoot_conversation_pending || false, - merge_brazil_contacts: chatwoot_merge_brazil_contacts ?? false, - import_contacts: chatwoot_import_contacts ?? true, - import_messages: chatwoot_import_messages ?? true, - days_limit_import_messages: chatwoot_days_limit_import_messages || 60, + accountId: chatwootAccountId, + token: chatwootToken, + url: chatwootUrl, + signMsg: chatwootSignMsg || false, + reopenConversation: chatwootReopenConversation || false, + conversationPending: chatwootConversationPending || false, + mergeBrazilContacts: chatwootMergeBrazilContacts ?? false, + importContacts: chatwootImportContacts ?? true, + importMessages: chatwootImportMessages ?? true, + daysLimitImportMessages: chatwootDaysLimitImportMessages || 60, number, - name_inbox: chatwoot_name_inbox ?? instance.instanceName, - webhook_url: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, + nameInbox: chatwootNameInbox ?? instance.instanceName, + webhookUrl: `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, }, }; } catch (error) { @@ -686,9 +703,17 @@ export class InstanceController { let arrayReturn = false; if (env.KEY !== key) { - const instanceByKey = await this.mongodbRepository.auth.findByKey(key); + const instanceByKey = await this.prismaRepository.auth.findUnique({ + where: { + apikey: key, + }, + include: { + Instance: true, + }, + }); + if (instanceByKey) { - name = instanceByKey._id; + name = instanceByKey.Instance.name; arrayReturn = true; } else { throw new UnauthorizedException(); @@ -737,8 +762,9 @@ export class InstanceController { throw new BadRequestException('The "' + instanceName + '" instance needs to be disconnected'); } try { - this.waMonitor.waInstances[instanceName]?.removeRabbitmqQueues(); - this.waMonitor.waInstances[instanceName]?.clearCacheChatwoot(); + const waInstances = this.waMonitor.waInstances[instanceName]; + waInstances?.removeRabbitmqQueues(); + waInstances?.clearCacheChatwoot(); if (instance.state === 'connecting') { this.logger.verbose('logging out instance: ' + instanceName); @@ -749,9 +775,9 @@ export class InstanceController { this.logger.verbose('deleting instance: ' + instanceName); try { - this.waMonitor.waInstances[instanceName]?.sendDataWebhook(Events.INSTANCE_DELETE, { + waInstances?.sendDataWebhook(Events.INSTANCE_DELETE, { instanceName, - instanceId: (await this.mongodbRepository.auth.find(instanceName))?.instanceId, + instanceId: waInstances.instanceId, }); } catch (error) { this.logger.error(error); diff --git a/src/api/controllers/proxy.controller.ts b/src/api/controllers/proxy.controller.ts index 7b34a9d9..b4b01be5 100644 --- a/src/api/controllers/proxy.controller.ts +++ b/src/api/controllers/proxy.controller.ts @@ -22,11 +22,15 @@ export class ProxyController { if (!data.enabled) { logger.verbose('proxy disabled'); - data.proxy = null; + data.host = ''; + data.port = ''; + data.protocol = ''; + data.username = ''; + data.password = ''; } - if (data.proxy) { - const testProxy = await this.testProxy(data.proxy); + if (data.host) { + const testProxy = await this.testProxy(data); if (!testProxy) { throw new BadRequestException('Invalid proxy'); } @@ -46,7 +50,7 @@ export class ProxyController { return this.proxyService.find(instance); } - public async testProxy(proxy: ProxyDto['proxy']) { + public async testProxy(proxy: ProxyDto) { logger.verbose('requested testProxy'); try { const serverIp = await axios.get('https://icanhazip.com/'); diff --git a/src/api/dto/instance.dto.ts b/src/api/dto/instance.dto.ts index d9a4d87a..a49bb619 100644 --- a/src/api/dto/instance.dto.ts +++ b/src/api/dto/instance.dto.ts @@ -11,41 +11,41 @@ export class InstanceDto { integration?: string; token?: string; webhook?: string; - webhook_by_events?: boolean; - webhook_base64?: boolean; - events?: string[]; - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; - chatwoot_account_id?: string; - chatwoot_token?: string; - chatwoot_url?: string; - chatwoot_sign_msg?: boolean; - chatwoot_reopen_conversation?: boolean; - chatwoot_conversation_pending?: boolean; - chatwoot_merge_brazil_contacts?: boolean; - chatwoot_import_contacts?: boolean; - chatwoot_import_messages?: boolean; - chatwoot_days_limit_import_messages?: number; - chatwoot_name_inbox?: string; - websocket_enabled?: boolean; - websocket_events?: string[]; - rabbitmq_enabled?: boolean; - rabbitmq_events?: string[]; - sqs_enabled?: boolean; - sqs_events?: string[]; - typebot_url?: string; + webhookByEvents?: boolean; + webhookBase64?: boolean; + webhookEvents?: string[]; + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; + chatwootAccountId?: string; + chatwootToken?: string; + chatwootUrl?: string; + chatwootSignMsg?: boolean; + chatwootReopenConversation?: boolean; + chatwootConversationPending?: boolean; + chatwootMergeBrazilContacts?: boolean; + chatwootImportContacts?: boolean; + chatwootImportMessages?: boolean; + chatwootDaysLimitImportMessages?: number; + chatwootNameInbox?: string; + websocketEnabled?: boolean; + websocketEvents?: string[]; + rabbitmqEnabled?: boolean; + rabbitmqEvents?: string[]; + sqsEnabled?: boolean; + sqsEvents?: string[]; + typebotUrl?: string; typebot?: string; - typebot_expire?: number; - typebot_keyword_finish?: string; - typebot_delay_message?: number; - typebot_unknown_message?: string; - typebot_listening_from_me?: boolean; - proxy?: ProxyDto['proxy']; + typebotExpire?: number; + typebotKeywordFinish?: string; + typebotDelayMessage?: number; + typebotUnknownMessage?: string; + typebotListeningFromMe?: boolean; + proxy?: ProxyDto; } export class SetPresenceDto { diff --git a/src/api/dto/label.dto.ts b/src/api/dto/label.dto.ts index 23ff47bb..706474a0 100644 --- a/src/api/dto/label.dto.ts +++ b/src/api/dto/label.dto.ts @@ -1,7 +1,7 @@ export class LabelDto { id?: string; name: string; - color: number; + color: string; predefinedId?: string; } diff --git a/src/api/dto/proxy.dto.ts b/src/api/dto/proxy.dto.ts index 7f3e7c06..18432d34 100644 --- a/src/api/dto/proxy.dto.ts +++ b/src/api/dto/proxy.dto.ts @@ -1,12 +1,8 @@ -class Proxy { +export class ProxyDto { + enabled: boolean; host: string; port: string; protocol: string; username?: string; password?: string; } - -export class ProxyDto { - enabled: boolean; - proxy: Proxy; -} diff --git a/src/api/dto/settings.dto.ts b/src/api/dto/settings.dto.ts index 8cd67948..09302a42 100644 --- a/src/api/dto/settings.dto.ts +++ b/src/api/dto/settings.dto.ts @@ -1,9 +1,9 @@ export class SettingsDto { - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; } diff --git a/src/api/dto/webhook.dto.ts b/src/api/dto/webhook.dto.ts index 87a21883..e0e6b722 100644 --- a/src/api/dto/webhook.dto.ts +++ b/src/api/dto/webhook.dto.ts @@ -2,6 +2,6 @@ export class WebhookDto { enabled?: boolean; url?: string; events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; + webhookByEvents?: boolean; + webhookBase64?: boolean; } diff --git a/src/api/guards/auth.guard.ts b/src/api/guards/auth.guard.ts index e236b563..cf4f1938 100644 --- a/src/api/guards/auth.guard.ts +++ b/src/api/guards/auth.guard.ts @@ -4,7 +4,7 @@ import { Auth, configService, Database } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { ForbiddenException, UnauthorizedException } from '../../exceptions'; import { InstanceDto } from '../dto/instance.dto'; -import { mongodbRepository } from '../server.module'; +import { prismaRepository } from '../server.module'; const logger = new Logger('GUARD'); @@ -28,13 +28,18 @@ async function apikey(req: Request, _: Response, next: NextFunction) { try { if (param?.instanceName) { - const instanceKey = await mongodbRepository.auth.find(param.instanceName); - if (instanceKey?.apikey === key) { + const instance = await prismaRepository.instance.findUnique({ + where: { name: param.instanceName }, + include: { Auth: true }, + }); + if (instance.Auth?.apikey === key) { return next(); } } else { if (req.originalUrl.includes('/instance/fetchInstances') && db.ENABLED) { - const instanceByKey = await mongodbRepository.auth.findByKey(key); + const instanceByKey = await prismaRepository.auth.findFirst({ + where: { apikey: key }, + }); if (instanceByKey) { return next(); } diff --git a/src/api/guards/instance.guard.ts b/src/api/guards/instance.guard.ts index 5902bd4f..b0e6e12d 100644 --- a/src/api/guards/instance.guard.ts +++ b/src/api/guards/instance.guard.ts @@ -10,7 +10,7 @@ import { InternalServerErrorException, NotFoundException, } from '../../exceptions'; -import { mongodbServer } from '../../libs/mongodb.connect'; +import { prismaServer } from '../../libs/prisma.connect'; import { InstanceDto } from '../dto/instance.dto'; import { cache, waMonitor } from '../server.module'; @@ -28,11 +28,9 @@ async function getInstance(instanceName: string) { } if (db.ENABLED) { - const collection = mongodbServer - .getClient() - .db(db.CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(instanceName); - return exists || (await collection.find({}).toArray()).length > 0; + const prisma = prismaServer; + + return exists || (await prisma.instance.findMany({ where: { name: instanceName } })).length > 0; } return exists || existsSync(join(INSTANCE_DIR, instanceName)); diff --git a/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts b/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts index afecc79a..05bc5434 100644 --- a/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts +++ b/src/api/integrations/chatwoot/controllers/chatwoot.controller.ts @@ -5,8 +5,7 @@ import { ConfigService, HttpServer } from '../../../../config/env.config'; import { Logger } from '../../../../config/logger.config'; import { BadRequestException } from '../../../../exceptions'; import { InstanceDto } from '../../../dto/instance.dto'; -import { MongodbRepository } from '../../../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../../../repository/prisma/repository.service'; +import { PrismaRepository } from '../../../repository/repository.service'; import { waMonitor } from '../../../server.module'; import { CacheService } from '../../../services/cache.service'; import { ChatwootDto } from '../dto/chatwoot.dto'; @@ -18,7 +17,6 @@ export class ChatwootController { constructor( private readonly chatwootService: ChatwootService, private readonly configService: ConfigService, - private readonly mongodbRepository: MongodbRepository, private readonly prismaRepository: PrismaRepository, ) {} @@ -30,39 +28,39 @@ export class ChatwootController { throw new BadRequestException('url is not valid'); } - if (!data.account_id) { - throw new BadRequestException('account_id is required'); + if (!data.accountId) { + throw new BadRequestException('accountId is required'); } if (!data.token) { throw new BadRequestException('token is required'); } - if (data.sign_msg !== true && data.sign_msg !== false) { - throw new BadRequestException('sign_msg is required'); + if (data.signMsg !== true && data.signMsg !== false) { + throw new BadRequestException('signMsg is required'); } - if (data.sign_msg === false) data.sign_delimiter = null; + if (data.signMsg === false) data.signDelimiter = null; } if (!data.enabled) { logger.verbose('chatwoot disabled'); - data.account_id = ''; + data.accountId = ''; data.token = ''; data.url = ''; - data.sign_msg = false; - data.sign_delimiter = null; - data.reopen_conversation = false; - data.conversation_pending = false; - data.import_contacts = false; - data.import_messages = false; - data.merge_brazil_contacts = false; - data.days_limit_import_messages = 0; - data.auto_create = false; - data.name_inbox = ''; + data.signMsg = false; + data.signDelimiter = null; + data.reopenConversation = false; + data.conversationPending = false; + data.importContacts = false; + data.importMessages = false; + data.mergeBrazilContacts = false; + data.daysLimitImportMessages = 0; + data.autoCreate = false; + data.nameInbox = ''; } - if (!data.name_inbox || data.name_inbox === '') { - data.name_inbox = instance.instanceName; + if (!data.nameInbox || data.nameInbox === '') { + data.nameInbox = instance.instanceName; } const result = await this.chatwootService.create(instance, data); @@ -87,10 +85,10 @@ export class ChatwootController { return { enabled: false, url: '', - account_id: '', + accountId: '', token: '', - sign_msg: false, - name_inbox: '', + signMsg: false, + nameInbox: '', webhook_url: '', }; } @@ -107,13 +105,7 @@ export class ChatwootController { logger.verbose('requested receiveWebhook from ' + instance.instanceName + ' instance'); const chatwootCache = new CacheService(new CacheEngine(this.configService, ChatwootService.name).getEngine()); - const chatwootService = new ChatwootService( - waMonitor, - this.configService, - this.mongodbRepository, - this.prismaRepository, - chatwootCache, - ); + const chatwootService = new ChatwootService(waMonitor, this.configService, this.prismaRepository, chatwootCache); return chatwootService.receiveWebhook(instance, data); } diff --git a/src/api/integrations/chatwoot/dto/chatwoot.dto.ts b/src/api/integrations/chatwoot/dto/chatwoot.dto.ts index a6786db2..5ddb97d9 100644 --- a/src/api/integrations/chatwoot/dto/chatwoot.dto.ts +++ b/src/api/integrations/chatwoot/dto/chatwoot.dto.ts @@ -1,17 +1,17 @@ export class ChatwootDto { enabled?: boolean; - account_id?: string; + accountId?: string; token?: string; url?: string; - name_inbox?: string; - sign_msg?: boolean; - sign_delimiter?: string; + nameInbox?: string; + signMsg?: boolean; + signDelimiter?: string; number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; - auto_create?: boolean; + reopenConversation?: boolean; + conversationPending?: boolean; + mergeBrazilContacts?: boolean; + importContacts?: boolean; + importMessages?: boolean; + daysLimitImportMessages?: number; + autoCreate?: boolean; } diff --git a/src/api/integrations/chatwoot/models/chatwoot.model.ts b/src/api/integrations/chatwoot/models/chatwoot.model.ts deleted file mode 100644 index 41a19388..00000000 --- a/src/api/integrations/chatwoot/models/chatwoot.model.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../../../libs/mongodb.connect'; - -export class ChatwootRaw { - _id?: string; - enabled?: boolean; - account_id?: string; - token?: string; - url?: string; - name_inbox?: string; - sign_msg?: boolean; - sign_delimiter?: string; - number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; -} - -const chatwootSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - account_id: { type: String, required: true }, - token: { type: String, required: true }, - url: { type: String, required: true }, - name_inbox: { type: String, required: true }, - sign_msg: { type: Boolean, required: true }, - sign_delimiter: { type: String, required: false }, - number: { type: String, required: true }, - reopen_conversation: { type: Boolean, required: true }, - conversation_pending: { type: Boolean, required: true }, - merge_brazil_contacts: { type: Boolean, required: true }, - import_contacts: { type: Boolean, required: true }, - import_messages: { type: Boolean, required: true }, - days_limit_import_messages: { type: Number, required: true }, -}); - -export const ChatwootModel = mongodbServer?.model(ChatwootRaw.name, chatwootSchema, 'chatwoot'); -export type IChatwootModel = typeof ChatwootModel; diff --git a/src/api/integrations/chatwoot/repository/chatwoot.repository.ts b/src/api/integrations/chatwoot/repository/chatwoot.repository.ts deleted file mode 100644 index 820f54af..00000000 --- a/src/api/integrations/chatwoot/repository/chatwoot.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { ChatwootRaw, IChatwootModel } from '../../../models'; - -export class ChatwootRepository extends Repository { - constructor(private readonly chatwootModel: IChatwootModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ChatwootRepository'); - - public async create(data: ChatwootRaw, instance: string): Promise { - try { - this.logger.verbose('creating chatwoot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving chatwoot to db'); - const insert = await this.chatwootModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('chatwoot saved to db: ' + insert.modifiedCount + ' chatwoot'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving chatwoot to store'); - - this.writeStore({ - path: join(this.storePath, 'chatwoot'), - fileName: instance, - data, - }); - - this.logger.verbose('chatwoot saved to store in path: ' + join(this.storePath, 'chatwoot') + '/' + instance); - - this.logger.verbose('chatwoot created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding chatwoot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding chatwoot in db'); - return await this.chatwootModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding chatwoot in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'chatwoot', instance + '.json'), { - encoding: 'utf-8', - }), - ) as ChatwootRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatwoot/services/chatwoot.service.ts index 48e06557..16076f33 100644 --- a/src/api/integrations/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatwoot/services/chatwoot.service.ts @@ -8,11 +8,12 @@ import ChatwootClient, { inbox, } from '@figuro/chatwoot-sdk'; import { request as chatwootRequest } from '@figuro/chatwoot-sdk/dist/core/request'; -import { proto } from '@whiskeysockets/baileys'; +import { Chatwoot as ChatwootModel, Contact as ContactModel, Message as MessageModel } from '@prisma/client'; import axios from 'axios'; import FormData from 'form-data'; import { createReadStream, unlinkSync, writeFileSync } from 'fs'; import Jimp from 'jimp'; +import Long from 'long'; import mimeTypes from 'mime-types'; import path from 'path'; @@ -22,14 +23,20 @@ import i18next from '../../../../utils/i18n'; import { ICache } from '../../../abstract/abstract.cache'; import { InstanceDto } from '../../../dto/instance.dto'; import { Options, Quoted, SendAudioDto, SendMediaDto, SendTextDto } from '../../../dto/sendMessage.dto'; -import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../models'; -import { MongodbRepository } from '../../../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../../../repository/prisma/repository.service'; +import { PrismaRepository } from '../../../repository/repository.service'; import { WAMonitoringService } from '../../../services/monitor.service'; import { Events } from '../../../types/wa.types'; import { ChatwootDto } from '../dto/chatwoot.dto'; import { chatwootImport } from '../utils/chatwoot-import-helper'; +interface ChatwootMessage { + messageId?: number; + inboxId?: number; + conversationId?: number; + contactInboxSourceId?: string; + isRead?: boolean; +} + export class ChatwootService { private readonly logger = new Logger(ChatwootService.name); @@ -38,7 +45,6 @@ export class ChatwootService { constructor( private readonly waMonitor: WAMonitoringService, private readonly configService: ConfigService, - private readonly mongodbRepository: MongodbRepository, private readonly prismaRepository: PrismaRepository, private readonly cache: ICache, ) {} @@ -46,7 +52,7 @@ export class ChatwootService { private async getProvider(instance: InstanceDto) { const cacheKey = `${instance.instanceName}:getProvider`; if (await this.cache.has(cacheKey)) { - return (await this.cache.get(cacheKey)) as ChatwootRaw; + return (await this.cache.get(cacheKey)) as ChatwootModel; } this.logger.verbose('get provider to instance: ' + instance.instanceName); @@ -110,12 +116,12 @@ export class ChatwootService { this.logger.verbose('chatwoot created'); - if (data.auto_create) { + if (data.autoCreate) { const urlServer = this.configService.get('SERVER').URL; await this.initInstanceChatwoot( instance, - data.name_inbox ?? instance.instanceName.split('-cwId-')[0], + data.nameInbox ?? instance.instanceName.split('-cwId-')[0], `${urlServer}/chatwoot/webhook/${encodeURIComponent(instance.instanceName)}`, true, data.number, @@ -1195,26 +1201,22 @@ export class ChatwootService { this.logger.verbose('check if is a message deletion'); if (body.event === 'message_updated' && body.content_attributes?.deleted) { - const message = await this.mongodbRepository.message.find({ + const message = await this.prismaRepository.message.findFirst({ where: { - owner: instance.instanceName, - chatwoot: { - messageId: body.id, - }, + chatwootMessageId: body.id, + instanceId: instance.instanceId, }, - limit: 1, }); - if (message.length && message[0].key?.id) { + + if (message) { this.logger.verbose('deleting message in whatsapp. Message id: ' + message[0].key.id); await waInstance?.client.sendMessage(message[0].key.remoteJid, { delete: message[0].key }); this.logger.verbose('deleting message in repository. Message id: ' + message[0].key.id); - this.mongodbRepository.message.delete({ + this.prismaRepository.message.deleteMany({ where: { - owner: instance.instanceName, - chatwoot: { - messageId: body.id, - }, + instanceId: instance.instanceId, + chatwootMessageId: body.id, }, }); } @@ -1368,9 +1370,7 @@ export class ChatwootService { messageId: body.id, inboxId: body.inbox?.id, conversationId: body.conversation?.id, - contactInbox: { - sourceId: body.conversation?.contact_inbox?.source_id, - }, + contactInboxSourceId: body.conversation?.contact_inbox?.source_id, }, instance, ); @@ -1391,25 +1391,27 @@ export class ChatwootService { }, }; - let messageSent: MessageRaw | proto.WebMessageInfo; + let messageSent: any; try { messageSent = await waInstance?.textMessage(data, true); if (!messageSent) { throw new Error('Message not sent'); } + if (Long.isLong(messageSent?.messageTimestamp)) { + messageSent.messageTimestamp = messageSent.messageTimestamp?.toNumber(); + } + this.updateChatwootMessageId( { ...messageSent, - owner: instance.instanceName, + instanceId: instance.instanceId, }, { messageId: body.id, inboxId: body.inbox?.id, conversationId: body.conversation?.id, - contactInbox: { - sourceId: body.conversation?.contact_inbox?.source_id, - }, + contactInboxSourceId: body.conversation?.contact_inbox?.source_id, }, instance, ); @@ -1424,32 +1426,72 @@ export class ChatwootService { const chatwootRead = this.configService.get('CHATWOOT').MESSAGE_READ; if (chatwootRead) { - const lastMessage = await this.mongodbRepository.message.find({ + const lastMessage = await this.prismaRepository.message.findFirst({ where: { key: { - fromMe: false, + path: ['fromMe'], + equals: false, }, - owner: instance.instanceName, + instanceId: instance.instanceId, }, - limit: 1, }); - if (lastMessage.length > 0 && !lastMessage[0].chatwoot?.isRead) { + if (lastMessage && !lastMessage.chatwootIsRead) { + const key = lastMessage.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + waInstance?.markMessageAsRead({ - read_messages: lastMessage.map((msg) => ({ - id: msg.key?.id, - fromMe: msg.key?.fromMe, - remoteJid: msg.key?.remoteJid, - })), + read_messages: [ + { + id: key.id, + fromMe: key.fromMe, + remoteJid: key.remoteJid, + }, + ], }); - const updateMessage = lastMessage.map((msg) => ({ - key: msg.key, - owner: msg.owner, - chatwoot: { - ...msg.chatwoot, - isRead: true, + const updateMessage = { + chatwootMessageId: lastMessage.chatwootMessageId, + chatwootConversationId: lastMessage.chatwootConversationId, + chatwootInboxId: lastMessage.chatwootInboxId, + chatwootContactInboxSourceId: lastMessage.chatwootContactInboxSourceId, + chatwootIsRead: true, + }; + + await this.prismaRepository.message.updateMany({ + where: { + instanceId: instance.instanceId, + AND: [ + { + key: { + path: ['id'], + equals: key.id, + }, + }, + { + key: { + path: ['remoteJid'], + equals: key.remoteJid, + }, + }, + { + key: { + path: ['fromMe'], + equals: key.fromMe, + }, + }, + { + key: { + path: ['participant'], + equals: key.participant, + }, + }, + ], }, - })); - this.mongodbRepository.message.update(updateMessage, instance.instanceName, true); + data: updateMessage, + }); } } } @@ -1481,31 +1523,48 @@ export class ChatwootService { } } - private updateChatwootMessageId( - message: MessageRaw, - chatwootMessageIds: MessageRaw['chatwoot'], - instance: InstanceDto, - ) { - if (!chatwootMessageIds.messageId || !message?.key?.id) { + private updateChatwootMessageId(message: MessageModel, chatwootMessageIds: ChatwootMessage, instance: InstanceDto) { + const key = message.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + + if (!chatwootMessageIds.messageId || !key?.id) { return; } - message.chatwoot = chatwootMessageIds; - this.mongodbRepository.message.update([message], instance.instanceName, true); - } - - private async getMessageByKeyId(instance: InstanceDto, keyId: string): Promise { - const messages = await this.mongodbRepository.message.find({ + this.prismaRepository.message.updateMany({ where: { key: { - id: keyId, + path: ['id'], + equals: key.id, }, - owner: instance.instanceName, + instanceId: instance.instanceId, + }, + data: { + chatwootMessageId: chatwootMessageIds.messageId, + chatwootConversationId: chatwootMessageIds.conversationId, + chatwootInboxId: chatwootMessageIds.inboxId, + chatwootContactInboxSourceId: chatwootMessageIds.contactInboxSourceId, + chatwootIsRead: chatwootMessageIds.isRead, + }, + }); + } + + private async getMessageByKeyId(instance: InstanceDto, keyId: string): Promise { + const messages = await this.prismaRepository.message.findFirst({ + where: { + key: { + path: ['id'], + equals: keyId, + }, + instanceId: instance.instanceId, }, - limit: 1, }); - return messages.length ? messages[0] : null; + return messages || null; } private async getReplyToIds( @@ -1519,8 +1578,8 @@ export class ChatwootService { inReplyToExternalId = msg.message?.extendedTextMessage?.contextInfo?.stanzaId; if (inReplyToExternalId) { const message = await this.getMessageByKeyId(instance, inReplyToExternalId); - if (message?.chatwoot?.messageId) { - inReplyTo = message.chatwoot.messageId; + if (message?.chatwootMessageId) { + inReplyTo = message.chatwootMessageId; } } } @@ -1533,16 +1592,21 @@ export class ChatwootService { private async getQuotedMessage(msg: any, instance: InstanceDto): Promise { if (msg?.content_attributes?.in_reply_to) { - const message = await this.mongodbRepository.message.find({ + const message = await this.prismaRepository.message.findFirst({ where: { - chatwoot: { - messageId: msg?.content_attributes?.in_reply_to, - }, - owner: instance.instanceName, + chatwootMessageId: msg?.content_attributes?.in_reply_to, + instanceId: instance.instanceId, }, - limit: 1, }); - if (message.length && message[0]?.key?.id) { + + const key = message.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; + + if (message && key?.id) { return { key: message[0].key, message: message[0].message, @@ -1588,7 +1652,12 @@ export class ChatwootService { private getReactionMessage(msg: any) { interface ReactionMessage { - key: MessageRaw['key']; + key: { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; text: string; } const reactionMessage: ReactionMessage | undefined = msg?.reactionMessage; @@ -2131,22 +2200,23 @@ export class ChatwootService { } const message = await this.getMessageByKeyId(instance, body.key.id); - if (message?.chatwoot?.messageId && message?.chatwoot?.conversationId) { + if (message?.chatwootMessageId && message?.chatwootConversationId) { this.logger.verbose('deleting message in repository. Message id: ' + body.key.id); - this.mongodbRepository.message.delete({ + this.prismaRepository.message.deleteMany({ where: { key: { - id: body.key.id, + path: ['id'], + equals: body.key.id, }, - owner: instance.instanceName, + instanceId: instance.instanceId, }, }); this.logger.verbose('deleting message in chatwoot. Message id: ' + body.key.id); return await client.messages.delete({ accountId: this.provider.account_id, - conversationId: message.chatwoot.conversationId, - messageId: message.chatwoot.messageId, + conversationId: message.chatwootConversationId, + messageId: message.chatwootMessageId, }); } } @@ -2157,18 +2227,25 @@ export class ChatwootService { body?.editedMessage?.conversation || body?.editedMessage?.extendedTextMessage?.text }\n\n_\`${i18next.t('cw.message.edited')}.\`_`; const message = await this.getMessageByKeyId(instance, body?.key?.id); - const messageType = message.key?.fromMe ? 'outgoing' : 'incoming'; + const key = message.key as { + id: string; + fromMe: boolean; + remoteJid: string; + participant?: string; + }; - if (message && message.chatwoot?.conversationId) { + const messageType = key?.fromMe ? 'outgoing' : 'incoming'; + + if (message && message.chatwootConversationId) { const send = await this.createMessage( instance, - message.chatwoot.conversationId, + message.chatwootConversationId, editedText, messageType, false, [], { - message: { extendedTextMessage: { contextInfo: { stanzaId: message.key.id } } }, + message: { extendedTextMessage: { contextInfo: { stanzaId: key.id } } }, }, 'WAID:' + body.key.id, ); @@ -2189,9 +2266,11 @@ export class ChatwootService { } const message = await this.getMessageByKeyId(instance, body.key.id); - const { conversationId, contactInbox } = message?.chatwoot || {}; + const conversationId = message?.chatwootConversationId; + const contactInboxSourceId = message?.chatwootContactInboxSourceId; + if (conversationId) { - let sourceId = contactInbox?.sourceId; + let sourceId = contactInboxSourceId; const inbox = (await this.getInbox(instance)) as inbox & { inbox_identifier?: string; }; @@ -2317,7 +2396,7 @@ export class ChatwootService { /* We can't proccess messages exactly in batch because Chatwoot use message id to order messages in frontend and we are receiving the messages mixed between the batches. Because this, we need to put all batches together and order after */ - public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageRaw[]) { + public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageModel[]) { if (!this.isImportHistoryAvailable()) { return; } @@ -2325,7 +2404,7 @@ export class ChatwootService { chatwootImport.addHistoryMessages(instance, messagesRaw); } - public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactRaw[]) { + public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactModel[]) { if (!this.isImportHistoryAvailable()) { return; } @@ -2382,16 +2461,18 @@ export class ChatwootService { ); const contactsWithProfilePicture = ( - await this.mongodbRepository.contact.find({ + await this.prismaRepository.contact.findMany({ where: { - owner: instance.instanceName, + instanceId: instance.instanceId, id: { - $in: recentContacts.map((contact) => contact.identifier), + in: recentContacts.map((contact) => Number(contact.identifier)), + }, + profilePicUrl: { + not: null, }, - profilePictureUrl: { $ne: null }, }, - } as any) - ).reduce((acc: Map, contact: ContactRaw) => acc.set(contact.id, contact), new Map()); + }) + ).reduce((acc: Map, contact: ContactModel) => acc.set(contact.id, contact), new Map()); recentContacts.forEach(async (contact) => { if (contactsWithProfilePicture.has(contact.identifier)) { diff --git a/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts b/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts index dd0bb23a..daafac1c 100644 --- a/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts +++ b/src/api/integrations/chatwoot/utils/chatwoot-import-helper.ts @@ -1,10 +1,11 @@ import { inbox } from '@figuro/chatwoot-sdk'; +import { Chatwoot as ChatwootModel, Contact, Message } from '@prisma/client'; import { proto } from '@whiskeysockets/baileys'; import { InstanceDto } from '../../../../api/dto/instance.dto'; -import { ChatwootRaw, ContactRaw, MessageRaw } from '../../../../api/models'; import { Chatwoot, configService } from '../../../../config/env.config'; import { Logger } from '../../../../config/logger.config'; +import { ChatwootDto } from '../dto/chatwoot.dto'; import { postgresClient } from '../libs/postgres.client'; import { ChatwootService } from '../services/chatwoot.service'; @@ -29,8 +30,8 @@ type IWebMessageInfo = Omit & Partial>(); - private historyMessages = new Map(); - private historyContacts = new Map(); + private historyMessages = new Map(); + private historyContacts = new Map(); public getRepositoryMessagesCache(instance: InstanceDto) { return this.repositoryMessagesCache.has(instance.instanceName) @@ -46,14 +47,14 @@ class ChatwootImport { this.repositoryMessagesCache.delete(instance.instanceName); } - public addHistoryMessages(instance: InstanceDto, messagesRaw: MessageRaw[]) { + public addHistoryMessages(instance: InstanceDto, messagesRaw: Message[]) { const actualValue = this.historyMessages.has(instance.instanceName) ? this.historyMessages.get(instance.instanceName) : []; this.historyMessages.set(instance.instanceName, actualValue.concat(messagesRaw)); } - public addHistoryContacts(instance: InstanceDto, contactsRaw: ContactRaw[]) { + public addHistoryContacts(instance: InstanceDto, contactsRaw: Contact[]) { const actualValue = this.historyContacts.has(instance.instanceName) ? this.historyContacts.get(instance.instanceName) : []; @@ -78,7 +79,7 @@ class ChatwootImport { return this.historyMessages.get(instance.instanceName)?.length ?? 0; } - public async importHistoryContacts(instance: InstanceDto, provider: ChatwootRaw) { + public async importHistoryContacts(instance: InstanceDto, provider: ChatwootDto) { try { if (this.getHistoryMessagesLenght(instance) > 0) { return; @@ -93,21 +94,21 @@ class ChatwootImport { return 0; } - let contactsChunk: ContactRaw[] = this.sliceIntoChunks(contacts, 3000); + let contactsChunk: Contact[] = this.sliceIntoChunks(contacts, 3000); while (contactsChunk.length > 0) { // inserting contacts in chatwoot db let sqlInsert = `INSERT INTO contacts (name, phone_number, account_id, identifier, created_at, updated_at) VALUES `; - const bindInsert = [provider.account_id]; + const bindInsert = [provider.accountId]; for (const contact of contactsChunk) { bindInsert.push(contact.pushName); const bindName = `$${bindInsert.length}`; - bindInsert.push(`+${contact.id.split('@')[0]}`); + bindInsert.push(`+${contact.remoteJid.split('@')[0]}`); const bindPhoneNumber = `$${bindInsert.length}`; - bindInsert.push(contact.id); + bindInsert.push(contact.remoteJid); const bindIdentifier = `$${bindInsert.length}`; sqlInsert += `(${bindName}, ${bindPhoneNumber}, $1, ${bindIdentifier}, NOW(), NOW()),`; @@ -137,7 +138,7 @@ class ChatwootImport { instance: InstanceDto, chatwootService: ChatwootService, inbox: inbox, - provider: ChatwootRaw, + provider: ChatwootModel, ) { try { const pgClient = postgresClient.getChatwootConnection(); @@ -156,8 +157,16 @@ class ChatwootImport { // ordering messages by number and timestamp asc messagesOrdered.sort((a, b) => { + const aKey = a.key as { + remoteJid: string; + }; + + const bKey = b.key as { + remoteJid: string; + }; + return ( - parseInt(a.key.remoteJid) - parseInt(b.key.remoteJid) || + parseInt(aKey.remoteJid) - parseInt(bKey.remoteJid) || (a.messageTimestamp as number) - (b.messageTimestamp as number) ); }); @@ -165,7 +174,7 @@ class ChatwootImport { const allMessagesMappedByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesOrdered); // Map structure: +552199999999 => { first message timestamp from number, last message timestamp from number} const phoneNumbersWithTimestamp = new Map(); - allMessagesMappedByPhoneNumber.forEach((messages: MessageRaw[], phoneNumber: string) => { + allMessagesMappedByPhoneNumber.forEach((messages: Message[], phoneNumber: string) => { phoneNumbersWithTimestamp.set(phoneNumber, { first: messages[0]?.messageTimestamp as number, last: messages[messages.length - 1]?.messageTimestamp as number, @@ -174,9 +183,9 @@ class ChatwootImport { // processing messages in batch const batchSize = 4000; - let messagesChunk: MessageRaw[] = this.sliceIntoChunks(messagesOrdered, batchSize); + let messagesChunk: Message[] = this.sliceIntoChunks(messagesOrdered, batchSize); while (messagesChunk.length > 0) { - // Map structure: +552199999999 => MessageRaw[] + // Map structure: +552199999999 => Message[] const messagesByPhoneNumber = this.createMessagesMapByPhoneNumber(messagesChunk); if (messagesByPhoneNumber.size > 0) { @@ -191,9 +200,9 @@ class ChatwootImport { let sqlInsertMsg = `INSERT INTO messages (content, account_id, inbox_id, conversation_id, message_type, private, content_type, sender_type, sender_id, created_at, updated_at) VALUES `; - const bindInsertMsg = [provider.account_id, inbox.id]; + const bindInsertMsg = [provider.accountId, inbox.id]; - messagesByPhoneNumber.forEach((messages: MessageRaw[], phoneNumber: string) => { + messagesByPhoneNumber.forEach((messages: any[], phoneNumber: string) => { const fksChatwoot = fksByNumber.get(phoneNumber); messages.forEach((message) => { @@ -257,14 +266,14 @@ class ChatwootImport { } public async selectOrCreateFksFromChatwoot( - provider: ChatwootRaw, + provider: ChatwootModel, inbox: inbox, phoneNumbersWithTimestamp: Map, - messagesByPhoneNumber: Map, + messagesByPhoneNumber: Map, ): Promise> { const pgClient = postgresClient.getChatwootConnection(); - const bindValues = [provider.account_id, inbox.id]; + const bindValues = [provider.accountId, inbox.id]; const phoneNumberBind = Array.from(messagesByPhoneNumber.keys()) .map((phoneNumber) => { const phoneNumberTimestamp = phoneNumbersWithTimestamp.get(phoneNumber); @@ -348,7 +357,7 @@ class ChatwootImport { return new Map(fksFromChatwoot.rows.map((item: FksChatwoot) => [item.phone_number, item])); } - public async getChatwootUser(provider: ChatwootRaw): Promise { + public async getChatwootUser(provider: ChatwootModel): Promise { try { const pgClient = postgresClient.getChatwootConnection(); @@ -362,10 +371,13 @@ class ChatwootImport { } } - public createMessagesMapByPhoneNumber(messages: MessageRaw[]): Map { - return messages.reduce((acc: Map, message: MessageRaw) => { - if (!this.isIgnorePhoneNumber(message?.key?.remoteJid)) { - const phoneNumber = message?.key?.remoteJid?.split('@')[0]; + public createMessagesMapByPhoneNumber(messages: Message[]): Map { + return messages.reduce((acc: Map, message: Message) => { + const key = message?.key as { + remoteJid: string; + }; + if (!this.isIgnorePhoneNumber(key?.remoteJid)) { + const phoneNumber = key?.remoteJid?.split('@')[0]; if (phoneNumber) { const phoneNumberPlus = `+${phoneNumber}`; const messages = acc.has(phoneNumberPlus) ? acc.get(phoneNumberPlus) : []; @@ -380,7 +392,7 @@ class ChatwootImport { public async getContactsOrderByRecentConversations( inbox: inbox, - provider: ChatwootRaw, + provider: ChatwootModel, limit = 50, ): Promise<{ id: number; phone_number: string; identifier: string }[]> { try { @@ -394,7 +406,7 @@ class ChatwootImport { ORDER BY conversations.last_activity_at DESC LIMIT $3`; - return (await pgClient.query(sql, [provider.account_id, inbox.id, limit]))?.rows; + return (await pgClient.query(sql, [provider.accountId, inbox.id, limit]))?.rows; } catch (error) { this.logger.error(`Error on get recent conversations: ${error.toString()}`); } diff --git a/src/api/integrations/rabbitmq/libs/amqp.server.ts b/src/api/integrations/rabbitmq/libs/amqp.server.ts index 99c10f66..1aab9c6a 100644 --- a/src/api/integrations/rabbitmq/libs/amqp.server.ts +++ b/src/api/integrations/rabbitmq/libs/amqp.server.ts @@ -1,3 +1,4 @@ +import { JsonValue } from '@prisma/client/runtime/library'; import * as amqp from 'amqplib/callback_api'; import { configService, Rabbitmq } from '../../../../config/env.config'; @@ -107,12 +108,14 @@ export const initQueues = (instanceName: string, events: string[]) => { }); }; -export const removeQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; +export const removeQueues = (instanceName: string, events: JsonValue) => { + const eventsArray = Array.isArray(events) ? events.map((event) => String(event)) : []; + + if (!events || !eventsArray.length) return; const channel = getAMQP(); - const queues = events.map((event) => { + const queues = eventsArray.map((event) => { return `${event.replace(/_/g, '.').toLowerCase()}`; }); diff --git a/src/api/integrations/rabbitmq/models/rabbitmq.model.ts b/src/api/integrations/rabbitmq/models/rabbitmq.model.ts deleted file mode 100644 index 7119b22b..00000000 --- a/src/api/integrations/rabbitmq/models/rabbitmq.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../../../libs/mongodb.connect'; - -export class RabbitmqRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const rabbitmqSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const RabbitmqModel = mongodbServer?.model(RabbitmqRaw.name, rabbitmqSchema, 'rabbitmq'); -export type IRabbitmqModel = typeof RabbitmqModel; diff --git a/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts b/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts deleted file mode 100644 index cb30c7c3..00000000 --- a/src/api/integrations/rabbitmq/repository/rabbitmq.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { IRabbitmqModel, RabbitmqRaw } from '../../../models'; - -export class RabbitmqRepository extends Repository { - constructor(private readonly rabbitmqModel: IRabbitmqModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('RabbitmqRepository'); - - public async create(data: RabbitmqRaw, instance: string): Promise { - try { - this.logger.verbose('creating rabbitmq'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving rabbitmq to db'); - const insert = await this.rabbitmqModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('rabbitmq saved to db: ' + insert.modifiedCount + ' rabbitmq'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving rabbitmq to store'); - - this.writeStore({ - path: join(this.storePath, 'rabbitmq'), - fileName: instance, - data, - }); - - this.logger.verbose('rabbitmq saved to store in path: ' + join(this.storePath, 'rabbitmq') + '/' + instance); - - this.logger.verbose('rabbitmq created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding rabbitmq'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding rabbitmq in db'); - return await this.rabbitmqModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding rabbitmq in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'rabbitmq', instance + '.json'), { - encoding: 'utf-8', - }), - ) as RabbitmqRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/rabbitmq/services/rabbitmq.service.ts b/src/api/integrations/rabbitmq/services/rabbitmq.service.ts index efb822fd..0b2edd9e 100644 --- a/src/api/integrations/rabbitmq/services/rabbitmq.service.ts +++ b/src/api/integrations/rabbitmq/services/rabbitmq.service.ts @@ -1,6 +1,7 @@ +import { Rabbitmq } from '@prisma/client'; + import { Logger } from '../../../../config/logger.config'; import { InstanceDto } from '../../../dto/instance.dto'; -import { RabbitmqRaw } from '../../../models'; import { WAMonitoringService } from '../../../services/monitor.service'; import { RabbitmqDto } from '../dto/rabbitmq.dto'; import { initQueues } from '../libs/amqp.server'; @@ -18,7 +19,7 @@ export class RabbitmqService { return { rabbitmq: { ...instance, rabbitmq: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find rabbitmq: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findRabbitmq(); @@ -29,7 +30,7 @@ export class RabbitmqService { return result; } catch (error) { - return { enabled: false, events: [] }; + return null; } } } diff --git a/src/api/integrations/sqs/libs/sqs.server.ts b/src/api/integrations/sqs/libs/sqs.server.ts index 3dc1d95d..18507577 100644 --- a/src/api/integrations/sqs/libs/sqs.server.ts +++ b/src/api/integrations/sqs/libs/sqs.server.ts @@ -1,4 +1,5 @@ import { SQS } from '@aws-sdk/client-sqs'; +import { JsonValue } from '@prisma/client/runtime/library'; import { configService, Sqs } from '../../../../config/env.config'; import { Logger } from '../../../../config/logger.config'; @@ -59,12 +60,13 @@ export const initQueues = (instanceName: string, events: string[]) => { }); }; -export const removeQueues = (instanceName: string, events: string[]) => { - if (!events || !events.length) return; +export const removeQueues = (instanceName: string, events: JsonValue) => { + const eventsArray = Array.isArray(events) ? events.map((event) => String(event)) : []; + if (!events || !eventsArray.length) return; const sqs = getSQS(); - const queues = events.map((event) => { + const queues = eventsArray.map((event) => { return `${event.replace(/_/g, '_').toLowerCase()}`; }); diff --git a/src/api/integrations/sqs/models/sqs.model.ts b/src/api/integrations/sqs/models/sqs.model.ts deleted file mode 100644 index 9ac2cbb2..00000000 --- a/src/api/integrations/sqs/models/sqs.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../../../libs/mongodb.connect'; - -export class SqsRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const sqsSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const SqsModel = mongodbServer?.model(SqsRaw.name, sqsSchema, 'sqs'); -export type ISqsModel = typeof SqsModel; diff --git a/src/api/integrations/sqs/repository/sqs.repository.ts b/src/api/integrations/sqs/repository/sqs.repository.ts deleted file mode 100644 index 7e149daa..00000000 --- a/src/api/integrations/sqs/repository/sqs.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { ISqsModel, SqsRaw } from '../../../models'; - -export class SqsRepository extends Repository { - constructor(private readonly sqsModel: ISqsModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('SqsRepository'); - - public async create(data: SqsRaw, instance: string): Promise { - try { - this.logger.verbose('creating sqs'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving sqs to db'); - const insert = await this.sqsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('sqs saved to db: ' + insert.modifiedCount + ' sqs'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving sqs to store'); - - this.writeStore({ - path: join(this.storePath, 'sqs'), - fileName: instance, - data, - }); - - this.logger.verbose('sqs saved to store in path: ' + join(this.storePath, 'sqs') + '/' + instance); - - this.logger.verbose('sqs created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding sqs'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding sqs in db'); - return await this.sqsModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding sqs in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'sqs', instance + '.json'), { - encoding: 'utf-8', - }), - ) as SqsRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/sqs/services/sqs.service.ts b/src/api/integrations/sqs/services/sqs.service.ts index 52780104..aad0d6e7 100644 --- a/src/api/integrations/sqs/services/sqs.service.ts +++ b/src/api/integrations/sqs/services/sqs.service.ts @@ -1,6 +1,7 @@ +import { Sqs } from '@prisma/client'; + import { Logger } from '../../../../config/logger.config'; import { InstanceDto } from '../../../dto/instance.dto'; -import { SqsRaw } from '../../../models'; import { WAMonitoringService } from '../../../services/monitor.service'; import { SqsDto } from '../dto/sqs.dto'; import { initQueues } from '../libs/sqs.server'; @@ -18,7 +19,7 @@ export class SqsService { return { sqs: { ...instance, sqs: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find sqs: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findSqs(); @@ -29,7 +30,7 @@ export class SqsService { return result; } catch (error) { - return { enabled: false, events: [] }; + return null; } } } diff --git a/src/api/integrations/typebot/dto/typebot.dto.ts b/src/api/integrations/typebot/dto/typebot.dto.ts index 6adfcf33..0871b107 100644 --- a/src/api/integrations/typebot/dto/typebot.dto.ts +++ b/src/api/integrations/typebot/dto/typebot.dto.ts @@ -1,3 +1,5 @@ +import { TypebotSession } from '@prisma/client'; + export class Session { remoteJid?: string; sessionId?: string; @@ -19,9 +21,9 @@ export class TypebotDto { url: string; typebot?: string; expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + sessions?: TypebotSession[]; } diff --git a/src/api/integrations/typebot/models/typebot.model.ts b/src/api/integrations/typebot/models/typebot.model.ts deleted file mode 100644 index 852c2922..00000000 --- a/src/api/integrations/typebot/models/typebot.model.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../../../libs/mongodb.connect'; - -class Session { - remoteJid?: string; - sessionId?: string; - status?: string; - createdAt?: number; - updateAt?: number; - prefilledVariables?: { - remoteJid?: string; - pushName?: string; - additionalData?: { [key: string]: any }; - }; -} - -export class TypebotRaw { - _id?: string; - enabled?: boolean; - url: string; - typebot?: string; - expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; -} - -const typebotSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - url: { type: String, required: true }, - typebot: { type: String, required: true }, - expire: { type: Number, required: true }, - keyword_finish: { type: String, required: true }, - delay_message: { type: Number, required: true }, - unknown_message: { type: String, required: true }, - listening_from_me: { type: Boolean, required: true }, - sessions: [ - { - remoteJid: { type: String, required: true }, - sessionId: { type: String, required: true }, - status: { type: String, required: true }, - createdAt: { type: Number, required: true }, - updateAt: { type: Number, required: true }, - prefilledVariables: { - remoteJid: { type: String, required: false }, - pushName: { type: String, required: false }, - additionalData: { type: Schema.Types.Mixed, required: false }, - }, - }, - ], -}); - -export const TypebotModel = mongodbServer?.model(TypebotRaw.name, typebotSchema, 'typebot'); -export type ITypebotModel = typeof TypebotModel; diff --git a/src/api/integrations/typebot/repository/typebot.repository.ts b/src/api/integrations/typebot/repository/typebot.repository.ts deleted file mode 100644 index 45453c63..00000000 --- a/src/api/integrations/typebot/repository/typebot.repository.ts +++ /dev/null @@ -1,68 +0,0 @@ -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 { ITypebotModel, TypebotRaw } from '../../../models'; - -export class TypebotRepository extends Repository { - constructor(private readonly typebotModel: ITypebotModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('TypebotRepository'); - - public async create(data: TypebotRaw, instance: string): Promise { - try { - this.logger.verbose('creating typebot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving typebot to db'); - const insert = await this.typebotModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('typebot saved to db: ' + insert.modifiedCount + ' typebot'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving typebot to store'); - - this.writeStore({ - path: join(this.storePath, 'typebot'), - fileName: instance, - data, - }); - - this.logger.verbose('typebot saved to store in path: ' + join(this.storePath, 'typebot') + '/' + instance); - - this.logger.verbose('typebot created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding typebot'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding typebot in db'); - return await this.typebotModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding typebot in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'typebot', instance + '.json'), { - encoding: 'utf-8', - }), - ) as TypebotRaw; - } catch (error) { - return { - enabled: false, - url: '', - typebot: '', - expire: 0, - sessions: [], - }; - } - } -} diff --git a/src/api/integrations/typebot/services/typebot.service.ts b/src/api/integrations/typebot/services/typebot.service.ts index ebdaa920..eef9c0e7 100644 --- a/src/api/integrations/typebot/services/typebot.service.ts +++ b/src/api/integrations/typebot/services/typebot.service.ts @@ -1,13 +1,13 @@ +import { Message } from '@prisma/client'; import axios from 'axios'; import EventEmitter2 from 'eventemitter2'; import { ConfigService, Typebot } from '../../../../config/env.config'; import { Logger } from '../../../../config/logger.config'; import { InstanceDto } from '../../../dto/instance.dto'; -import { MessageRaw } from '../../../models'; import { WAMonitoringService } from '../../../services/monitor.service'; import { Events } from '../../../types/wa.types'; -import { Session, TypebotDto } from '../dto/typebot.dto'; +import { TypebotDto } from '../dto/typebot.dto'; export class TypebotService { constructor( @@ -64,10 +64,10 @@ export class TypebotService { url: findData.url, typebot: findData.typebot, expire: findData.expire, - keyword_finish: findData.keyword_finish, - delay_message: findData.delay_message, - unknown_message: findData.unknown_message, - listening_from_me: findData.listening_from_me, + keywordFinish: findData.keywordFinish, + delayMessage: findData.delayMessage, + unknownMessage: findData.unknownMessage, + listeningFromMe: findData.listeningFromMe, sessions: findData.sessions, }; @@ -82,19 +82,19 @@ export class TypebotService { } }); } else if (status === 'paused') { - const session: Session = { - remoteJid: remoteJid, - sessionId: Math.floor(Math.random() * 10000000000).toString(), - status: status, - createdAt: Date.now(), - updateAt: Date.now(), - prefilledVariables: { - remoteJid: remoteJid, - pushName: '', - additionalData: {}, - }, - }; - findData.sessions.push(session); + // const session: Session = { + // remoteJid: remoteJid, + // sessionId: Math.floor(Math.random() * 10000000000).toString(), + // status: status, + // createdAt: Date.now(), + // updateAt: Date.now(), + // prefilledVariables: { + // remoteJid: remoteJid, + // pushName: '', + // additionalData: {}, + // }, + // }; + // findData.sessions.push(session); } const typebotData = { @@ -102,10 +102,10 @@ export class TypebotService { url: findData.url, typebot: findData.typebot, expire: findData.expire, - keyword_finish: findData.keyword_finish, - delay_message: findData.delay_message, - unknown_message: findData.unknown_message, - listening_from_me: findData.listening_from_me, + keywordFinish: findData.keywordFinish, + delayMessage: findData.delayMessage, + unknownMessage: findData.unknownMessage, + listeningFromMe: findData.listeningFromMe, sessions: findData.sessions, }; @@ -124,7 +124,8 @@ export class TypebotService { public async clearSessions(instance: InstanceDto, remoteJid: string) { const findTypebot = await this.find(instance); - const sessions = (findTypebot.sessions as Session[]) ?? []; + const sessions = []; + // const sessions = (findTypebot.sessions as Session[]) ?? []; const sessionWithRemoteJid = sessions.filter((session) => session.remoteJid === remoteJid); @@ -138,10 +139,10 @@ export class TypebotService { url: findTypebot.url, typebot: findTypebot.typebot, expire: findTypebot.expire, - keyword_finish: findTypebot.keyword_finish, - delay_message: findTypebot.delay_message, - unknown_message: findTypebot.unknown_message, - listening_from_me: findTypebot.listening_from_me, + keywordFinish: findTypebot.keywordFinish, + delayMessage: findTypebot.delayMessage, + unknownMessage: findTypebot.unknownMessage, + listeningFromMe: findTypebot.listeningFromMe, sessions, }; @@ -163,10 +164,10 @@ export class TypebotService { const variables = data.variables; const findTypebot = await this.find(instance); const expire = findTypebot.expire; - const keyword_finish = findTypebot.keyword_finish; - const delay_message = findTypebot.delay_message; - const unknown_message = findTypebot.unknown_message; - const listening_from_me = findTypebot.listening_from_me; + const keywordFinish = findTypebot.keywordFinish; + const delayMessage = findTypebot.delayMessage; + const unknownMessage = findTypebot.unknownMessage; + const listeningFromMe = findTypebot.listeningFromMe; const prefilledVariables = { remoteJid: remoteJid, @@ -188,10 +189,10 @@ export class TypebotService { typebot: typebot, remoteJid: remoteJid, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: newSessions, prefilledVariables: prefilledVariables, }); @@ -467,10 +468,10 @@ export class TypebotService { url: data.url, typebot: data.typebot, expire: data.expire, - keyword_finish: data.keyword_finish, - delay_message: data.delay_message, - unknown_message: data.unknown_message, - listening_from_me: data.listening_from_me, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, sessions: data.sessions, }; @@ -585,7 +586,7 @@ export class TypebotService { await instance.textMessage({ number: remoteJid.split('@')[0], options: { - delay: instance.localTypebot.delay_message || 1000, + delay: instance.localTypebot.delayMessage || 1000, presence: 'composing', }, textMessage: { @@ -598,7 +599,7 @@ export class TypebotService { await instance.mediaMessage({ number: remoteJid.split('@')[0], options: { - delay: instance.localTypebot.delay_message || 1000, + delay: instance.localTypebot.delayMessage || 1000, presence: 'composing', }, mediaMessage: { @@ -612,7 +613,7 @@ export class TypebotService { await instance.mediaMessage({ number: remoteJid.split('@')[0], options: { - delay: instance.localTypebot.delay_message || 1000, + delay: instance.localTypebot.delayMessage || 1000, presence: 'composing', }, mediaMessage: { @@ -626,7 +627,7 @@ export class TypebotService { await instance.audioWhatsapp({ number: remoteJid.split('@')[0], options: { - delay: instance.localTypebot.delay_message || 1000, + delay: instance.localTypebot.delayMessage || 1000, presence: 'recording', encoding: true, }, @@ -658,7 +659,7 @@ export class TypebotService { await instance.textMessage({ number: remoteJid.split('@')[0], options: { - delay: instance.localTypebot.delay_message || 1000, + delay: instance.localTypebot.delayMessage || 1000, presence: 'composing', }, textMessage: { @@ -675,16 +676,17 @@ export class TypebotService { } } - public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: MessageRaw) { + public async sendTypebot(instance: InstanceDto, remoteJid: string, msg: Message) { const findTypebot = await this.find(instance); const url = findTypebot.url; const typebot = findTypebot.typebot; - const sessions = (findTypebot.sessions as Session[]) ?? []; + // const sessions = (findTypebot.sessions as Session[]) ?? []; + const sessions = []; const expire = findTypebot.expire; - const keyword_finish = findTypebot.keyword_finish; - const delay_message = findTypebot.delay_message; - const unknown_message = findTypebot.unknown_message; - const listening_from_me = findTypebot.listening_from_me; + const keywordFinish = findTypebot.keywordFinish; + const delayMessage = findTypebot.delayMessage; + const unknownMessage = findTypebot.unknownMessage; + const listeningFromMe = findTypebot.listeningFromMe; const messageType = this.getTypeMessage(msg.message).messageType; const session = sessions.find((session) => session.remoteJid === remoteJid); @@ -705,10 +707,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: newSessions, remoteJid: remoteJid, pushName: msg.pushName, @@ -720,22 +722,22 @@ export class TypebotService { const content = this.getConversationMessage(msg.message); if (!content) { - if (unknown_message) { + if (unknownMessage) { this.waMonitor.waInstances[instance.instanceName].textMessage({ number: remoteJid.split('@')[0], options: { - delay: delay_message || 1000, + delay: delayMessage || 1000, presence: 'composing', }, textMessage: { - text: unknown_message, + text: unknownMessage, }, }); } return; } - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { const newSessions = await this.clearSessions(instance, remoteJid); const typebotData = { @@ -743,10 +745,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: newSessions, }; @@ -801,10 +803,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: sessions, remoteJid: remoteJid, pushName: msg.pushName, @@ -819,22 +821,22 @@ export class TypebotService { const content = this.getConversationMessage(msg.message); if (!content) { - if (unknown_message) { + if (unknownMessage) { this.waMonitor.waInstances[instance.instanceName].textMessage({ number: remoteJid.split('@')[0], options: { - delay: delay_message || 1000, + delay: delayMessage || 1000, presence: 'composing', }, textMessage: { - text: unknown_message, + text: unknownMessage, }, }); } return; } - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { const newSessions = await this.clearSessions(instance, remoteJid); const typebotData = { @@ -842,10 +844,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: newSessions, }; @@ -899,10 +901,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions, }; @@ -911,22 +913,22 @@ export class TypebotService { const content = this.getConversationMessage(msg.message); if (!content) { - if (unknown_message) { + if (unknownMessage) { this.waMonitor.waInstances[instance.instanceName].textMessage({ number: remoteJid.split('@')[0], options: { - delay: delay_message || 1000, + delay: delayMessage || 1000, presence: 'composing', }, textMessage: { - text: unknown_message, + text: unknownMessage, }, }); } return; } - if (keyword_finish && content.toLowerCase() === keyword_finish.toLowerCase()) { + if (keywordFinish && content.toLowerCase() === keywordFinish.toLowerCase()) { const newSessions = await this.clearSessions(instance, remoteJid); const typebotData = { @@ -934,10 +936,10 @@ export class TypebotService { url: url, typebot: typebot, expire: expire, - keyword_finish: keyword_finish, - delay_message: delay_message, - unknown_message: unknown_message, - listening_from_me: listening_from_me, + keywordFinish: keywordFinish, + delayMessage: delayMessage, + unknownMessage: unknownMessage, + listeningFromMe: listeningFromMe, sessions: newSessions, }; diff --git a/src/api/integrations/websocket/models/websocket.model.ts b/src/api/integrations/websocket/models/websocket.model.ts deleted file mode 100644 index c28bd956..00000000 --- a/src/api/integrations/websocket/models/websocket.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../../../libs/mongodb.connect'; - -export class WebsocketRaw { - _id?: string; - enabled?: boolean; - events?: string[]; -} - -const websocketSchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, -}); - -export const WebsocketModel = mongodbServer?.model(WebsocketRaw.name, websocketSchema, 'websocket'); -export type IWebsocketModel = typeof WebsocketModel; diff --git a/src/api/integrations/websocket/repository/websocket.repository.ts b/src/api/integrations/websocket/repository/websocket.repository.ts deleted file mode 100644 index 48d5b7d3..00000000 --- a/src/api/integrations/websocket/repository/websocket.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { IWebsocketModel, WebsocketRaw } from '../../../models'; - -export class WebsocketRepository extends Repository { - constructor(private readonly websocketModel: IWebsocketModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('WebsocketRepository'); - - public async create(data: WebsocketRaw, instance: string): Promise { - try { - this.logger.verbose('creating websocket'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving websocket to db'); - const insert = await this.websocketModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('websocket saved to db: ' + insert.modifiedCount + ' websocket'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving websocket to store'); - - this.writeStore({ - path: join(this.storePath, 'websocket'), - fileName: instance, - data, - }); - - this.logger.verbose('websocket saved to store in path: ' + join(this.storePath, 'websocket') + '/' + instance); - - this.logger.verbose('websocket created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding websocket'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding websocket in db'); - return await this.websocketModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding websocket in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'websocket', instance + '.json'), { - encoding: 'utf-8', - }), - ) as WebsocketRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/integrations/websocket/services/websocket.service.ts b/src/api/integrations/websocket/services/websocket.service.ts index fcbb4353..585800c7 100644 --- a/src/api/integrations/websocket/services/websocket.service.ts +++ b/src/api/integrations/websocket/services/websocket.service.ts @@ -1,6 +1,7 @@ +import { Websocket } from '@prisma/client'; + import { Logger } from '../../../../config/logger.config'; import { InstanceDto } from '../../../dto/instance.dto'; -import { WebsocketRaw } from '../../../models'; import { WAMonitoringService } from '../../../services/monitor.service'; import { WebsocketDto } from '../dto/websocket.dto'; @@ -16,7 +17,7 @@ export class WebsocketService { return { websocket: { ...instance, websocket: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find websocket: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findWebsocket(); @@ -27,7 +28,7 @@ export class WebsocketService { return result; } catch (error) { - return { enabled: false, events: [] }; + return null; } } } diff --git a/src/api/models/auth.model.ts b/src/api/models/auth.model.ts deleted file mode 100644 index fd84fd45..00000000 --- a/src/api/models/auth.model.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class AuthRaw { - _id?: string; - apikey?: string; - instanceId?: string; -} - -const authSchema = new Schema({ - _id: { type: String, _id: true }, - apikey: { type: String, minlength: 1 }, - instanceId: { type: String, minlength: 1 }, -}); - -export const AuthModel = mongodbServer?.model(AuthRaw.name, authSchema, 'authentication'); -export type IAuthModel = typeof AuthModel; diff --git a/src/api/models/chat.model.ts b/src/api/models/chat.model.ts deleted file mode 100644 index 0d575e4a..00000000 --- a/src/api/models/chat.model.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class ChatRaw { - _id?: string; - id?: string; - owner: string; - lastMsgTimestamp?: number; - labels?: string[]; -} - -type ChatRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type ChatRawSelect = ChatRawBoolean; - -const chatSchema = new Schema({ - _id: { type: String, _id: true }, - id: { type: String, required: true, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, - labels: { type: [String], default: [] }, -}); - -export const ChatModel = mongodbServer?.model(ChatRaw.name, chatSchema, 'chats'); -export type IChatModel = typeof ChatModel; diff --git a/src/api/models/contact.model.ts b/src/api/models/contact.model.ts deleted file mode 100644 index b1bdd9fb..00000000 --- a/src/api/models/contact.model.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class ContactRaw { - _id?: string; - pushName?: string; - id?: string; - profilePictureUrl?: string; - owner: string; -} - -type ContactRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type ContactRawSelect = ContactRawBoolean; - -const contactSchema = new Schema({ - _id: { type: String, _id: true }, - pushName: { type: String, minlength: 1 }, - id: { type: String, required: true, minlength: 1 }, - profilePictureUrl: { type: String, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, -}); - -export const ContactModel = mongodbServer?.model(ContactRaw.name, contactSchema, 'contacts'); -export type IContactModel = typeof ContactModel; diff --git a/src/api/models/index.ts b/src/api/models/index.ts deleted file mode 100644 index 2a94c737..00000000 --- a/src/api/models/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export * from '../integrations/chatwoot/models/chatwoot.model'; -export * from '../integrations/rabbitmq/models/rabbitmq.model'; -export * from '../integrations/sqs/models/sqs.model'; -export * from '../integrations/typebot/models/typebot.model'; -export * from '../integrations/websocket/models/websocket.model'; -export * from './auth.model'; -export * from './chat.model'; -export * from './contact.model'; -export * from './integration.model'; -export * from './label.model'; -export * from './message.model'; -export * from './proxy.model'; -export * from './settings.model'; -export * from './webhook.model'; diff --git a/src/api/models/integration.model.ts b/src/api/models/integration.model.ts deleted file mode 100644 index 6ff519fb..00000000 --- a/src/api/models/integration.model.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class IntegrationRaw { - _id?: string; - integration?: string; - number?: string; - token?: string; -} - -const integrationSchema = new Schema({ - _id: { type: String, _id: true }, - integration: { type: String, required: true }, - number: { type: String, required: true }, - token: { type: String, required: true }, -}); - -export const IntegrationModel = mongodbServer?.model(IntegrationRaw.name, integrationSchema, 'integration'); -export type IntegrationModel = typeof IntegrationModel; diff --git a/src/api/models/label.model.ts b/src/api/models/label.model.ts deleted file mode 100644 index e6931e27..00000000 --- a/src/api/models/label.model.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class LabelRaw { - _id?: string; - id?: string; - owner: string; - name: string; - color: number; - predefinedId?: string; -} - -type LabelRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type LabelRawSelect = LabelRawBoolean; - -const labelSchema = new Schema({ - _id: { type: String, _id: true }, - id: { type: String, required: true, minlength: 1 }, - owner: { type: String, required: true, minlength: 1 }, - name: { type: String, required: true, minlength: 1 }, - color: { type: Number, required: true, min: 0, max: 19 }, - predefinedId: { type: String }, -}); - -export const LabelModel = mongodbServer?.model(LabelRaw.name, labelSchema, 'labels'); -export type ILabelModel = typeof LabelModel; diff --git a/src/api/models/message.model.ts b/src/api/models/message.model.ts deleted file mode 100644 index 7214c5a7..00000000 --- a/src/api/models/message.model.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; -import { wa } from '../types/wa.types'; - -class Key { - id?: string; - remoteJid?: string; - fromMe?: boolean; - participant?: string; -} - -class ChatwootMessage { - messageId?: number; - inboxId?: number; - conversationId?: number; - contactInbox?: { sourceId: string }; - isRead?: boolean; -} - -export class MessageRaw { - _id?: string; - key?: Key; - pushName?: string; - participant?: string; - message?: object; - messageType?: string; - messageTimestamp?: number | Long.Long; - owner: string; - source?: 'android' | 'web' | 'ios' | 'unknown' | 'desktop'; - source_id?: string; - source_reply_id?: string; - chatwoot?: ChatwootMessage; - contextInfo?: any; - status?: wa.StatusMessage | any; -} - -type MessageRawBoolean = { - [P in keyof T]?: 0 | 1; -}; -export type MessageRawSelect = Omit, 'key'>, 'chatwoot'> & { - key?: MessageRawBoolean; - chatwoot?: MessageRawBoolean; -}; - -const messageSchema = new Schema({ - _id: { type: String, _id: true }, - key: { - id: { type: String, required: true, minlength: 1 }, - remoteJid: { type: String, required: true, minlength: 1 }, - fromMe: { type: Boolean, required: true }, - participant: { type: String, minlength: 1 }, - }, - pushName: { type: String }, - participant: { type: String }, - messageType: { type: String }, - message: { type: Object }, - source: { type: String, minlength: 3, enum: ['android', 'web', 'ios', 'unknown', 'desktop'] }, - messageTimestamp: { type: Number, required: true }, - owner: { type: String, required: true, minlength: 1 }, - chatwoot: { - messageId: { type: Number }, - inboxId: { type: Number }, - conversationId: { type: Number }, - contactInbox: { type: Object }, - isRead: { type: Boolean }, - }, -}); - -messageSchema.index({ 'chatwoot.messageId': 1, owner: 1 }); -messageSchema.index({ 'key.id': 1 }); -messageSchema.index({ 'key.id': 1, owner: 1 }); -messageSchema.index({ owner: 1 }); - -export const MessageModel = mongodbServer?.model(MessageRaw.name, messageSchema, 'messages'); -export type IMessageModel = typeof MessageModel; - -export class MessageUpdateRaw { - _id?: string; - remoteJid?: string; - id?: string; - fromMe?: boolean; - participant?: string; - datetime?: number; - status?: wa.StatusMessage; - owner: string; - pollUpdates?: any; -} - -const messageUpdateSchema = new Schema({ - _id: { type: String, _id: true }, - remoteJid: { type: String, required: true, min: 1 }, - id: { type: String, required: true, min: 1 }, - fromMe: { type: Boolean, required: true }, - participant: { type: String, min: 1 }, - datetime: { type: Number, required: true, min: 1 }, - status: { type: String, required: true }, - owner: { type: String, required: true, min: 1 }, -}); - -export const MessageUpModel = mongodbServer?.model(MessageUpdateRaw.name, messageUpdateSchema, 'messageUpdate'); -export type IMessageUpModel = typeof MessageUpModel; diff --git a/src/api/models/proxy.model.ts b/src/api/models/proxy.model.ts deleted file mode 100644 index ed4580f4..00000000 --- a/src/api/models/proxy.model.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -class Proxy { - host?: string; - port?: string; - protocol?: string; - username?: string; - password?: string; -} - -export class ProxyRaw { - _id?: string; - enabled?: boolean; - proxy?: Proxy; -} - -const proxySchema = new Schema({ - _id: { type: String, _id: true }, - enabled: { type: Boolean, required: true }, - proxy: { - host: { type: String, required: true }, - port: { type: String, required: true }, - protocol: { type: String, required: true }, - username: { type: String, required: false }, - password: { type: String, required: false }, - }, -}); - -export const ProxyModel = mongodbServer?.model(ProxyRaw.name, proxySchema, 'proxy'); -export type IProxyModel = typeof ProxyModel; diff --git a/src/api/models/settings.model.ts b/src/api/models/settings.model.ts deleted file mode 100644 index 05f073c5..00000000 --- a/src/api/models/settings.model.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class SettingsRaw { - _id?: string; - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; -} - -const settingsSchema = new Schema({ - _id: { type: String, _id: true }, - reject_call: { type: Boolean, required: true }, - msg_call: { type: String, required: true }, - groups_ignore: { type: Boolean, required: true }, - always_online: { type: Boolean, required: true }, - read_messages: { type: Boolean, required: true }, - read_status: { type: Boolean, required: true }, - sync_full_history: { type: Boolean, required: true }, -}); - -export const SettingsModel = mongodbServer?.model(SettingsRaw.name, settingsSchema, 'settings'); -export type ISettingsModel = typeof SettingsModel; diff --git a/src/api/models/webhook.model.ts b/src/api/models/webhook.model.ts deleted file mode 100644 index 5c970392..00000000 --- a/src/api/models/webhook.model.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Schema } from 'mongoose'; - -import { mongodbServer } from '../../libs/mongodb.connect'; - -export class WebhookRaw { - _id?: string; - url?: string; - enabled?: boolean; - events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; -} - -const webhookSchema = new Schema({ - _id: { type: String, _id: true }, - url: { type: String, required: true }, - enabled: { type: Boolean, required: true }, - events: { type: [String], required: true }, - webhook_by_events: { type: Boolean, required: true }, - webhook_base64: { type: Boolean, required: true }, -}); - -export const WebhookModel = mongodbServer?.model(WebhookRaw.name, webhookSchema, 'webhook'); -export type IWebhookModel = typeof WebhookModel; diff --git a/src/api/repository/mongodb/auth.repository.ts b/src/api/repository/mongodb/auth.repository.ts deleted file mode 100644 index 94ea80f7..00000000 --- a/src/api/repository/mongodb/auth.repository.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { Auth, ConfigService } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { AUTH_DIR } from '../../../config/path.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { AuthRaw, IAuthModel, IntegrationModel } from '../../models'; - -export class AuthRepository extends Repository { - constructor( - private readonly authModel: IAuthModel, - private readonly integrationModel: IntegrationModel, - readonly configService: ConfigService, - ) { - super(configService); - this.auth = configService.get('AUTHENTICATION'); - } - - private readonly auth: Auth; - private readonly logger = new Logger('AuthRepository'); - - public async create(data: AuthRaw, instance: string): Promise { - try { - this.logger.verbose('creating auth'); - - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving auth to db'); - const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving auth to store'); - - this.writeStore({ - path: join(AUTH_DIR, 'apikey'), - fileName: instance, - data, - }); - this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, 'apikey') + '/' + instance); - - this.logger.verbose('auth created'); - return { insertCount: 1 }; - } catch (error) { - return { error } as any; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding auth in store'); - - return JSON.parse( - readFileSync(join(AUTH_DIR, 'apikey', instance + '.json'), { - encoding: 'utf-8', - }), - ) as AuthRaw; - } catch (error) { - return {}; - } - } - - public async findByKey(key: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ apikey: key }); - } - - return {}; - } catch (error) { - return {}; - } - } - - public async list(): Promise { - try { - if (this.dbSettings.ENABLED) { - this.logger.verbose('listing auth in db'); - return await this.authModel.find(); - } - - this.logger.verbose('listing auth in store'); - - const auths: AuthRaw[] = []; - const openDir = opendirSync(join(AUTH_DIR, 'apikey'), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - auths.push( - JSON.parse( - readFileSync(join(AUTH_DIR, 'apikey', dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - return auths; - } catch (error) { - return []; - } - } - - public async findInstanceNameById(instanceId: string): Promise { - try { - this.logger.verbose('finding auth by instanceId'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const response = await this.authModel.findOne({ instanceId }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } - - public async findInstanceNameByNumber(number: string): Promise { - try { - this.logger.verbose('finding auth by number'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const instance = await this.integrationModel.findOne({ number }); - - const response = await this.authModel.findOne({ _id: instance._id }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } -} diff --git a/src/api/repository/mongodb/chat.repository.ts b/src/api/repository/mongodb/chat.repository.ts deleted file mode 100644 index 087b9674..00000000 --- a/src/api/repository/mongodb/chat.repository.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { ChatRaw, ChatRawSelect, IChatModel } from '../../models'; - -export class ChatQuery { - select?: ChatRawSelect; - where: ChatRaw; -} - -export class ChatRepository extends Repository { - constructor(private readonly chatModel: IChatModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ChatRepository'); - - public async insert(data: ChatRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting chats'); - if (data.length === 0) { - this.logger.verbose('no chats to insert'); - return; - } - - try { - this.logger.verbose('saving chats to store'); - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving chats to db'); - const insert = await this.chatModel.insertMany([...data]); - - this.logger.verbose('chats saved to db: ' + insert.length + ' chats'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving chats to store'); - - const store = this.configService.get('STORE'); - - if (store.CHATS) { - this.logger.verbose('saving chats to store'); - data.forEach((chat) => { - this.writeStore({ - path: join(this.storePath, 'chats', instanceName), - fileName: chat.id, - data: chat, - }); - this.logger.verbose( - 'chats saved to store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id, - ); - }); - - this.logger.verbose('chats saved to store'); - return { insertCount: data.length }; - } - - this.logger.verbose('chats not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: ChatQuery): Promise { - try { - this.logger.verbose('finding chats'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding chats in db'); - return await this.chatModel.find({ owner: query.where.owner }).select(query.select ?? {}); - } - - this.logger.verbose('finding chats in store'); - - const chats: ChatRaw[] = []; - const openDir = opendirSync(join(this.storePath, 'chats', query.where.owner)); - for await (const dirent of openDir) { - if (dirent.isFile()) { - chats.push( - JSON.parse( - readFileSync(join(this.storePath, 'chats', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - this.logger.verbose('chats found in store: ' + chats.length + ' chats'); - return chats; - } catch (error) { - return []; - } - } - - public async delete(query: ChatQuery) { - try { - this.logger.verbose('deleting chats'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting chats in db'); - return await this.chatModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting chats in store'); - rmSync(join(this.storePath, 'chats', query.where.owner, query.where.id + '.josn'), { - force: true, - recursive: true, - }); - - return { deleted: { chatId: query.where.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } - - public async update(data: ChatRaw[], instanceName: string, saveDb = false): Promise { - try { - this.logger.verbose('updating chats'); - - if (data.length === 0) { - this.logger.verbose('no chats to update'); - return; - } - - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating chats in db'); - - const chats = data.map((chat) => { - return { - updateOne: { - filter: { id: chat.id }, - update: { ...chat }, - upsert: true, - }, - }; - }); - - const { nModified } = await this.chatModel.bulkWrite(chats); - - this.logger.verbose('chats updated in db: ' + nModified + ' chats'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating chats in store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('updating chats in store'); - data.forEach((chat) => { - this.writeStore({ - path: join(this.storePath, 'chats', instanceName), - fileName: chat.id, - data: chat, - }); - this.logger.verbose( - 'chats updated in store in path: ' + join(this.storePath, 'chats', instanceName) + '/' + chat.id, - ); - }); - - this.logger.verbose('chats updated in store: ' + data.length + ' chats'); - - return { insertCount: data.length }; - } - - this.logger.verbose('chats not updated'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } -} diff --git a/src/api/repository/mongodb/contact.repository.ts b/src/api/repository/mongodb/contact.repository.ts deleted file mode 100644 index d6b4df0d..00000000 --- a/src/api/repository/mongodb/contact.repository.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { ContactRaw, ContactRawSelect, IContactModel } from '../../models'; - -export class ContactQuery { - select?: ContactRawSelect; - where: ContactRaw; -} - -export class ContactQueryMany { - owner: ContactRaw['owner']; - ids: ContactRaw['id'][]; -} - -export class ContactRepository extends Repository { - constructor(private readonly contactModel: IContactModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ContactRepository'); - - public async insert(data: ContactRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting contacts'); - - if (data.length === 0) { - this.logger.verbose('no contacts to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving contacts to db'); - - const insert = await this.contactModel.insertMany([...data]); - - this.logger.verbose('contacts saved to db: ' + insert.length + ' contacts'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving contacts to store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('saving contacts to store'); - data.forEach((contact) => { - this.writeStore({ - path: join(this.storePath, 'contacts', instanceName), - fileName: contact.id, - data: contact, - }); - this.logger.verbose( - 'contacts saved to store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, - ); - }); - - this.logger.verbose('contacts saved to store: ' + data.length + ' contacts'); - return { insertCount: data.length }; - } - - this.logger.verbose('contacts not saved'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async update(data: ContactRaw[], instanceName: string, saveDb = false): Promise { - try { - this.logger.verbose('updating contacts'); - - if (data.length === 0) { - this.logger.verbose('no contacts to update'); - return; - } - - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating contacts in db'); - - const contacts = data.map((contact) => { - return { - updateOne: { - filter: { id: contact.id }, - update: { ...contact }, - upsert: true, - }, - }; - }); - - const { nModified } = await this.contactModel.bulkWrite(contacts); - - this.logger.verbose('contacts updated in db: ' + nModified + ' contacts'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating contacts in store'); - - const store = this.configService.get('STORE'); - - if (store.CONTACTS) { - this.logger.verbose('updating contacts in store'); - data.forEach((contact) => { - this.writeStore({ - path: join(this.storePath, 'contacts', instanceName), - fileName: contact.id, - data: contact, - }); - this.logger.verbose( - 'contacts updated in store in path: ' + join(this.storePath, 'contacts', instanceName) + '/' + contact.id, - ); - }); - - this.logger.verbose('contacts updated in store: ' + data.length + ' contacts'); - - return { insertCount: data.length }; - } - - this.logger.verbose('contacts not updated'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: ContactQuery): Promise { - try { - this.logger.verbose('finding contacts'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding contacts in db'); - return await this.contactModel.find({ ...query.where }).select(query.select ?? {}); - } - - this.logger.verbose('finding contacts in store'); - const contacts: ContactRaw[] = []; - if (query?.where?.id) { - this.logger.verbose('finding contacts in store by id'); - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.where.owner, query.where.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding contacts in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'contacts', query.where.owner), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts'); - return contacts; - } catch (error) { - return []; - } - } - - public async findManyById(query: ContactQueryMany): Promise { - try { - this.logger.verbose('finding contacts'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding contacts in db'); - return await this.contactModel.find({ - owner: query.owner, - id: { $in: query.ids }, - }); - } - - this.logger.verbose('finding contacts in store'); - const contacts: ContactRaw[] = []; - if (query.ids.length > 0) { - this.logger.verbose('finding contacts in store by id'); - query.ids.forEach((id) => { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.owner, id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - }); - } else { - this.logger.verbose('finding contacts in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'contacts', query.owner), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - contacts.push( - JSON.parse( - readFileSync(join(this.storePath, 'contacts', query.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('contacts found in store: ' + contacts.length + ' contacts'); - return contacts; - } catch (error) { - return []; - } - } -} diff --git a/src/api/repository/mongodb/instance.repository.ts b/src/api/repository/mongodb/instance.repository.ts deleted file mode 100644 index 94ea80f7..00000000 --- a/src/api/repository/mongodb/instance.repository.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { Auth, ConfigService } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { AUTH_DIR } from '../../../config/path.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { AuthRaw, IAuthModel, IntegrationModel } from '../../models'; - -export class AuthRepository extends Repository { - constructor( - private readonly authModel: IAuthModel, - private readonly integrationModel: IntegrationModel, - readonly configService: ConfigService, - ) { - super(configService); - this.auth = configService.get('AUTHENTICATION'); - } - - private readonly auth: Auth; - private readonly logger = new Logger('AuthRepository'); - - public async create(data: AuthRaw, instance: string): Promise { - try { - this.logger.verbose('creating auth'); - - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving auth to db'); - const insert = await this.authModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('auth saved to db: ' + insert.modifiedCount + ' auth'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving auth to store'); - - this.writeStore({ - path: join(AUTH_DIR, 'apikey'), - fileName: instance, - data, - }); - this.logger.verbose('auth saved to store in path: ' + join(AUTH_DIR, 'apikey') + '/' + instance); - - this.logger.verbose('auth created'); - return { insertCount: 1 }; - } catch (error) { - return { error } as any; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding auth in store'); - - return JSON.parse( - readFileSync(join(AUTH_DIR, 'apikey', instance + '.json'), { - encoding: 'utf-8', - }), - ) as AuthRaw; - } catch (error) { - return {}; - } - } - - public async findByKey(key: string): Promise { - try { - this.logger.verbose('finding auth'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - return await this.authModel.findOne({ apikey: key }); - } - - return {}; - } catch (error) { - return {}; - } - } - - public async list(): Promise { - try { - if (this.dbSettings.ENABLED) { - this.logger.verbose('listing auth in db'); - return await this.authModel.find(); - } - - this.logger.verbose('listing auth in store'); - - const auths: AuthRaw[] = []; - const openDir = opendirSync(join(AUTH_DIR, 'apikey'), { - encoding: 'utf-8', - }); - for await (const dirent of openDir) { - if (dirent.isFile()) { - auths.push( - JSON.parse( - readFileSync(join(AUTH_DIR, 'apikey', dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - return auths; - } catch (error) { - return []; - } - } - - public async findInstanceNameById(instanceId: string): Promise { - try { - this.logger.verbose('finding auth by instanceId'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const response = await this.authModel.findOne({ instanceId }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } - - public async findInstanceNameByNumber(number: string): Promise { - try { - this.logger.verbose('finding auth by number'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding auth in db'); - const instance = await this.integrationModel.findOne({ number }); - - const response = await this.authModel.findOne({ _id: instance._id }); - - return response._id; - } - - this.logger.verbose('finding auth in store is not supported'); - } catch (error) { - return null; - } - } -} diff --git a/src/api/repository/mongodb/integration.repository.ts b/src/api/repository/mongodb/integration.repository.ts deleted file mode 100644 index cb7f9fa5..00000000 --- a/src/api/repository/mongodb/integration.repository.ts +++ /dev/null @@ -1,64 +0,0 @@ -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 { IntegrationModel, IntegrationRaw } from '../../models'; - -export class IntegrationRepository extends Repository { - constructor(private readonly integrationModel: IntegrationModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('IntegrationRepository'); - - public async create(data: IntegrationRaw, instance: string): Promise { - try { - this.logger.verbose('creating integration'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving integration to db'); - const insert = await this.integrationModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('integration saved to db: ' + insert.modifiedCount + ' integration'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving integration to store'); - - this.writeStore({ - path: join(this.storePath, 'integration'), - fileName: instance, - data, - }); - - this.logger.verbose( - 'integration saved to store in path: ' + join(this.storePath, 'integration') + '/' + instance, - ); - - this.logger.verbose('integration created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding integration'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding integration in db'); - return await this.integrationModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding integration in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'integration', instance + '.json'), { - encoding: 'utf-8', - }), - ) as IntegrationRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/mongodb/label.repository.ts b/src/api/repository/mongodb/label.repository.ts deleted file mode 100644 index 73ba5bf9..00000000 --- a/src/api/repository/mongodb/label.repository.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { ILabelModel, LabelRaw, LabelRawSelect } from '../../models'; - -export class LabelQuery { - select?: LabelRawSelect; - where: Partial; -} - -export class LabelRepository extends Repository { - constructor(private readonly labelModel: ILabelModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('LabelRepository'); - - public async insert(data: LabelRaw, instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting labels'); - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving labels to db'); - const insert = await this.labelModel.findOneAndUpdate({ id: data.id }, data, { upsert: true }); - - this.logger.verbose(`label ${data.name} saved to db`); - return { insertCount: Number(!!insert._id) }; - } - - this.logger.verbose('saving label to store'); - - const store = this.configService.get('STORE'); - - if (store.LABELS) { - this.logger.verbose('saving label to store'); - this.writeStore({ - path: join(this.storePath, 'labels', instanceName), - fileName: data.id, - data, - }); - this.logger.verbose( - 'labels saved to store in path: ' + join(this.storePath, 'labels', instanceName) + '/' + data.id, - ); - - this.logger.verbose(`label ${data.name} saved to store`); - return { insertCount: 1 }; - } - - this.logger.verbose('labels not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } finally { - data = undefined; - } - } - - public async find(query: LabelQuery): Promise { - try { - this.logger.verbose('finding labels'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding labels in db'); - return await this.labelModel.find({ owner: query.where.owner }).select(query.select ?? {}); - } - - this.logger.verbose('finding labels in store'); - - const labels: LabelRaw[] = []; - const openDir = opendirSync(join(this.storePath, 'labels', query.where.owner)); - for await (const dirent of openDir) { - if (dirent.isFile()) { - labels.push( - JSON.parse( - readFileSync(join(this.storePath, 'labels', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - - this.logger.verbose('labels found in store: ' + labels.length + ' labels'); - return labels; - } catch (error) { - return []; - } - } - - public async delete(query: LabelQuery) { - try { - this.logger.verbose('deleting labels'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting labels in db'); - return await this.labelModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting labels in store'); - rmSync(join(this.storePath, 'labels', query.where.owner, query.where.id + '.josn'), { - force: true, - recursive: true, - }); - - return { deleted: { labelId: query.where.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } -} diff --git a/src/api/repository/mongodb/message.repository.ts b/src/api/repository/mongodb/message.repository.ts deleted file mode 100644 index ae0bcfc5..00000000 --- a/src/api/repository/mongodb/message.repository.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { opendirSync, readFileSync, rmSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { IMessageModel, MessageRaw, MessageRawSelect } from '../../models'; - -export class MessageQuery { - select?: MessageRawSelect; - where: MessageRaw; - limit?: number; -} - -export class MessageRepository extends Repository { - constructor(private readonly messageModel: IMessageModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('MessageRepository'); - - public buildQuery(query: MessageQuery): MessageQuery { - for (const [o, p] of Object.entries(query?.where || {})) { - if (typeof p === 'object' && p !== null && !Array.isArray(p)) { - for (const [k, v] of Object.entries(p)) { - query.where[`${o}.${k}`] = v; - } - delete query.where[o]; - } - } - - for (const [o, p] of Object.entries(query?.select || {})) { - if (typeof p === 'object' && p !== null && !Array.isArray(p)) { - for (const [k, v] of Object.entries(p)) { - query.select[`${o}.${k}`] = v; - } - delete query.select[o]; - } - } - - return query; - } - - public async insert(data: MessageRaw[], instanceName: string, saveDb = false): Promise { - this.logger.verbose('inserting messages'); - - if (!Array.isArray(data) || data.length === 0) { - this.logger.verbose('no messages to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving messages to db'); - const cleanedData = data.map((obj) => { - const cleanedObj = { ...obj }; - if ('extendedTextMessage' in obj.message) { - const extendedTextMessage = obj.message.extendedTextMessage as { - contextInfo?: { - mentionedJid?: any; - }; - }; - - if (typeof extendedTextMessage === 'object' && extendedTextMessage !== null) { - if ('contextInfo' in extendedTextMessage) { - delete extendedTextMessage.contextInfo?.mentionedJid; - extendedTextMessage.contextInfo = {}; - } - } - } - return cleanedObj; - }); - - const insert = await this.messageModel.insertMany([...cleanedData]); - - this.logger.verbose('messages saved to db: ' + insert.length + ' messages'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving messages to store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGES) { - this.logger.verbose('saving messages to store'); - - data.forEach((message) => { - this.writeStore({ - path: join(this.storePath, 'messages', instanceName), - fileName: message.key.id, - data: message, - }); - this.logger.verbose( - 'messages saved to store in path: ' + join(this.storePath, 'messages', instanceName) + '/' + message.key.id, - ); - }); - - this.logger.verbose('messages saved to store: ' + data.length + ' messages'); - return { insertCount: data.length }; - } - - this.logger.verbose('messages not saved to store'); - return { insertCount: 0 }; - } catch (error) { - console.log('ERROR: ', error); - return error; - } finally { - data = undefined; - } - } - - public async find(query: MessageQuery) { - try { - this.logger.verbose('finding messages'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding messages in db'); - query = this.buildQuery(query); - - return await this.messageModel - .find({ ...query.where }) - .select(query.select || {}) - .sort({ messageTimestamp: -1 }) - .limit(query?.limit ?? 0); - } - - this.logger.verbose('finding messages in store'); - const messages: MessageRaw[] = []; - if (query?.where?.key?.id) { - this.logger.verbose('finding messages in store by id'); - messages.push( - JSON.parse( - readFileSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding messages in store by owner'); - const openDir = opendirSync(join(this.storePath, 'messages', query.where.owner), { - encoding: 'utf-8', - }); - - for await (const dirent of openDir) { - if (dirent.isFile()) { - messages.push( - JSON.parse( - readFileSync(join(this.storePath, 'messages', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('messages found in store: ' + messages.length + ' messages'); - return messages - .sort((x, y) => { - return (y.messageTimestamp as number) - (x.messageTimestamp as number); - }) - .splice(0, query?.limit ?? messages.length); - } catch (error) { - this.logger.error(`error on message find: ${error.toString()}`); - return []; - } - } - - public async update(data: MessageRaw[], instanceName: string, saveDb?: boolean): Promise { - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('updating messages in db'); - - const messages = data.map((message) => { - return { - updateOne: { - filter: { 'key.id': message.key.id }, - update: { ...message }, - }, - }; - }); - - const { nModified } = await this.messageModel.bulkWrite(messages); - - this.logger.verbose('messages updated in db: ' + nModified + ' messages'); - return { insertCount: nModified }; - } - - this.logger.verbose('updating messages in store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGES) { - this.logger.verbose('updating messages in store'); - data.forEach((message) => { - this.writeStore({ - path: join(this.storePath, 'messages', instanceName), - fileName: message.key.id, - data: message, - }); - this.logger.verbose( - 'messages updated in store in path: ' + - join(this.storePath, 'messages', instanceName) + - '/' + - message.key.id, - ); - }); - - this.logger.verbose('messages updated in store: ' + data.length + ' messages'); - return { insertCount: data.length }; - } - - this.logger.verbose('messages not updated'); - return { insertCount: 0 }; - } catch (error) { - this.logger.error(error); - } - } - - public async delete(query: MessageQuery) { - try { - this.logger.verbose('deleting message'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('deleting message in db'); - query = this.buildQuery(query); - - return await this.messageModel.deleteOne({ ...query.where }); - } - - this.logger.verbose('deleting message in store'); - rmSync(join(this.storePath, 'messages', query.where.owner, query.where.key.id + '.json'), { - force: true, - recursive: true, - }); - - return { deleted: { messageId: query.where.key.id } }; - } catch (error) { - return { error: error?.toString() }; - } - } -} diff --git a/src/api/repository/mongodb/messageUp.repository.ts b/src/api/repository/mongodb/messageUp.repository.ts deleted file mode 100644 index 8c967e8f..00000000 --- a/src/api/repository/mongodb/messageUp.repository.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { opendirSync, readFileSync } from 'fs'; -import { join } from 'path'; - -import { ConfigService, StoreConf } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { IInsert, Repository } from '../../abstract/abstract.repository'; -import { IMessageUpModel, MessageUpdateRaw } from '../../models'; - -export class MessageUpQuery { - where: MessageUpdateRaw; - limit?: number; -} - -export class MessageUpRepository extends Repository { - constructor(private readonly messageUpModel: IMessageUpModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('MessageUpRepository'); - - public async insert(data: MessageUpdateRaw[], instanceName: string, saveDb?: boolean): Promise { - this.logger.verbose('inserting message up'); - - if (data.length === 0) { - this.logger.verbose('no message up to insert'); - return; - } - - try { - if (this.dbSettings.ENABLED && saveDb) { - this.logger.verbose('saving message up to db'); - const insert = await this.messageUpModel.insertMany([...data]); - - this.logger.verbose('message up saved to db: ' + insert.length + ' message up'); - return { insertCount: insert.length }; - } - - this.logger.verbose('saving message up to store'); - - const store = this.configService.get('STORE'); - - if (store.MESSAGE_UP) { - this.logger.verbose('saving message up to store'); - data.forEach((update) => { - this.writeStore({ - path: join(this.storePath, 'message-up', instanceName), - fileName: update.id, - data: update, - }); - this.logger.verbose( - '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'); - return { insertCount: data.length }; - } - - this.logger.verbose('message up not saved to store'); - return { insertCount: 0 }; - } catch (error) { - return error; - } - } - - public async find(query: MessageUpQuery) { - try { - this.logger.verbose('finding message up'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding message up in db'); - return await this.messageUpModel - .find({ ...query.where }) - .sort({ datetime: -1 }) - .limit(query?.limit ?? 0); - } - - this.logger.verbose('finding message up in store'); - - const messageUpdate: MessageUpdateRaw[] = []; - if (query?.where?.id) { - this.logger.verbose('finding message up in store by id'); - - messageUpdate.push( - JSON.parse( - readFileSync(join(this.storePath, 'message-up', query.where.owner, query.where.id + '.json'), { - encoding: 'utf-8', - }), - ), - ); - } else { - this.logger.verbose('finding message up in store by owner'); - - const openDir = opendirSync(join(this.storePath, 'message-up', query.where.owner), { - encoding: 'utf-8', - }); - - for await (const dirent of openDir) { - if (dirent.isFile()) { - messageUpdate.push( - JSON.parse( - readFileSync(join(this.storePath, 'message-up', query.where.owner, dirent.name), { - encoding: 'utf-8', - }), - ), - ); - } - } - } - - this.logger.verbose('message up found in store: ' + messageUpdate.length + ' message up'); - return messageUpdate - .sort((x, y) => { - return y.datetime - x.datetime; - }) - .splice(0, query?.limit ?? messageUpdate.length); - } catch (error) { - return []; - } - } -} diff --git a/src/api/repository/mongodb/proxy.repository.ts b/src/api/repository/mongodb/proxy.repository.ts deleted file mode 100644 index e624da16..00000000 --- a/src/api/repository/mongodb/proxy.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { IProxyModel, ProxyRaw } from '../../models'; - -export class ProxyRepository extends Repository { - constructor(private readonly proxyModel: IProxyModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('ProxyRepository'); - - public async create(data: ProxyRaw, instance: string): Promise { - try { - this.logger.verbose('creating proxy'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving proxy to db'); - const insert = await this.proxyModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('proxy saved to db: ' + insert.modifiedCount + ' proxy'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving proxy to store'); - - this.writeStore({ - path: join(this.storePath, 'proxy'), - fileName: instance, - data, - }); - - this.logger.verbose('proxy saved to store in path: ' + join(this.storePath, 'proxy') + '/' + instance); - - this.logger.verbose('proxy created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding proxy'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding proxy in db'); - return await this.proxyModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding proxy in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'proxy', instance + '.json'), { - encoding: 'utf-8', - }), - ) as ProxyRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/mongodb/repository.manager.ts b/src/api/repository/mongodb/repository.manager.ts deleted file mode 100644 index 410f9509..00000000 --- a/src/api/repository/mongodb/repository.manager.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import fs from 'fs'; -import { MongoClient } from 'mongodb'; -import { join } from 'path'; - -import { ConfigService, Database } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; -import { ChatwootRepository } from '../../integrations/chatwoot/repository/chatwoot.repository'; -import { RabbitmqRepository } from '../../integrations/rabbitmq/repository/rabbitmq.repository'; -import { SqsRepository } from '../../integrations/sqs/repository/sqs.repository'; -import { TypebotRepository } from '../../integrations/typebot/repository/typebot.repository'; -import { WebsocketRepository } from '../../integrations/websocket/repository/websocket.repository'; -import { AuthRepository } from './auth.repository'; -import { ChatRepository } from './chat.repository'; -import { ContactRepository } from './contact.repository'; -import { IntegrationRepository } from './integration.repository'; -import { LabelRepository } from './label.repository'; -import { MessageRepository } from './message.repository'; -import { MessageUpRepository } from './messageUp.repository'; -import { ProxyRepository } from './proxy.repository'; -import { SettingsRepository } from './settings.repository'; -import { WebhookRepository } from './webhook.repository'; -export class MongodbRepository { - constructor( - public readonly message: MessageRepository, - public readonly chat: ChatRepository, - public readonly contact: ContactRepository, - public readonly messageUpdate: MessageUpRepository, - public readonly webhook: WebhookRepository, - public readonly chatwoot: ChatwootRepository, - public readonly settings: SettingsRepository, - public readonly websocket: WebsocketRepository, - public readonly rabbitmq: RabbitmqRepository, - public readonly sqs: SqsRepository, - public readonly typebot: TypebotRepository, - public readonly proxy: ProxyRepository, - public readonly integration: IntegrationRepository, - public readonly auth: AuthRepository, - public readonly labels: LabelRepository, - private configService: ConfigService, - mongodbServer?: MongoClient, - prismaServer?: PrismaClient, - ) { - this.mongodbClient = mongodbServer; - this.prismaClient = prismaServer; - this.__init_repo_without_db__(); - } - - private mongodbClient?: MongoClient; - private prismaClient?: PrismaClient; - private readonly logger = new Logger('RepositoryBroker'); - - public get mongodbServer() { - return this.mongodbClient; - } - - public get prismaServer() { - return this.prismaClient; - } - - private __init_repo_without_db__() { - this.logger.verbose('initializing repository without db'); - if (!this.configService.get('DATABASE').ENABLED) { - const storePath = join(process.cwd(), 'store'); - - this.logger.verbose('creating store path: ' + storePath); - try { - const authDir = join(storePath, 'auth', 'apikey'); - const chatsDir = join(storePath, 'chats'); - const contactsDir = join(storePath, 'contacts'); - const messagesDir = join(storePath, 'messages'); - const messageUpDir = join(storePath, 'message-up'); - const webhookDir = join(storePath, 'webhook'); - const chatwootDir = join(storePath, 'chatwoot'); - const settingsDir = join(storePath, 'settings'); - const websocketDir = join(storePath, 'websocket'); - const rabbitmqDir = join(storePath, 'rabbitmq'); - const sqsDir = join(storePath, 'sqs'); - const typebotDir = join(storePath, 'typebot'); - const proxyDir = join(storePath, 'proxy'); - const integrationDir = join(storePath, 'integration'); - const tempDir = join(storePath, 'temp'); - - if (!fs.existsSync(authDir)) { - this.logger.verbose('creating auth dir: ' + authDir); - fs.mkdirSync(authDir, { recursive: true }); - } - if (!fs.existsSync(chatsDir)) { - this.logger.verbose('creating chats dir: ' + chatsDir); - fs.mkdirSync(chatsDir, { recursive: true }); - } - if (!fs.existsSync(contactsDir)) { - this.logger.verbose('creating contacts dir: ' + contactsDir); - fs.mkdirSync(contactsDir, { recursive: true }); - } - if (!fs.existsSync(messagesDir)) { - this.logger.verbose('creating messages dir: ' + messagesDir); - fs.mkdirSync(messagesDir, { recursive: true }); - } - if (!fs.existsSync(messageUpDir)) { - this.logger.verbose('creating message-up dir: ' + messageUpDir); - fs.mkdirSync(messageUpDir, { recursive: true }); - } - if (!fs.existsSync(webhookDir)) { - this.logger.verbose('creating webhook dir: ' + webhookDir); - fs.mkdirSync(webhookDir, { recursive: true }); - } - if (!fs.existsSync(chatwootDir)) { - this.logger.verbose('creating chatwoot dir: ' + chatwootDir); - fs.mkdirSync(chatwootDir, { recursive: true }); - } - if (!fs.existsSync(settingsDir)) { - this.logger.verbose('creating settings dir: ' + settingsDir); - fs.mkdirSync(settingsDir, { recursive: true }); - } - if (!fs.existsSync(websocketDir)) { - this.logger.verbose('creating websocket dir: ' + websocketDir); - fs.mkdirSync(websocketDir, { recursive: true }); - } - if (!fs.existsSync(rabbitmqDir)) { - this.logger.verbose('creating rabbitmq dir: ' + rabbitmqDir); - fs.mkdirSync(rabbitmqDir, { recursive: true }); - } - if (!fs.existsSync(sqsDir)) { - this.logger.verbose('creating sqs dir: ' + sqsDir); - fs.mkdirSync(sqsDir, { recursive: true }); - } - if (!fs.existsSync(typebotDir)) { - this.logger.verbose('creating typebot dir: ' + typebotDir); - fs.mkdirSync(typebotDir, { recursive: true }); - } - if (!fs.existsSync(proxyDir)) { - this.logger.verbose('creating proxy dir: ' + proxyDir); - fs.mkdirSync(proxyDir, { recursive: true }); - } - if (!fs.existsSync(integrationDir)) { - this.logger.verbose('creating integration dir: ' + integrationDir); - fs.mkdirSync(integrationDir, { recursive: true }); - } - if (!fs.existsSync(tempDir)) { - this.logger.verbose('creating temp dir: ' + tempDir); - fs.mkdirSync(tempDir, { recursive: true }); - } - } catch (error) { - this.logger.error(error); - } - } else { - try { - const storePath = join(process.cwd(), 'store'); - - this.logger.verbose('creating store path: ' + storePath); - - const tempDir = join(storePath, 'temp'); - const chatwootDir = join(storePath, 'chatwoot'); - - 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); - } - } - } -} diff --git a/src/api/repository/mongodb/settings.repository.ts b/src/api/repository/mongodb/settings.repository.ts deleted file mode 100644 index d2000f48..00000000 --- a/src/api/repository/mongodb/settings.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { ISettingsModel, SettingsRaw } from '../../models'; - -export class SettingsRepository extends Repository { - constructor(private readonly settingsModel: ISettingsModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('SettingsRepository'); - - public async create(data: SettingsRaw, instance: string): Promise { - try { - this.logger.verbose('creating settings'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving settings to db'); - const insert = await this.settingsModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('settings saved to db: ' + insert.modifiedCount + ' settings'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving settings to store'); - - this.writeStore({ - path: join(this.storePath, 'settings'), - fileName: instance, - data, - }); - - this.logger.verbose('settings saved to store in path: ' + join(this.storePath, 'settings') + '/' + instance); - - this.logger.verbose('settings created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding settings'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding settings in db'); - return await this.settingsModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding settings in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'settings', instance + '.json'), { - encoding: 'utf-8', - }), - ) as SettingsRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/mongodb/webhook.repository.ts b/src/api/repository/mongodb/webhook.repository.ts deleted file mode 100644 index fc2b6560..00000000 --- a/src/api/repository/mongodb/webhook.repository.ts +++ /dev/null @@ -1,62 +0,0 @@ -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 { IWebhookModel, WebhookRaw } from '../../models'; - -export class WebhookRepository extends Repository { - constructor(private readonly webhookModel: IWebhookModel, private readonly configService: ConfigService) { - super(configService); - } - - private readonly logger = new Logger('WebhookRepository'); - - public async create(data: WebhookRaw, instance: string): Promise { - try { - this.logger.verbose('creating webhook'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('saving webhook to db'); - const insert = await this.webhookModel.replaceOne({ _id: instance }, { ...data }, { upsert: true }); - - this.logger.verbose('webhook saved to db: ' + insert.modifiedCount + ' webhook'); - return { insertCount: insert.modifiedCount }; - } - - this.logger.verbose('saving webhook to store'); - - this.writeStore({ - path: join(this.storePath, 'webhook'), - fileName: instance, - data, - }); - - this.logger.verbose('webhook saved to store in path: ' + join(this.storePath, 'webhook') + '/' + instance); - - this.logger.verbose('webhook created'); - return { insertCount: 1 }; - } catch (error) { - return error; - } - } - - public async find(instance: string): Promise { - try { - this.logger.verbose('finding webhook'); - if (this.dbSettings.ENABLED) { - this.logger.verbose('finding webhook in db'); - return await this.webhookModel.findOne({ _id: instance }); - } - - this.logger.verbose('finding webhook in store'); - return JSON.parse( - readFileSync(join(this.storePath, 'webhook', instance + '.json'), { - encoding: 'utf-8', - }), - ) as WebhookRaw; - } catch (error) { - return {}; - } - } -} diff --git a/src/api/repository/prisma/repository.service.ts b/src/api/repository/repository.service.ts similarity index 83% rename from src/api/repository/prisma/repository.service.ts rename to src/api/repository/repository.service.ts index c3724f5a..9c9bbf0e 100644 --- a/src/api/repository/prisma/repository.service.ts +++ b/src/api/repository/repository.service.ts @@ -1,7 +1,7 @@ import { PrismaClient } from '@prisma/client'; -import { ConfigService } from '../../../config/env.config'; -import { Logger } from '../../../config/logger.config'; +import { ConfigService } from '../../config/env.config'; +import { Logger } from '../../config/logger.config'; export class Query { where?: T; diff --git a/src/api/routes/chat.router.ts b/src/api/routes/chat.router.ts index 6ccbe89a..4dea069a 100644 --- a/src/api/routes/chat.router.ts +++ b/src/api/routes/chat.router.ts @@ -1,3 +1,4 @@ +import { Contact, Message, MessageUpdate } from '@prisma/client'; import { RequestHandler, Router } from 'express'; import { Logger } from '../../config/logger.config'; @@ -37,9 +38,7 @@ import { WhatsAppNumberDto, } from '../dto/chat.dto'; import { InstanceDto } from '../dto/instance.dto'; -import { ContactQuery } from '../repository/mongodb/contact.repository'; -import { MessageQuery } from '../repository/mongodb/message.repository'; -import { MessageUpQuery } from '../repository/mongodb/messageUp.repository'; +import { Query } from '../repository/repository.service'; import { chatController } from '../server.module'; import { HttpStatus } from './index.router'; @@ -176,10 +175,10 @@ export class ChatRouter extends RouterBroker { logger.verbose('request query: '); logger.verbose(req.query); - const response = await this.dataValidate({ + const response = await this.dataValidate>({ request: req, schema: contactValidateSchema, - ClassRef: ContactQuery, + ClassRef: Query, execute: (instance, data) => chatController.fetchContacts(instance, data), }); @@ -210,10 +209,10 @@ export class ChatRouter extends RouterBroker { logger.verbose('request query: '); logger.verbose(req.query); - const response = await this.dataValidate({ + const response = await this.dataValidate>({ request: req, schema: messageValidateSchema, - ClassRef: MessageQuery, + ClassRef: Query, execute: (instance, data) => chatController.fetchMessages(instance, data), }); @@ -227,10 +226,10 @@ export class ChatRouter extends RouterBroker { logger.verbose('request query: '); logger.verbose(req.query); - const response = await this.dataValidate({ + const response = await this.dataValidate>({ request: req, schema: messageUpSchema, - ClassRef: MessageUpQuery, + ClassRef: Query, execute: (instance, data) => chatController.fetchStatusMessage(instance, data), }); diff --git a/src/api/routes/instance.router.ts b/src/api/routes/instance.router.ts index a150c15a..7bd3bd13 100644 --- a/src/api/routes/instance.router.ts +++ b/src/api/routes/instance.router.ts @@ -1,8 +1,7 @@ import { RequestHandler, Router } from 'express'; -import { ConfigService, Database } from '../../config/env.config'; +import { ConfigService } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; -import { mongodbServer } from '../../libs/mongodb.connect'; import { instanceNameSchema, presenceOnlySchema } from '../../validate/validate.schema'; import { RouterBroker } from '../abstract/abstract.router'; import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; @@ -162,28 +161,6 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }); - - this.router.delete('/deleteDatabase', async (req, res) => { - logger.verbose('request received in deleteDatabase'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const db = this.configService.get('DATABASE'); - if (db.ENABLED) { - try { - await mongodbServer.dropDatabase(); - return res - .status(HttpStatus.CREATED) - .json({ status: 'SUCCESS', error: false, response: { message: 'database deleted' } }); - } catch (error) { - return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: error.message }); - } - } - - return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ error: true, message: 'Database is not enabled' }); - }); } public readonly router = Router(); diff --git a/src/api/server.module.ts b/src/api/server.module.ts index 85f5c15d..df91bad2 100644 --- a/src/api/server.module.ts +++ b/src/api/server.module.ts @@ -2,8 +2,6 @@ import { CacheEngine } from '../cache/cacheengine'; import { configService } from '../config/env.config'; import { eventEmitter } from '../config/event.config'; import { Logger } from '../config/logger.config'; -import { mongodbServer } from '../libs/mongodb.connect'; -import { prismaServer } from '../libs/prisma.connect'; import { ChatController } from './controllers/chat.controller'; import { GroupController } from './controllers/group.controller'; import { InstanceController } from './controllers/instance.controller'; @@ -13,50 +11,17 @@ import { SendMessageController } from './controllers/sendMessage.controller'; import { SettingsController } from './controllers/settings.controller'; import { WebhookController } from './controllers/webhook.controller'; import { ChatwootController } from './integrations/chatwoot/controllers/chatwoot.controller'; -import { ChatwootRepository } from './integrations/chatwoot/repository/chatwoot.repository'; import { ChatwootService } from './integrations/chatwoot/services/chatwoot.service'; import { RabbitmqController } from './integrations/rabbitmq/controllers/rabbitmq.controller'; -import { RabbitmqRepository } from './integrations/rabbitmq/repository/rabbitmq.repository'; import { RabbitmqService } from './integrations/rabbitmq/services/rabbitmq.service'; import { SqsController } from './integrations/sqs/controllers/sqs.controller'; -import { SqsRepository } from './integrations/sqs/repository/sqs.repository'; import { SqsService } from './integrations/sqs/services/sqs.service'; import { TypebotController } from './integrations/typebot/controllers/typebot.controller'; -import { TypebotRepository } from './integrations/typebot/repository/typebot.repository'; import { TypebotService } from './integrations/typebot/services/typebot.service'; import { WebsocketController } from './integrations/websocket/controllers/websocket.controller'; -import { WebsocketRepository } from './integrations/websocket/repository/websocket.repository'; import { WebsocketService } from './integrations/websocket/services/websocket.service'; -import { - AuthModel, - ChatModel, - ChatwootModel, - ContactModel, - IntegrationModel, - MessageModel, - MessageUpModel, - ProxyModel, - RabbitmqModel, - SettingsModel, - SqsModel, - TypebotModel, - WebhookModel, - WebsocketModel, -} from './models'; -import { LabelModel } from './models/label.model'; import { ProviderFiles } from './provider/sessions'; -import { AuthRepository } from './repository/mongodb/auth.repository'; -import { ChatRepository } from './repository/mongodb/chat.repository'; -import { ContactRepository } from './repository/mongodb/contact.repository'; -import { IntegrationRepository } from './repository/mongodb/integration.repository'; -import { LabelRepository } from './repository/mongodb/label.repository'; -import { MessageRepository } from './repository/mongodb/message.repository'; -import { MessageUpRepository } from './repository/mongodb/messageUp.repository'; -import { ProxyRepository } from './repository/mongodb/proxy.repository'; -import { MongodbRepository } from './repository/mongodb/repository.manager'; -import { SettingsRepository } from './repository/mongodb/settings.repository'; -import { WebhookRepository } from './repository/mongodb/webhook.repository'; -import { PrismaRepository } from './repository/prisma/repository.service'; +import { PrismaRepository } from './repository/repository.service'; import { AuthService } from './services/auth.service'; import { CacheService } from './services/cache.service'; import { IntegrationService } from './services/integration.service'; @@ -67,62 +32,24 @@ import { WebhookService } from './services/webhook.service'; const logger = new Logger('WA MODULE'); -const messageRepository = new MessageRepository(MessageModel, configService); -const chatRepository = new ChatRepository(ChatModel, configService); -const contactRepository = new ContactRepository(ContactModel, configService); -const messageUpdateRepository = new MessageUpRepository(MessageUpModel, configService); -const typebotRepository = new TypebotRepository(TypebotModel, configService); -const webhookRepository = new WebhookRepository(WebhookModel, configService); -const websocketRepository = new WebsocketRepository(WebsocketModel, configService); -const proxyRepository = new ProxyRepository(ProxyModel, configService); -const rabbitmqRepository = new RabbitmqRepository(RabbitmqModel, configService); -const sqsRepository = new SqsRepository(SqsModel, configService); -const integrationRepository = new IntegrationRepository(IntegrationModel, configService); -const chatwootRepository = new ChatwootRepository(ChatwootModel, configService); -const settingsRepository = new SettingsRepository(SettingsModel, configService); -const authRepository = new AuthRepository(AuthModel, IntegrationModel, configService); -const labelRepository = new LabelRepository(LabelModel, configService); - -export const mongodbRepository = new MongodbRepository( - messageRepository, - chatRepository, - contactRepository, - messageUpdateRepository, - webhookRepository, - chatwootRepository, - settingsRepository, - websocketRepository, - rabbitmqRepository, - sqsRepository, - typebotRepository, - proxyRepository, - integrationRepository, - authRepository, - labelRepository, - configService, - mongodbServer.getClient(), - prismaServer, -); - -export const prismaRepository = new PrismaRepository(configService); - export const cache = new CacheService(new CacheEngine(configService, 'instance').getEngine()); const chatwootCache = new CacheService(new CacheEngine(configService, ChatwootService.name).getEngine()); const baileysCache = new CacheService(new CacheEngine(configService, 'baileys').getEngine()); + const providerFiles = new ProviderFiles(configService); +export const prismaRepository = new PrismaRepository(configService); export const waMonitor = new WAMonitoringService( eventEmitter, configService, - mongodbRepository, prismaRepository, + providerFiles, cache, chatwootCache, baileysCache, - providerFiles, ); -const authService = new AuthService(waMonitor, mongodbRepository, prismaRepository); +const authService = new AuthService(waMonitor, configService, prismaRepository); const typebotService = new TypebotService(waMonitor, configService, eventEmitter); export const typebotController = new TypebotController(typebotService); @@ -144,19 +71,8 @@ export const sqsController = new SqsController(sqsService); const integrationService = new IntegrationService(waMonitor); -const chatwootService = new ChatwootService( - waMonitor, - configService, - mongodbRepository, - prismaRepository, - chatwootCache, -); -export const chatwootController = new ChatwootController( - chatwootService, - configService, - mongodbRepository, - prismaRepository, -); +const chatwootService = new ChatwootService(waMonitor, configService, prismaRepository, chatwootCache); +export const chatwootController = new ChatwootController(chatwootService, configService, prismaRepository); const settingsService = new SettingsService(waMonitor); export const settingsController = new SettingsController(settingsService); @@ -164,7 +80,6 @@ export const settingsController = new SettingsController(settingsService); export const instanceController = new InstanceController( waMonitor, configService, - mongodbRepository, prismaRepository, eventEmitter, authService, diff --git a/src/api/services/auth.service.ts b/src/api/services/auth.service.ts index 40be497d..91b19242 100644 --- a/src/api/services/auth.service.ts +++ b/src/api/services/auth.service.ts @@ -1,16 +1,16 @@ import { v4 } from 'uuid'; +import { ConfigService } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { BadRequestException } from '../../exceptions'; import { InstanceDto } from '../dto/instance.dto'; -import { MongodbRepository } from '../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../repository/prisma/repository.service'; +import { PrismaRepository } from '../repository/repository.service'; import { WAMonitoringService } from './monitor.service'; export class AuthService { constructor( private readonly waMonitor: WAMonitoringService, - private readonly mongodbRepository: MongodbRepository, + private readonly configService: ConfigService, private readonly prismaRepository: PrismaRepository, ) {} @@ -21,22 +21,28 @@ export class AuthService { this.logger.verbose(token ? 'APIKEY defined: ' + apikey : 'APIKEY created: ' + apikey); - const auth = await this.mongodbRepository.auth.create( - { apikey, instanceId: instance.instanceId }, - instance.instanceName, - ); + const db = this.configService.get('DATABASE'); - this.logger.verbose('APIKEY saved in database'); + if (db.ENABLED) { + try { + await this.prismaRepository.auth.create({ + data: { + apikey: apikey, + instanceId: instance.instanceId, + }, + }); - if (auth['error']) { - this.logger.error({ - localError: AuthService.name + '.apikey', - error: auth['error'], - }); - throw new BadRequestException('Authentication error', auth['error']?.toString()); + this.logger.verbose('APIKEY saved in database'); + + return { apikey }; + } catch (error) { + this.logger.error({ + localError: AuthService.name + '.apikey', + error: error, + }); + throw new BadRequestException('Authentication error', error?.toString()); + } } - - return { apikey }; } public async checkDuplicateToken(token: string) { diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index 1560d589..963cf113 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -21,20 +21,21 @@ import { import { Logger } from '../../config/logger.config'; import { ROOT_DIR } from '../../config/path.config'; import { NotFoundException } from '../../exceptions'; -import { ChatwootRaw } from '../integrations/chatwoot/models/chatwoot.model'; +import { IntegrationDto } from '../dto/integration.dto'; +import { ProxyDto } from '../dto/proxy.dto'; +import { SettingsDto } from '../dto/settings.dto'; +import { WebhookDto } from '../dto/webhook.dto'; +import { ChatwootDto } from '../integrations/chatwoot/dto/chatwoot.dto'; import { ChatwootService } from '../integrations/chatwoot/services/chatwoot.service'; +import { RabbitmqDto } from '../integrations/rabbitmq/dto/rabbitmq.dto'; import { getAMQP, removeQueues } from '../integrations/rabbitmq/libs/amqp.server'; +import { SqsDto } from '../integrations/sqs/dto/sqs.dto'; import { getSQS, removeQueues as removeQueuesSQS } from '../integrations/sqs/libs/sqs.server'; +import { TypebotDto } from '../integrations/typebot/dto/typebot.dto'; import { TypebotService } from '../integrations/typebot/services/typebot.service'; +import { WebsocketDto } from '../integrations/websocket/dto/websocket.dto'; import { getIO } from '../integrations/websocket/libs/socket.server'; -import { WebsocketRaw } from '../integrations/websocket/models/websocket.model'; -import { IntegrationRaw, ProxyRaw, RabbitmqRaw, SettingsRaw, SqsRaw, TypebotRaw } from '../models'; -import { WebhookRaw } from '../models/webhook.model'; -import { ContactQuery } from '../repository/mongodb/contact.repository'; -import { MessageQuery } from '../repository/mongodb/message.repository'; -import { MessageUpQuery } from '../repository/mongodb/messageUp.repository'; -import { MongodbRepository } from '../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../repository/prisma/repository.service'; +import { PrismaRepository } from '../repository/repository.service'; import { waMonitor } from '../server.module'; import { Events, wa } from '../types/wa.types'; import { CacheService } from './cache.service'; @@ -43,7 +44,6 @@ export class ChannelStartupService { constructor( public readonly configService: ConfigService, public readonly eventEmitter: EventEmitter2, - public readonly mongodbRepository: MongodbRepository, public readonly prismaRepository: PrismaRepository, public readonly chatwootCache: CacheService, ) { @@ -68,7 +68,6 @@ export class ChannelStartupService { public chatwootService = new ChatwootService( waMonitor, this.configService, - this.mongodbRepository, this.prismaRepository, this.chatwootCache, ); @@ -109,6 +108,21 @@ export class ChannelStartupService { return this.instance.name; } + public set instanceId(id: string) { + if (!id) { + this.logger.verbose('Instance id not found, generating random id with uuid'); + this.instance.id = v4(); + return; + } + this.logger.verbose(`Setting instanceId: ${id}`); + this.instance.id = id; + } + + public get instanceId() { + this.logger.verbose('Getting instanceId'); + return this.instance.id; + } + public get wuid() { this.logger.verbose('Getting remoteJid of instance'); return this.instance.wuid; @@ -116,7 +130,12 @@ export class ChannelStartupService { public async loadIntegration() { this.logger.verbose('Loading webhook'); - const data = await this.mongodbRepository.integration.find(this.instanceName); + const data = await this.prismaRepository.integration.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + this.localIntegration.integration = data?.integration; this.logger.verbose(`Integration: ${this.localIntegration.integration}`); @@ -129,9 +148,26 @@ export class ChannelStartupService { this.logger.verbose('Integration loaded'); } - public async setIntegration(data: IntegrationRaw) { + public async setIntegration(data: IntegrationDto) { this.logger.verbose('Setting integration'); - await this.mongodbRepository.integration.create(data, this.instanceName); + console.log('setIntegration'); + await this.prismaRepository.integration.upsert({ + where: { + instanceId: this.instanceId, + }, + update: { + integration: data.integration, + number: data.number, + token: data.token, + }, + create: { + integration: data.integration, + number: data.number, + token: data.token, + instanceId: this.instanceId, + }, + }); + this.logger.verbose(`Integration: ${data.integration}`); this.logger.verbose(`Integration number: ${data.number}`); this.logger.verbose(`Integration token: ${data.token}`); @@ -141,15 +177,23 @@ export class ChannelStartupService { public async findIntegration() { this.logger.verbose('Finding integration'); - let data: any; + let data; - data = await this.mongodbRepository.integration.find(this.instanceName); + data = await this.prismaRepository.integration.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { - this.mongodbRepository.integration.create( - { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }, - this.instanceName, - ); + await this.prismaRepository.integration.create({ + data: { + integration: 'WHATSAPP-BAILEYS', + number: '', + token: '', + instanceId: this.instanceId, + }, + }); data = { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }; } @@ -157,84 +201,106 @@ export class ChannelStartupService { this.logger.verbose(`Integration number: ${data.number}`); this.logger.verbose(`Integration token: ${data.token}`); - return { - integration: data.integration, - number: data.number, - token: data.token, - }; + return data; } public async loadSettings() { this.logger.verbose('Loading settings'); - const data = await this.mongodbRepository.settings.find(this.instanceName); - this.localSettings.reject_call = data?.reject_call; - this.logger.verbose(`Settings reject_call: ${this.localSettings.reject_call}`); + const data = await this.prismaRepository.setting.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); - this.localSettings.msg_call = data?.msg_call; - this.logger.verbose(`Settings msg_call: ${this.localSettings.msg_call}`); + this.localSettings.rejectCall = data?.rejectCall; + this.logger.verbose(`Settings rejectCall: ${this.localSettings.rejectCall}`); - this.localSettings.groups_ignore = data?.groups_ignore; - this.logger.verbose(`Settings groups_ignore: ${this.localSettings.groups_ignore}`); + this.localSettings.msgCall = data?.msgCall; + this.logger.verbose(`Settings msgCall: ${this.localSettings.msgCall}`); - this.localSettings.always_online = data?.always_online; - this.logger.verbose(`Settings always_online: ${this.localSettings.always_online}`); + this.localSettings.groupsIgnore = data?.groupsIgnore; + this.logger.verbose(`Settings groupsIgnore: ${this.localSettings.groupsIgnore}`); - this.localSettings.read_messages = data?.read_messages; - this.logger.verbose(`Settings read_messages: ${this.localSettings.read_messages}`); + this.localSettings.alwaysOnline = data?.alwaysOnline; + this.logger.verbose(`Settings alwaysOnline: ${this.localSettings.alwaysOnline}`); - this.localSettings.read_status = data?.read_status; - this.logger.verbose(`Settings read_status: ${this.localSettings.read_status}`); + this.localSettings.readMessages = data?.readMessages; + this.logger.verbose(`Settings readMessages: ${this.localSettings.readMessages}`); - this.localSettings.sync_full_history = data?.sync_full_history; - this.logger.verbose(`Settings sync_full_history: ${this.localSettings.sync_full_history}`); + this.localSettings.readStatus = data?.readStatus; + this.logger.verbose(`Settings readStatus: ${this.localSettings.readStatus}`); + + this.localSettings.syncFullHistory = data?.syncFullHistory; + this.logger.verbose(`Settings syncFullHistory: ${this.localSettings.syncFullHistory}`); this.logger.verbose('Settings loaded'); } - public async setSettings(data: SettingsRaw) { + public async setSettings(data: SettingsDto) { this.logger.verbose('Setting settings'); - await this.mongodbRepository.settings.create(data, this.instanceName); - this.logger.verbose(`Settings reject_call: ${data.reject_call}`); - this.logger.verbose(`Settings msg_call: ${data.msg_call}`); - this.logger.verbose(`Settings groups_ignore: ${data.groups_ignore}`); - this.logger.verbose(`Settings always_online: ${data.always_online}`); - this.logger.verbose(`Settings read_messages: ${data.read_messages}`); - this.logger.verbose(`Settings read_status: ${data.read_status}`); - this.logger.verbose(`Settings sync_full_history: ${data.sync_full_history}`); + await this.prismaRepository.setting.create({ + data: { + rejectCall: data.rejectCall, + msgCall: data.msgCall, + groupsIgnore: data.groupsIgnore, + alwaysOnline: data.alwaysOnline, + readMessages: data.readMessages, + readStatus: data.readStatus, + syncFullHistory: data.syncFullHistory, + instanceId: this.instanceId, + }, + }); + + this.logger.verbose(`Settings rejectCall: ${data.rejectCall}`); + this.logger.verbose(`Settings msgCall: ${data.msgCall}`); + this.logger.verbose(`Settings groupsIgnore: ${data.groupsIgnore}`); + this.logger.verbose(`Settings alwaysOnline: ${data.alwaysOnline}`); + this.logger.verbose(`Settings readMessages: ${data.readMessages}`); + this.logger.verbose(`Settings readStatus: ${data.readStatus}`); + this.logger.verbose(`Settings syncFullHistory: ${data.syncFullHistory}`); Object.assign(this.localSettings, data); this.logger.verbose('Settings set'); } public async findSettings() { this.logger.verbose('Finding settings'); - const data = await this.mongodbRepository.settings.find(this.instanceName); + const data = await this.prismaRepository.setting.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Settings not found'); return null; } - this.logger.verbose(`Settings url: ${data.reject_call}`); - this.logger.verbose(`Settings msg_call: ${data.msg_call}`); - this.logger.verbose(`Settings groups_ignore: ${data.groups_ignore}`); - this.logger.verbose(`Settings always_online: ${data.always_online}`); - this.logger.verbose(`Settings read_messages: ${data.read_messages}`); - this.logger.verbose(`Settings read_status: ${data.read_status}`); - this.logger.verbose(`Settings sync_full_history: ${data.sync_full_history}`); + this.logger.verbose(`Settings url: ${data.rejectCall}`); + this.logger.verbose(`Settings msgCall: ${data.msgCall}`); + this.logger.verbose(`Settings groupsIgnore: ${data.groupsIgnore}`); + this.logger.verbose(`Settings alwaysOnline: ${data.alwaysOnline}`); + this.logger.verbose(`Settings readMessages: ${data.readMessages}`); + this.logger.verbose(`Settings readStatus: ${data.readStatus}`); + this.logger.verbose(`Settings syncFullHistory: ${data.syncFullHistory}`); return { - reject_call: data.reject_call, - msg_call: data.msg_call, - groups_ignore: data.groups_ignore, - always_online: data.always_online, - read_messages: data.read_messages, - read_status: data.read_status, - sync_full_history: data.sync_full_history, + rejectCall: data.rejectCall, + msgCall: data.msgCall, + groupsIgnore: data.groupsIgnore, + alwaysOnline: data.alwaysOnline, + readMessages: data.readMessages, + readStatus: data.readStatus, + syncFullHistory: data.syncFullHistory, }; } public async loadWebhook() { this.logger.verbose('Loading webhook'); - const data = await this.mongodbRepository.webhook.find(this.instanceName); + const data = await this.prismaRepository.webhook.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + this.localWebhook.url = data?.url; this.logger.verbose(`Webhook url: ${this.localWebhook.url}`); @@ -244,18 +310,28 @@ export class ChannelStartupService { this.localWebhook.events = data?.events; this.logger.verbose(`Webhook events: ${this.localWebhook.events}`); - this.localWebhook.webhook_by_events = data?.webhook_by_events; - this.logger.verbose(`Webhook by events: ${this.localWebhook.webhook_by_events}`); + this.localWebhook.webhookByEvents = data?.webhookByEvents; + this.logger.verbose(`Webhook by events: ${this.localWebhook.webhookByEvents}`); - this.localWebhook.webhook_base64 = data?.webhook_base64; - this.logger.verbose(`Webhook by webhook_base64: ${this.localWebhook.webhook_base64}`); + this.localWebhook.webhookBase64 = data?.webhookBase64; + this.logger.verbose(`Webhook by webhookBase64: ${this.localWebhook.webhookBase64}`); this.logger.verbose('Webhook loaded'); } - public async setWebhook(data: WebhookRaw) { + public async setWebhook(data: WebhookDto) { this.logger.verbose('Setting webhook'); - await this.mongodbRepository.webhook.create(data, this.instanceName); + await this.prismaRepository.webhook.create({ + data: { + url: data.url, + enabled: data.enabled, + events: data.events, + webhookByEvents: data.webhookByEvents, + webhookBase64: data.webhookBase64, + instanceId: this.instanceId, + }, + }); + this.logger.verbose(`Webhook url: ${data.url}`); this.logger.verbose(`Webhook events: ${data.events}`); Object.assign(this.localWebhook, data); @@ -264,7 +340,11 @@ export class ChannelStartupService { public async findWebhook() { this.logger.verbose('Finding webhook'); - const data = await this.mongodbRepository.webhook.find(this.instanceName); + const data = await this.prismaRepository.webhook.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Webhook not found'); @@ -274,23 +354,22 @@ export class ChannelStartupService { this.logger.verbose(`Webhook url: ${data.url}`); this.logger.verbose(`Webhook events: ${data.events}`); - return { - enabled: data.enabled, - url: data.url, - events: data.events, - webhook_by_events: data.webhook_by_events, - webhook_base64: data.webhook_base64, - }; + return data; } public async loadChatwoot() { this.logger.verbose('Loading chatwoot'); - const data = await this.mongodbRepository.chatwoot.find(this.instanceName); + const data = await this.prismaRepository.chatwoot.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); + this.localChatwoot.enabled = data?.enabled; this.logger.verbose(`Chatwoot enabled: ${this.localChatwoot.enabled}`); - this.localChatwoot.account_id = data?.account_id; - this.logger.verbose(`Chatwoot account id: ${this.localChatwoot.account_id}`); + this.localChatwoot.accountId = data?.accountId; + this.logger.verbose(`Chatwoot account id: ${this.localChatwoot.accountId}`); this.localChatwoot.token = data?.token; this.logger.verbose(`Chatwoot token: ${this.localChatwoot.token}`); @@ -298,53 +377,74 @@ export class ChannelStartupService { this.localChatwoot.url = data?.url; this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`); - this.localChatwoot.name_inbox = data?.name_inbox; - this.logger.verbose(`Chatwoot inbox name: ${this.localChatwoot.name_inbox}`); + this.localChatwoot.nameInbox = data?.nameInbox; + this.logger.verbose(`Chatwoot inbox name: ${this.localChatwoot.nameInbox}`); - this.localChatwoot.sign_msg = data?.sign_msg; - this.logger.verbose(`Chatwoot sign msg: ${this.localChatwoot.sign_msg}`); + this.localChatwoot.signMsg = data?.signMsg; + this.logger.verbose(`Chatwoot sign msg: ${this.localChatwoot.signMsg}`); + + this.localChatwoot.signDelimiter = data?.signDelimiter; + this.logger.verbose(`Chatwoot sign delimiter: ${this.localChatwoot.signDelimiter}`); this.localChatwoot.number = data?.number; this.logger.verbose(`Chatwoot number: ${this.localChatwoot.number}`); - this.localChatwoot.reopen_conversation = data?.reopen_conversation; - this.logger.verbose(`Chatwoot reopen conversation: ${this.localChatwoot.reopen_conversation}`); + this.localChatwoot.reopenConversation = data?.reopenConversation; + this.logger.verbose(`Chatwoot reopen conversation: ${this.localChatwoot.reopenConversation}`); - this.localChatwoot.conversation_pending = data?.conversation_pending; - this.logger.verbose(`Chatwoot conversation pending: ${this.localChatwoot.conversation_pending}`); + this.localChatwoot.conversationPending = data?.conversationPending; + this.logger.verbose(`Chatwoot conversation pending: ${this.localChatwoot.conversationPending}`); - this.localChatwoot.merge_brazil_contacts = data?.merge_brazil_contacts; - this.logger.verbose(`Chatwoot merge brazil contacts: ${this.localChatwoot.merge_brazil_contacts}`); + this.localChatwoot.mergeBrazilContacts = data?.mergeBrazilContacts; + this.logger.verbose(`Chatwoot merge brazil contacts: ${this.localChatwoot.mergeBrazilContacts}`); - this.localChatwoot.import_contacts = data?.import_contacts; - this.logger.verbose(`Chatwoot import contacts: ${this.localChatwoot.import_contacts}`); + this.localChatwoot.importContacts = data?.importContacts; + this.logger.verbose(`Chatwoot import contacts: ${this.localChatwoot.importContacts}`); - this.localChatwoot.import_messages = data?.import_messages; - this.logger.verbose(`Chatwoot import messages: ${this.localChatwoot.import_messages}`); + this.localChatwoot.importMessages = data?.importMessages; + this.logger.verbose(`Chatwoot import messages: ${this.localChatwoot.importMessages}`); - this.localChatwoot.days_limit_import_messages = data?.days_limit_import_messages; - this.logger.verbose(`Chatwoot days limit import messages: ${this.localChatwoot.days_limit_import_messages}`); + this.localChatwoot.daysLimitImportMessages = data?.daysLimitImportMessages; + this.logger.verbose(`Chatwoot days limit import messages: ${this.localChatwoot.daysLimitImportMessages}`); this.logger.verbose('Chatwoot loaded'); } - public async setChatwoot(data: ChatwootRaw) { + public async setChatwoot(data: ChatwootDto) { this.logger.verbose('Setting chatwoot'); - await this.mongodbRepository.chatwoot.create(data, this.instanceName); - this.logger.verbose(`Chatwoot account id: ${data.account_id}`); + await this.prismaRepository.chatwoot.create({ + data: { + enabled: data.enabled, + accountId: data.accountId, + token: data.token, + url: data.url, + nameInbox: data.nameInbox, + signMsg: data.signMsg, + number: data.number, + reopenConversation: data.reopenConversation, + conversationPending: data.conversationPending, + mergeBrazilContacts: data.mergeBrazilContacts, + importContacts: data.importContacts, + importMessages: data.importMessages, + daysLimitImportMessages: data.daysLimitImportMessages, + instanceId: this.instanceId, + }, + }); + + this.logger.verbose(`Chatwoot account id: ${data.accountId}`); this.logger.verbose(`Chatwoot token: ${data.token}`); this.logger.verbose(`Chatwoot url: ${data.url}`); - this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); - this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`); - this.logger.verbose(`Chatwoot sign delimiter: ${data.sign_delimiter}`); - this.logger.verbose(`Chatwoot reopen conversation: ${data.reopen_conversation}`); - this.logger.verbose(`Chatwoot conversation pending: ${data.conversation_pending}`); - this.logger.verbose(`Chatwoot merge brazil contacts: ${data.merge_brazil_contacts}`); - this.logger.verbose(`Chatwoot import contacts: ${data.import_contacts}`); - this.logger.verbose(`Chatwoot import messages: ${data.import_messages}`); - this.logger.verbose(`Chatwoot days limit import messages: ${data.days_limit_import_messages}`); + this.logger.verbose(`Chatwoot inbox name: ${data.nameInbox}`); + this.logger.verbose(`Chatwoot sign msg: ${data.signMsg}`); + this.logger.verbose(`Chatwoot sign delimiter: ${data.signDelimiter}`); + this.logger.verbose(`Chatwoot reopen conversation: ${data.reopenConversation}`); + this.logger.verbose(`Chatwoot conversation pending: ${data.conversationPending}`); + this.logger.verbose(`Chatwoot merge brazil contacts: ${data.mergeBrazilContacts}`); + this.logger.verbose(`Chatwoot import contacts: ${data.importContacts}`); + this.logger.verbose(`Chatwoot import messages: ${data.importMessages}`); + this.logger.verbose(`Chatwoot days limit import messages: ${data.daysLimitImportMessages}`); - Object.assign(this.localChatwoot, { ...data, sign_delimiter: data.sign_msg ? data.sign_delimiter : null }); + Object.assign(this.localChatwoot, { ...data, signDelimiter: data.signMsg ? data.signDelimiter : null }); this.clearCacheChatwoot(); @@ -353,40 +453,44 @@ export class ChannelStartupService { public async findChatwoot() { this.logger.verbose('Finding chatwoot'); - const data = await this.mongodbRepository.chatwoot.find(this.instanceName); + const data = await this.prismaRepository.chatwoot.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Chatwoot not found'); return null; } - this.logger.verbose(`Chatwoot account id: ${data.account_id}`); + this.logger.verbose(`Chatwoot account id: ${data.accountId}`); this.logger.verbose(`Chatwoot token: ${data.token}`); this.logger.verbose(`Chatwoot url: ${data.url}`); - this.logger.verbose(`Chatwoot inbox name: ${data.name_inbox}`); - this.logger.verbose(`Chatwoot sign msg: ${data.sign_msg}`); - this.logger.verbose(`Chatwoot sign delimiter: ${data.sign_delimiter}`); - this.logger.verbose(`Chatwoot reopen conversation: ${data.reopen_conversation}`); - this.logger.verbose(`Chatwoot conversation pending: ${data.conversation_pending}`); - this.logger.verbose(`Chatwoot merge brazilian contacts: ${data.merge_brazil_contacts}`); - this.logger.verbose(`Chatwoot import contacts: ${data.import_contacts}`); - this.logger.verbose(`Chatwoot import messages: ${data.import_messages}`); - this.logger.verbose(`Chatwoot days limit import messages: ${data.days_limit_import_messages}`); + this.logger.verbose(`Chatwoot inbox name: ${data.nameInbox}`); + this.logger.verbose(`Chatwoot sign msg: ${data.signMsg}`); + this.logger.verbose(`Chatwoot sign delimiter: ${data.signDelimiter}`); + this.logger.verbose(`Chatwoot reopen conversation: ${data.reopenConversation}`); + this.logger.verbose(`Chatwoot conversation pending: ${data.conversationPending}`); + this.logger.verbose(`Chatwoot merge brazilian contacts: ${data.mergeBrazilContacts}`); + this.logger.verbose(`Chatwoot import contacts: ${data.importContacts}`); + this.logger.verbose(`Chatwoot import messages: ${data.importMessages}`); + this.logger.verbose(`Chatwoot days limit import messages: ${data.daysLimitImportMessages}`); return { enabled: data.enabled, - account_id: data.account_id, + accountId: data.accountId, token: data.token, url: data.url, - name_inbox: data.name_inbox, - sign_msg: data.sign_msg, - sign_delimiter: data.sign_delimiter || null, - reopen_conversation: data.reopen_conversation, - conversation_pending: data.conversation_pending, - merge_brazil_contacts: data.merge_brazil_contacts, - import_contacts: data.import_contacts, - import_messages: data.import_messages, - days_limit_import_messages: data.days_limit_import_messages, + nameInbox: data.nameInbox, + signMsg: data.signMsg, + signDelimiter: data.signDelimiter || null, + reopenConversation: data.reopenConversation, + conversationPending: data.conversationPending, + mergeBrazilContacts: data.mergeBrazilContacts, + importContacts: data.importContacts, + importMessages: data.importMessages, + daysLimitImportMessages: data.daysLimitImportMessages, }; } @@ -400,7 +504,11 @@ export class ChannelStartupService { public async loadWebsocket() { this.logger.verbose('Loading websocket'); - const data = await this.mongodbRepository.websocket.find(this.instanceName); + const data = await this.prismaRepository.websocket.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); this.localWebsocket.enabled = data?.enabled; this.logger.verbose(`Websocket enabled: ${this.localWebsocket.enabled}`); @@ -411,9 +519,16 @@ export class ChannelStartupService { this.logger.verbose('Websocket loaded'); } - public async setWebsocket(data: WebsocketRaw) { + public async setWebsocket(data: WebsocketDto) { this.logger.verbose('Setting websocket'); - await this.mongodbRepository.websocket.create(data, this.instanceName); + await this.prismaRepository.websocket.create({ + data: { + enabled: data.enabled, + events: data.events, + instanceId: this.instanceId, + }, + }); + this.logger.verbose(`Websocket events: ${data.events}`); Object.assign(this.localWebsocket, data); this.logger.verbose('Websocket set'); @@ -421,7 +536,11 @@ export class ChannelStartupService { public async findWebsocket() { this.logger.verbose('Finding websocket'); - const data = await this.mongodbRepository.websocket.find(this.instanceName); + const data = await this.prismaRepository.websocket.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Websocket not found'); @@ -429,15 +548,16 @@ export class ChannelStartupService { } this.logger.verbose(`Websocket events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; + return data; } public async loadRabbitmq() { this.logger.verbose('Loading rabbitmq'); - const data = await this.mongodbRepository.rabbitmq.find(this.instanceName); + const data = await this.prismaRepository.rabbitmq.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); this.localRabbitmq.enabled = data?.enabled; this.logger.verbose(`Rabbitmq enabled: ${this.localRabbitmq.enabled}`); @@ -448,9 +568,16 @@ export class ChannelStartupService { this.logger.verbose('Rabbitmq loaded'); } - public async setRabbitmq(data: RabbitmqRaw) { + public async setRabbitmq(data: RabbitmqDto) { this.logger.verbose('Setting rabbitmq'); - await this.mongodbRepository.rabbitmq.create(data, this.instanceName); + await this.prismaRepository.rabbitmq.create({ + data: { + enabled: data.enabled, + events: data.events, + instanceId: this.instanceId, + }, + }); + this.logger.verbose(`Rabbitmq events: ${data.events}`); Object.assign(this.localRabbitmq, data); this.logger.verbose('Rabbitmq set'); @@ -458,7 +585,11 @@ export class ChannelStartupService { public async findRabbitmq() { this.logger.verbose('Finding rabbitmq'); - const data = await this.mongodbRepository.rabbitmq.find(this.instanceName); + const data = await this.prismaRepository.rabbitmq.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Rabbitmq not found'); @@ -466,10 +597,7 @@ export class ChannelStartupService { } this.logger.verbose(`Rabbitmq events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; + return data; } public async removeRabbitmqQueues() { @@ -482,7 +610,11 @@ export class ChannelStartupService { public async loadSqs() { this.logger.verbose('Loading sqs'); - const data = await this.mongodbRepository.sqs.find(this.instanceName); + const data = await this.prismaRepository.sqs.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); this.localSqs.enabled = data?.enabled; this.logger.verbose(`Sqs enabled: ${this.localSqs.enabled}`); @@ -493,9 +625,16 @@ export class ChannelStartupService { this.logger.verbose('Sqs loaded'); } - public async setSqs(data: SqsRaw) { + public async setSqs(data: SqsDto) { this.logger.verbose('Setting sqs'); - await this.mongodbRepository.sqs.create(data, this.instanceName); + await this.prismaRepository.sqs.create({ + data: { + enabled: data.enabled, + events: data.events, + instanceId: this.instanceId, + }, + }); + this.logger.verbose(`Sqs events: ${data.events}`); Object.assign(this.localSqs, data); this.logger.verbose('Sqs set'); @@ -503,7 +642,11 @@ export class ChannelStartupService { public async findSqs() { this.logger.verbose('Finding sqs'); - const data = await this.mongodbRepository.sqs.find(this.instanceName); + const data = await this.prismaRepository.sqs.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Sqs not found'); @@ -511,10 +654,7 @@ export class ChannelStartupService { } this.logger.verbose(`Sqs events: ${data.events}`); - return { - enabled: data.enabled, - events: data.events, - }; + return data; } public async removeSqsQueues() { @@ -527,7 +667,14 @@ export class ChannelStartupService { public async loadTypebot() { this.logger.verbose('Loading typebot'); - const data = await this.mongodbRepository.typebot.find(this.instanceName); + const data = await this.prismaRepository.typebot.findUnique({ + where: { + instanceId: this.instanceId, + }, + include: { + sessions: true, + }, + }); this.localTypebot.enabled = data?.enabled; this.logger.verbose(`Typebot enabled: ${this.localTypebot.enabled}`); @@ -541,39 +688,66 @@ export class ChannelStartupService { this.localTypebot.expire = data?.expire; this.logger.verbose(`Typebot expire: ${this.localTypebot.expire}`); - this.localTypebot.keyword_finish = data?.keyword_finish; - this.logger.verbose(`Typebot keyword_finish: ${this.localTypebot.keyword_finish}`); + this.localTypebot.keywordFinish = data?.keywordFinish; + this.logger.verbose(`Typebot keywordFinish: ${this.localTypebot.keywordFinish}`); - this.localTypebot.delay_message = data?.delay_message; - this.logger.verbose(`Typebot delay_message: ${this.localTypebot.delay_message}`); + this.localTypebot.delayMessage = data?.delayMessage; + this.logger.verbose(`Typebot delayMessage: ${this.localTypebot.delayMessage}`); - this.localTypebot.unknown_message = data?.unknown_message; - this.logger.verbose(`Typebot unknown_message: ${this.localTypebot.unknown_message}`); + this.localTypebot.unknownMessage = data?.unknownMessage; + this.logger.verbose(`Typebot unknownMessage: ${this.localTypebot.unknownMessage}`); - this.localTypebot.listening_from_me = data?.listening_from_me; - this.logger.verbose(`Typebot listening_from_me: ${this.localTypebot.listening_from_me}`); + this.localTypebot.listeningFromMe = data?.listeningFromMe; + this.logger.verbose(`Typebot listeningFromMe: ${this.localTypebot.listeningFromMe}`); this.localTypebot.sessions = data?.sessions; this.logger.verbose('Typebot loaded'); } - public async setTypebot(data: TypebotRaw) { + public async setTypebot(data: TypebotDto) { this.logger.verbose('Setting typebot'); - await this.mongodbRepository.typebot.create(data, this.instanceName); + + const typebot = await this.prismaRepository.typebot.create({ + data: { + enabled: data.enabled, + url: data.url, + typebot: data.typebot, + expire: data.expire, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, + instanceId: this.instanceId, + }, + }); + + await this.prismaRepository.typebotSession.deleteMany({ + where: { + typebotId: typebot.id, + }, + }); + this.logger.verbose(`Typebot typebot: ${data.typebot}`); this.logger.verbose(`Typebot expire: ${data.expire}`); - this.logger.verbose(`Typebot keyword_finish: ${data.keyword_finish}`); - this.logger.verbose(`Typebot delay_message: ${data.delay_message}`); - this.logger.verbose(`Typebot unknown_message: ${data.unknown_message}`); - this.logger.verbose(`Typebot listening_from_me: ${data.listening_from_me}`); + this.logger.verbose(`Typebot keywordFinish: ${data.keywordFinish}`); + this.logger.verbose(`Typebot delayMessage: ${data.delayMessage}`); + this.logger.verbose(`Typebot unknownMessage: ${data.unknownMessage}`); + this.logger.verbose(`Typebot listeningFromMe: ${data.listeningFromMe}`); Object.assign(this.localTypebot, data); this.logger.verbose('Typebot set'); } public async findTypebot() { this.logger.verbose('Finding typebot'); - const data = await this.mongodbRepository.typebot.find(this.instanceName); + const data = await this.prismaRepository.typebot.findUnique({ + where: { + instanceId: this.instanceId, + }, + include: { + sessions: true, + }, + }); if (!data) { this.logger.verbose('Typebot not found'); @@ -585,48 +759,69 @@ export class ChannelStartupService { url: data.url, typebot: data.typebot, expire: data.expire, - keyword_finish: data.keyword_finish, - delay_message: data.delay_message, - unknown_message: data.unknown_message, - listening_from_me: data.listening_from_me, + keywordFinish: data.keywordFinish, + delayMessage: data.delayMessage, + unknownMessage: data.unknownMessage, + listeningFromMe: data.listeningFromMe, sessions: data.sessions, }; } public async loadProxy() { this.logger.verbose('Loading proxy'); - const data = await this.mongodbRepository.proxy.find(this.instanceName); + const data = await this.prismaRepository.proxy.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); this.localProxy.enabled = data?.enabled; this.logger.verbose(`Proxy enabled: ${this.localProxy.enabled}`); - this.localProxy.proxy = data?.proxy; + this.localProxy.proxy = { + host: data?.host, + port: `${data?.port}`, + username: data?.username, + password: data?.password, + }; + this.logger.verbose(`Proxy proxy: ${this.localProxy.proxy?.host}`); this.logger.verbose('Proxy loaded'); } - public async setProxy(data: ProxyRaw) { + public async setProxy(data: ProxyDto) { this.logger.verbose('Setting proxy'); - await this.mongodbRepository.proxy.create(data, this.instanceName); - this.logger.verbose(`Proxy proxy: ${data.proxy}`); + await this.prismaRepository.proxy.create({ + data: { + enabled: data.enabled, + host: data.host, + port: data.port, + username: data.username, + password: data.password, + instanceId: this.instanceId, + }, + }); + + this.logger.verbose(`Proxy proxy: ${data.host}`); Object.assign(this.localProxy, data); this.logger.verbose('Proxy set'); } public async findProxy() { this.logger.verbose('Finding proxy'); - const data = await this.mongodbRepository.proxy.find(this.instanceName); + const data = await this.prismaRepository.proxy.findUnique({ + where: { + instanceId: this.instanceId, + }, + }); if (!data) { this.logger.verbose('Proxy not found'); throw new NotFoundException('Proxy not found'); } - return { - enabled: data.enabled, - proxy: data.proxy, - }; + return data; } public async sendDataWebhook(event: Events, data: T, local = true) { @@ -646,7 +841,11 @@ export class ChannelStartupService { const now = localISOTime; const expose = this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES; - const tokenStore = await this.mongodbRepository.auth.find(this.instanceName); + const tokenStore = await this.prismaRepository.auth.findFirst({ + where: { + instanceId: this.instanceId, + }, + }); const instanceApikey = tokenStore?.apikey || 'Apikey not found'; if (rabbitmqEnabled) { @@ -930,7 +1129,7 @@ export class ChannelStartupService { this.logger.verbose('Sending data to webhook local'); let baseURL: string; - if (this.localWebhook.webhook_by_events) { + if (this.localWebhook.webhookByEvents) { baseURL = `${this.localWebhook.url}/${transformedWe}`; } else { baseURL = this.localWebhook.url; @@ -1167,61 +1366,63 @@ export class ChannelStartupService { return `${number}@s.whatsapp.net`; } - public async fetchContacts(query: ContactQuery) { + public async fetchContacts(query: any) { this.logger.verbose('Fetching contacts'); if (query?.where) { - query.where.owner = this.instance.name; - if (query.where?.id) { - query.where.id = this.createJid(query.where.id); + query.where.remoteJid = this.instance.name; + if (query.where?.remoteJid) { + query.where.remoteJid = this.createJid(query.where.remoteJid); } } else { query = { where: { - owner: this.instance.name, + instanceId: this.instanceId, }, }; } - return await this.mongodbRepository.contact.find(query); + return await this.prismaRepository.contact.findMany({ + where: query.where, + }); } - public async fetchMessages(query: MessageQuery) { + public async fetchMessages(query: any) { this.logger.verbose('Fetching messages'); if (query?.where) { if (query.where?.key?.remoteJid) { query.where.key.remoteJid = this.createJid(query.where.key.remoteJid); } - query.where.owner = this.instance.name; + query.where.instanceId = this.instanceId; } else { query = { where: { - owner: this.instance.name, + instanceId: this.instanceId, }, limit: query?.limit, }; } - return await this.mongodbRepository.message.find(query); + return await this.prismaRepository.message.findMany(query); } - public async fetchStatusMessage(query: MessageUpQuery) { + public async fetchStatusMessage(query: any) { this.logger.verbose('Fetching status messages'); if (query?.where) { if (query.where?.remoteJid) { query.where.remoteJid = this.createJid(query.where.remoteJid); } - query.where.owner = this.instance.name; + query.where.instanceId = this.instanceId; } else { query = { where: { - owner: this.instance.name, + instanceId: this.instanceId, }, limit: query?.limit, }; } - return await this.mongodbRepository.messageUpdate.find(query); + return await this.prismaRepository.messageUpdate.findMany(query); } public async fetchChats() { this.logger.verbose('Fetching chats'); - return await this.mongodbRepository.chat.find({ where: { owner: this.instance.name } }); + return await this.prismaRepository.chat.findMany({ where: { instanceId: this.instanceId } }); } } diff --git a/src/api/services/channels/whatsapp.baileys.service.ts b/src/api/services/channels/whatsapp.baileys.service.ts index 6d83acf9..e584285e 100644 --- a/src/api/services/channels/whatsapp.baileys.service.ts +++ b/src/api/services/channels/whatsapp.baileys.service.ts @@ -68,9 +68,7 @@ import { } from '../../../config/env.config'; import { INSTANCE_DIR } from '../../../config/path.config'; import { BadRequestException, InternalServerErrorException, NotFoundException } from '../../../exceptions'; -import { mongodbServer } from '../../../libs/mongodb.connect'; import { makeProxyAgent } from '../../../utils/makeProxyAgent'; -import { useMultiFileAuthStateMongoDb } from '../../../utils/use-multi-file-auth-state-mongodb'; import useMultiFileAuthStatePrisma from '../../../utils/use-multi-file-auth-state-prisma'; import { AuthStateProvider } from '../../../utils/use-multi-file-auth-state-provider-files'; import { useMultiFileAuthStateRedisDb } from '../../../utils/use-multi-file-auth-state-redis-db'; @@ -122,13 +120,8 @@ import { StatusMessage, } from '../../dto/sendMessage.dto'; import { chatwootImport } from '../../integrations/chatwoot/utils/chatwoot-import-helper'; -import { SettingsRaw } from '../../models'; -import { ChatRaw } from '../../models/chat.model'; -import { ContactRaw } from '../../models/contact.model'; -import { MessageRaw, MessageUpdateRaw } from '../../models/message.model'; import { ProviderFiles } from '../../provider/sessions'; -import { MongodbRepository } from '../../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../../repository/prisma/repository.service'; +import { PrismaRepository } from '../../repository/repository.service'; import { waMonitor } from '../../server.module'; import { Events, MessageSubtype, TypeMediaMessage, wa } from '../../types/wa.types'; import { CacheService } from './../cache.service'; @@ -140,20 +133,19 @@ export class BaileysStartupService extends ChannelStartupService { constructor( public readonly configService: ConfigService, public readonly eventEmitter: EventEmitter2, - public readonly mongoRepository: MongodbRepository, public readonly prismaRepository: PrismaRepository, public readonly cache: CacheService, public readonly chatwootCache: CacheService, public readonly baileysCache: CacheService, private readonly providerFiles: ProviderFiles, ) { - super(configService, eventEmitter, mongoRepository, prismaRepository, chatwootCache); + super(configService, eventEmitter, prismaRepository, chatwootCache); this.logger.verbose('BaileysStartupService initialized'); this.cleanStore(); this.instance.qrcode = { count: 0 }; this.mobile = false; this.recoveringMessages(); - this.forceUpdateGroupMetadataCache(); + this.cronForceUpdateGroupMetadataCache(); this.authStateProvider = new AuthStateProvider(this.providerFiles); } @@ -189,23 +181,29 @@ export class BaileysStartupService extends ChannelStartupService { } } - private async forceUpdateGroupMetadataCache() { + private async cronForceUpdateGroupMetadataCache() { if ( !this.configService.get('CACHE').REDIS.ENABLED && !this.configService.get('CACHE').LOCAL.ENABLED ) return; - setInterval(async () => { - this.logger.verbose('Forcing update group metadata cache'); - const groups = await this.fetchAllGroups({ getParticipants: 'false' }); + await this.forceUpdateGroupMetadataCache(); - for (const group of groups) { - await this.updateGroupMetadataCache(group.id); - } + setInterval(async () => { + await this.forceUpdateGroupMetadataCache(); }, 3600000); } + private async forceUpdateGroupMetadataCache() { + this.logger.verbose('Forcing update group metadata cache'); + const groups = await this.fetchAllGroups({ getParticipants: 'false' }); + + for (const group of groups) { + await this.updateGroupMetadataCache(group.id); + } + } + public get connectionStatus() { this.logger.verbose('Getting connection status'); return this.stateConnection; @@ -227,14 +225,14 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('Profile name not found, trying to get from database'); if (this.configService.get('DATABASE').ENABLED) { this.logger.verbose('Database enabled, trying to get from database'); - const collection = mongodbServer - .getClient() - .db(this.configService.get('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(this.instanceName); - const data = await collection.findOne({ _id: 'creds' }); + + const data = await this.prismaRepository.session.findUnique({ + where: { sessionId: this.instanceId }, + }); + if (data) { this.logger.verbose('Profile name found in database'); - const creds = JSON.parse(JSON.stringify(data), BufferJSON.reviver); + const creds = JSON.parse(JSON.stringify(data.creds), BufferJSON.reviver); profileName = creds.me?.name || creds.me?.verifiedName; } } else if (existsSync(join(INSTANCE_DIR, this.instanceName, 'creds.json'))) { @@ -460,11 +458,18 @@ export class BaileysStartupService extends ChannelStartupService { } } + // TODO: Refactor this method for prisma private async getMessage(key: proto.IMessageKey, full = false) { this.logger.verbose('Getting message with key: ' + JSON.stringify(key)); try { - const webMessageInfo = (await this.mongodbRepository.message.find({ - where: { owner: this.instance.name, key: { id: key.id } }, + const webMessageInfo = (await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, })) as unknown as proto.IWebMessageInfo[]; if (full) { this.logger.verbose('Returning full message'); @@ -513,8 +518,7 @@ export class BaileysStartupService extends ChannelStartupService { if (db.SAVE_DATA.INSTANCE && db.ENABLED) { this.logger.verbose('Database enabled'); - if (db.PROVIDER === 'mongodb') return await useMultiFileAuthStateMongoDb(this.instance.name); - else return await useMultiFileAuthStatePrisma(this.instance.name); + return await useMultiFileAuthStatePrisma(this.instanceId); } this.logger.verbose('Store file enabled'); @@ -597,22 +601,22 @@ export class BaileysStartupService extends ChannelStartupService { mobile, browser: number ? ['Chrome (Linux)', session.NAME, release()] : browser, version, - markOnlineOnConnect: this.localSettings.always_online, + markOnlineOnConnect: this.localSettings.alwaysOnline, retryRequestDelayMs: 10, connectTimeoutMs: 60_000, qrTimeout: 40_000, defaultQueryTimeoutMs: undefined, emitOwnEvents: false, shouldIgnoreJid: (jid) => { - const isGroupJid = this.localSettings.groups_ignore && isJidGroup(jid); - const isBroadcast = !this.localSettings.read_status && isJidBroadcast(jid); + const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid); + const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid); return isGroupJid || isBroadcast; }, msgRetryCounterCache: this.msgRetryCounterCache, getMessage: async (key) => (await this.getMessage(key)) as Promise, generateHighQualityLinkPreview: true, - syncFullHistory: this.localSettings.sync_full_history, + syncFullHistory: this.localSettings.syncFullHistory, shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { return this.historySyncNotification(msg); }, @@ -775,22 +779,22 @@ export class BaileysStartupService extends ChannelStartupService { printQRInTerminal: false, browser: this.phoneNumber ? ['Chrome (Linux)', session.NAME, release()] : browser, version, - markOnlineOnConnect: this.localSettings.always_online, + markOnlineOnConnect: this.localSettings.alwaysOnline, retryRequestDelayMs: 10, connectTimeoutMs: 60_000, qrTimeout: 40_000, defaultQueryTimeoutMs: undefined, emitOwnEvents: false, shouldIgnoreJid: (jid) => { - const isGroupJid = this.localSettings.groups_ignore && isJidGroup(jid); - const isBroadcast = !this.localSettings.read_status && isJidBroadcast(jid); + const isGroupJid = this.localSettings.groupsIgnore && isJidGroup(jid); + const isBroadcast = !this.localSettings.readStatus && isJidBroadcast(jid); return isGroupJid || isBroadcast; }, msgRetryCounterCache: this.msgRetryCounterCache, getMessage: async (key) => (await this.getMessage(key)) as Promise, generateHighQualityLinkPreview: true, - syncFullHistory: this.localSettings.sync_full_history, + syncFullHistory: this.localSettings.syncFullHistory, shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => { return this.historySyncNotification(msg); }, @@ -826,29 +830,31 @@ export class BaileysStartupService extends ChannelStartupService { } private readonly chatHandle = { - 'chats.upsert': async (chats: Chat[], database: Database) => { + 'chats.upsert': async (chats: Chat[]) => { this.logger.verbose('Event received: chats.upsert'); - this.logger.verbose('Finding chats in database'); - const chatsRepository = await this.mongodbRepository.chat.find({ - where: { owner: this.instance.name }, + this.logger.verbose('Finding existing chat IDs in the database'); + const existingChatIds = await this.prismaRepository.chat.findMany({ + where: { instanceId: this.instanceId }, + select: { remoteJid: true }, }); - this.logger.verbose('Verifying if chats exists in database to insert'); - const chatsRaw: ChatRaw[] = []; - for await (const chat of chats) { - if (chatsRepository.find((cr) => cr.id === chat.id)) { - continue; - } + const existingChatIdSet = new Set(existingChatIds.map((chat) => chat.remoteJid)); - chatsRaw.push({ id: chat.id, owner: this.instance.wuid }); - } + this.logger.verbose('Verifying if chats exist in the database to insert'); + const chatsToInsert = chats + .filter((chat) => !existingChatIdSet.has(chat.id)) + .map((chat) => ({ remoteJid: chat.id, instanceId: this.instanceId })); this.logger.verbose('Sending data to webhook in event CHATS_UPSERT'); - this.sendDataWebhook(Events.CHATS_UPSERT, chatsRaw); + this.sendDataWebhook(Events.CHATS_UPSERT, chatsToInsert); - this.logger.verbose('Inserting chats in database'); - this.mongodbRepository.chat.insert(chatsRaw, this.instance.name, database.SAVE_DATA.CHATS); + if (chatsToInsert.length > 0) { + this.logger.verbose('Inserting new chats in the database'); + await this.prismaRepository.chat.createMany({ + data: chatsToInsert, + }); + } }, 'chats.update': async ( @@ -861,12 +867,26 @@ export class BaileysStartupService extends ChannelStartupService { >[], ) => { this.logger.verbose('Event received: chats.update'); - const chatsRaw: ChatRaw[] = chats.map((chat) => { - return { id: chat.id, owner: this.instance.wuid }; + const chatsRaw = chats.map((chat) => { + return { remoteJid: chat.id, instanceId: this.instanceId }; }); this.logger.verbose('Sending data to webhook in event CHATS_UPDATE'); this.sendDataWebhook(Events.CHATS_UPDATE, chatsRaw); + + this.logger.verbose('Updating chats in the database'); + + for (const chat of chats) { + await this.prismaRepository.chat.updateMany({ + where: { + instanceId: this.instanceId, + remoteJid: chat.id, + }, + data: { + lastMsgTimestamp: Long.fromValue(chat.lastMessageRecvTimestamp).toString(), + }, + }); + } }, 'chats.delete': async (chats: string[]) => { @@ -875,8 +895,8 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('Deleting chats in database'); chats.forEach( async (chat) => - await this.mongodbRepository.chat.delete({ - where: { owner: this.instance.name, id: chat }, + await this.prismaRepository.chat.deleteMany({ + where: { instanceId: this.instanceId, remoteJid: chat }, }), ); @@ -886,79 +906,75 @@ export class BaileysStartupService extends ChannelStartupService { }; private readonly contactHandle = { - 'contacts.upsert': async (contacts: Contact[], database: Database) => { + 'contacts.upsert': async (contacts: Contact[]) => { try { this.logger.verbose('Event received: contacts.upsert'); - this.logger.verbose('Finding contacts in database'); - const contactsRepository = new Set( - ( - await this.mongodbRepository.contact.find({ - select: { id: 1, _id: 0 }, - where: { owner: this.instance.name }, - }) - ).map((contact) => contact.id), - ); - - this.logger.verbose('Verifying if contacts exists in database to insert'); - let contactsRaw: ContactRaw[] = []; - - for (const contact of contacts) { - if (contactsRepository.has(contact.id)) { - continue; - } - - contactsRaw.push({ - id: contact.id, - pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], - profilePictureUrl: null, - owner: this.instance.name, - }); - } + const contactsRaw: any = contacts.map((contact) => ({ + remoteJid: contact.id, + pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], + profilePicUrl: null, + instanceId: this.instanceId, + })); this.logger.verbose('Sending data to webhook in event CONTACTS_UPSERT'); if (contactsRaw.length > 0) this.sendDataWebhook(Events.CONTACTS_UPSERT, contactsRaw); this.logger.verbose('Inserting contacts in database'); - this.mongodbRepository.contact.insert(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); + if (contactsRaw.length > 0) { + await this.prismaRepository.contact.createMany({ + data: contactsRaw, + skipDuplicates: true, + }); + } - if (this.localChatwoot.enabled && this.localChatwoot.import_contacts && contactsRaw.length) { + if (this.localChatwoot.enabled && this.localChatwoot.importContacts && contactsRaw.length) { this.chatwootService.addHistoryContacts({ instanceName: this.instance.name }, contactsRaw); chatwootImport.importHistoryContacts({ instanceName: this.instance.name }, this.localChatwoot); } - // Update profile pictures - contactsRaw = []; - for await (const contact of contacts) { - contactsRaw.push({ - id: contact.id, + this.logger.verbose('Updating profile pictures'); + const updatedContacts = await Promise.all( + contacts.map(async (contact) => ({ + remoteJid: contact.id, pushName: contact?.name || contact?.verifiedName || contact.id.split('@')[0], - profilePictureUrl: (await this.profilePicture(contact.id)).profilePictureUrl, - owner: this.instance.name, - }); - } + profilePicUrl: (await this.profilePicture(contact.id)).profilePictureUrl, + instanceId: this.instanceId, + })), + ); this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); - if (contactsRaw.length > 0) this.sendDataWebhook(Events.CONTACTS_UPSERT, contactsRaw); + if (updatedContacts.length > 0) this.sendDataWebhook(Events.CONTACTS_UPDATE, updatedContacts); this.logger.verbose('Updating contacts in database'); - this.mongodbRepository.contact.update(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); + if (updatedContacts.length > 0) { + await Promise.all( + updatedContacts.map((contact) => + this.prismaRepository.contact.updateMany({ + where: { remoteJid: contact.remoteJid, instanceId: this.instanceId }, + data: { + profilePicUrl: contact.profilePicUrl, + }, + }), + ), + ); + } } catch (error) { - this.logger.error(error); + this.logger.error(`Error: ${error.message}`); } }, - 'contacts.update': async (contacts: Partial[], database: Database) => { + 'contacts.update': async (contacts: Partial[]) => { this.logger.verbose('Event received: contacts.update'); this.logger.verbose('Verifying if contacts exists in database to update'); - const contactsRaw: ContactRaw[] = []; + const contactsRaw: any = []; for await (const contact of contacts) { contactsRaw.push({ - id: contact.id, + remoteJid: contact.id, pushName: contact?.name ?? contact?.verifiedName, - profilePictureUrl: (await this.profilePicture(contact.id)).profilePictureUrl, - owner: this.instance.name, + profilePicUrl: (await this.profilePicture(contact.id)).profilePictureUrl, + instanceId: this.instanceId, }); } @@ -966,30 +982,30 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw); this.logger.verbose('Updating contacts in database'); - this.mongodbRepository.contact.update(contactsRaw, this.instance.name, database.SAVE_DATA.CONTACTS); + this.prismaRepository.contact.updateMany({ + where: { instanceId: this.instanceId }, + data: contactsRaw, + }); }, }; private readonly messageHandle = { - 'messaging-history.set': async ( - { - messages, - chats, - contacts, - }: { - chats: Chat[]; - contacts: Contact[]; - messages: proto.IWebMessageInfo[]; - isLatest: boolean; - }, - database: Database, - ) => { + 'messaging-history.set': async ({ + messages, + chats, + contacts, + }: { + chats: Chat[]; + contacts: Contact[]; + messages: proto.IWebMessageInfo[]; + isLatest: boolean; + }) => { try { this.logger.verbose('Event received: messaging-history.set'); const instance: InstanceDto = { instanceName: this.instance.name }; - const daysLimitToImport = this.localChatwoot.enabled ? this.localChatwoot.days_limit_import_messages : 1000; + const daysLimitToImport = this.localChatwoot.enabled ? this.localChatwoot.daysLimitImportMessages : 1000; this.logger.verbose(`Param days limit import messages is: ${daysLimitToImport}`); const date = new Date(); @@ -1004,14 +1020,13 @@ export class BaileysStartupService extends ChannelStartupService { return; } - const chatsRaw: ChatRaw[] = []; + const chatsRaw: any[] = []; const chatsRepository = new Set( ( - await this.mongodbRepository.chat.find({ - select: { id: 1, _id: 0 }, - where: { owner: this.instance.name }, + await this.prismaRepository.chat.findMany({ + where: { instanceId: this.instanceId }, }) - ).map((chat) => chat.id), + ).map((chat) => chat.remoteJid), ); for (const chat of chats) { @@ -1020,8 +1035,8 @@ export class BaileysStartupService extends ChannelStartupService { } chatsRaw.push({ - id: chat.id, - owner: this.instance.name, + remoteJid: chat.id, + instanceId: this.instanceId, lastMsgTimestamp: chat.lastMessageRecvTimestamp, }); } @@ -1030,17 +1045,26 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.CHATS_SET, chatsRaw); this.logger.verbose('Inserting chats in database'); - this.mongodbRepository.chat.insert(chatsRaw, this.instance.name, database.SAVE_DATA.CHATS); + this.prismaRepository.chat.createMany({ + data: chatsRaw, + skipDuplicates: true, + }); - const messagesRaw: MessageRaw[] = []; + const messagesRaw: any[] = []; const messagesRepository = new Set( chatwootImport.getRepositoryMessagesCache(instance) ?? ( - await this.mongodbRepository.message.find({ - select: { key: { id: 1 }, _id: 0 }, - where: { owner: this.instance.name }, + await this.prismaRepository.message.findMany({ + select: { key: true }, + where: { instanceId: this.instanceId }, }) - ).map((message) => message.key.id), + ).map((message) => { + const key = message.key as { + id: string; + }; + + return key.id; + }), ); if (chatwootImport.getRepositoryMessagesCache(instance) === null) { @@ -1080,8 +1104,8 @@ export class BaileysStartupService extends ChannelStartupService { message: { ...m.message }, messageType: getContentType(m.message), messageTimestamp: m.messageTimestamp as number, - owner: this.instance.name, status: m.status ? status[m.status] : null, + instanceId: this.instanceId, }); } @@ -1089,9 +1113,12 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.MESSAGES_SET, [...messagesRaw]); this.logger.verbose('Inserting messages in database'); - await this.mongodbRepository.message.insert(messagesRaw, this.instance.name, database.SAVE_DATA.NEW_MESSAGE); + this.prismaRepository.message.createMany({ + data: messagesRaw, + skipDuplicates: true, + }); - if (this.localChatwoot.enabled && this.localChatwoot.import_messages && messagesRaw.length > 0) { + if (this.localChatwoot.enabled && this.localChatwoot.importMessages && messagesRaw.length > 0) { this.chatwootService.addHistoryMessages( instance, messagesRaw.filter((msg) => !chatwootImport.isIgnorePhoneNumber(msg.key?.remoteJid)), @@ -1105,7 +1132,6 @@ export class BaileysStartupService extends ChannelStartupService { id: c.id, name: c.name ?? c.notify, })), - database, ); contacts = undefined; @@ -1124,8 +1150,7 @@ export class BaileysStartupService extends ChannelStartupService { messages: proto.IWebMessageInfo[]; type: MessageUpsertType; }, - database: Database, - settings: SettingsRaw, + settings: any, ) => { try { this.logger.verbose('Event received: messages.upsert'); @@ -1169,12 +1194,12 @@ export class BaileysStartupService extends ChannelStartupService { received.messageTimestamp = received.messageTimestamp?.toNumber(); } - if (settings?.groups_ignore && received.key.remoteJid.includes('@g.us')) { + if (settings?.groupsIgnore && received.key.remoteJid.includes('@g.us')) { this.logger.verbose('group ignored'); return; } - let messageRaw: MessageRaw; + let messageRaw: any; const isMedia = received?.message?.imageMessage || @@ -1185,7 +1210,7 @@ export class BaileysStartupService extends ChannelStartupService { const contentMsg = received?.message[getContentType(received.message)] as any; - if (this.localWebhook.webhook_base64 === true && isMedia) { + if (this.localWebhook.webhookBase64 === true && isMedia) { const buffer = await downloadMediaMessage( { key: received.key, message: received?.message }, 'buffer', @@ -1195,6 +1220,7 @@ export class BaileysStartupService extends ChannelStartupService { reuploadRequest: this.client.updateMediaMessage, }, ); + messageRaw = { key: received.key, pushName: received.pushName, @@ -1205,7 +1231,7 @@ export class BaileysStartupService extends ChannelStartupService { contextInfo: contentMsg?.contextInfo, messageType: getContentType(received.message), messageTimestamp: received.messageTimestamp as number, - owner: this.instance.name, + instanceId: this.instanceId, source: getDevice(received.key.id), }; } else { @@ -1216,16 +1242,16 @@ export class BaileysStartupService extends ChannelStartupService { contextInfo: contentMsg?.contextInfo, messageType: getContentType(received.message), messageTimestamp: received.messageTimestamp as number, - owner: this.instance.name, + instanceId: this.instanceId, source: getDevice(received.key.id), }; } - if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') { + if (this.localSettings.readMessages && received.key.id !== 'status@broadcast') { await this.client.readMessages([received.key]); } - if (this.localSettings.read_status && received.key.id === 'status@broadcast') { + if (this.localSettings.readStatus && received.key.id === 'status@broadcast') { await this.client.readMessages([received.key]); } @@ -1255,7 +1281,7 @@ export class BaileysStartupService extends ChannelStartupService { ); if ((this.localTypebot.enabled && type === 'notify') || typebotSessionRemoteJid) { - if (!(this.localTypebot.listening_from_me === false && messageRaw.key.fromMe === true)) { + if (!(this.localTypebot.listeningFromMe === false && messageRaw.key.fromMe === true)) { if (messageRaw.messageType !== 'reactionMessage') await this.typebotService.sendTypebot( { instanceName: this.instance.name }, @@ -1266,18 +1292,20 @@ export class BaileysStartupService extends ChannelStartupService { } this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.message.insert([messageRaw], this.instance.name, database.SAVE_DATA.NEW_MESSAGE); - - this.logger.verbose('Verifying contact from message'); - const contact = await this.mongodbRepository.contact.find({ - where: { owner: this.instance.name, id: received.key.remoteJid }, + await this.prismaRepository.message.create({ + data: messageRaw, }); - const contactRaw: ContactRaw = { - id: received.key.remoteJid, + this.logger.verbose('Verifying contact from message'); + const contact = await this.prismaRepository.contact.findFirst({ + where: { remoteJid: received.key.remoteJid, instanceId: this.instanceId }, + }); + + const contactRaw: any = { + remoteJid: received.key.remoteJid, pushName: received.pushName, - profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + profilePicUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, + instanceId: this.instanceId, }; if (contactRaw.id === 'status@broadcast') { @@ -1285,13 +1313,13 @@ export class BaileysStartupService extends ChannelStartupService { return; } - if (contact?.length) { + if (contact) { this.logger.verbose('Contact found in database'); - const contactRaw: ContactRaw = { - id: received.key.remoteJid, - pushName: contact[0].pushName, - profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + const contactRaw: any = { + remoteJid: received.key.remoteJid, + pushName: contact.pushName, + profilePicUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, + instanceId: this.instanceId, }; this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); @@ -1306,7 +1334,10 @@ export class BaileysStartupService extends ChannelStartupService { } this.logger.verbose('Updating contact in database'); - await this.mongodbRepository.contact.update([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + this.prismaRepository.contact.updateMany({ + where: { remoteJid: received.key.remoteJid, instanceId: this.instanceId }, + data: contactRaw, + }); return; } @@ -1316,14 +1347,16 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); this.logger.verbose('Inserting contact in database'); - this.mongodbRepository.contact.insert([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + await this.prismaRepository.contact.create({ + data: contactRaw, + }); } } catch (error) { this.logger.error(error); } }, - 'messages.update': async (args: WAMessageUpdate[], database: Database, settings: SettingsRaw) => { + 'messages.update': async (args: WAMessageUpdate[], settings: any) => { this.logger.verbose('Event received: messages.update'); const status: Record = { 0: 'ERROR', @@ -1334,7 +1367,7 @@ export class BaileysStartupService extends ChannelStartupService { 5: 'PLAYED', }; for await (const { key, update } of args) { - if (settings?.groups_ignore && key.remoteJid?.includes('@g.us')) { + if (settings?.groupsIgnore && key.remoteJid?.includes('@g.us')) { this.logger.verbose('group ignored'); return; } @@ -1365,6 +1398,21 @@ export class BaileysStartupService extends ChannelStartupService { } } + const findMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, + }); + + if (!findMessage) { + this.logger.verbose('Message not found in database'); + return; + } + if (status[update.status] === 'READ' && !key.fromMe) return; if (update.message === null && update.status === undefined) { @@ -1373,21 +1421,22 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('Sending data to webhook in event MESSAGE_DELETE'); this.sendDataWebhook(Events.MESSAGES_DELETE, key); - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: 'DELETED', - datetime: Date.now(), - owner: this.instance.name, + dateTime: Date.now(), }; this.logger.verbose(message); this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.messageUpdate.insert( - [message], - this.instance.name, - database.SAVE_DATA.MESSAGE_UPDATE, - ); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); if (this.localChatwoot.enabled) { this.chatwootService.eventWhatsapp( @@ -1400,11 +1449,14 @@ export class BaileysStartupService extends ChannelStartupService { return; } - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: status[update.status], - datetime: Date.now(), - owner: this.instance.name, + dateTime: Date.now(), pollUpdates, }; @@ -1414,7 +1466,9 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.MESSAGES_UPDATE, message); this.logger.verbose('Inserting message in database'); - this.mongodbRepository.messageUpdate.insert([message], this.instance.name, database.SAVE_DATA.MESSAGE_UPDATE); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); } } }, @@ -1454,37 +1508,35 @@ export class BaileysStartupService extends ChannelStartupService { }; private readonly labelHandle = { - [Events.LABELS_EDIT]: async (label: Label, database: Database) => { + [Events.LABELS_EDIT]: async (label: Label) => { this.logger.verbose('Event received: labels.edit'); this.logger.verbose('Finding labels in database'); - const labelsRepository = await this.mongodbRepository.labels.find({ - where: { owner: this.instance.name }, + const labelsRepository = await this.prismaRepository.label.findMany({ + where: { instanceId: this.instanceId }, }); - const savedLabel = labelsRepository.find((l) => l.id === label.id); + const savedLabel = labelsRepository.find((l) => l.labelId === label.id); if (label.deleted && savedLabel) { this.logger.verbose('Sending data to webhook in event LABELS_EDIT'); - await this.mongodbRepository.labels.delete({ - where: { owner: this.instance.name, id: label.id }, + await this.prismaRepository.label.delete({ + where: { instanceId: this.instanceId, labelId: label.id }, }); this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); return; } const labelName = label.name.replace(/[^\x20-\x7E]/g, ''); - if (!savedLabel || savedLabel.color !== label.color || savedLabel.name !== labelName) { + if (!savedLabel || savedLabel.color !== `${label.color}` || savedLabel.name !== labelName) { this.logger.verbose('Sending data to webhook in event LABELS_EDIT'); - await this.mongodbRepository.labels.insert( - { - color: label.color, + await this.prismaRepository.label.create({ + data: { + color: `${label.color}`, name: labelName, - owner: this.instance.name, - id: label.id, + labelId: label.id, predefinedId: label.predefinedId, + instanceId: this.instanceId, }, - this.instance.name, - database.SAVE_DATA.LABELS, - ); + }); this.sendDataWebhook(Events.LABELS_EDIT, { ...label, instance: this.instance.name }); } }, @@ -1497,24 +1549,25 @@ export class BaileysStartupService extends ChannelStartupService { // Atualiza labels nos chats if (database.ENABLED && database.SAVE_DATA.CHATS) { - const chats = await this.mongodbRepository.chat.find({ - where: { - owner: this.instance.name, - }, + const chats = await this.prismaRepository.chat.findMany({ + where: { instanceId: this.instanceId }, }); - const chat = chats.find((c) => c.id === data.association.chatId); + const chat = chats.find((c) => c.remoteJid === data.association.chatId); if (chat) { - let labels = [...chat.labels]; + const labelsArray = Array.isArray(chat.labels) ? chat.labels.map((event) => String(event)) : []; + let labels = [...labelsArray]; + if (data.type === 'remove') { labels = labels.filter((label) => label !== data.association.labelId); } else if (data.type === 'add') { labels = [...labels, data.association.labelId]; } - await this.mongodbRepository.chat.update( - [{ id: chat.id, owner: this.instance.name, labels }], - this.instance.name, - database.SAVE_DATA.CHATS, - ); + await this.prismaRepository.chat.update({ + where: { id: chat.id }, + data: { + labels, + }, + }); } } @@ -1540,15 +1593,15 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('Listening event: call'); const call = events.call[0]; - if (settings?.reject_call && call.status == 'offer') { + if (settings?.rejectCall && call.status == 'offer') { this.logger.verbose('Rejecting call'); this.client.rejectCall(call.id, call.from); } - if (settings?.msg_call?.trim().length > 0 && call.status == 'offer') { + if (settings?.msgCall?.trim().length > 0 && call.status == 'offer') { this.logger.verbose('Sending message in call'); const msg = await this.client.sendMessage(call.from, { - text: settings.msg_call, + text: settings.msgCall, }); this.logger.verbose('Sending data to event messages.upsert'); @@ -1575,33 +1628,33 @@ export class BaileysStartupService extends ChannelStartupService { if (events['messaging-history.set']) { this.logger.verbose('Listening event: messaging-history.set'); const payload = events['messaging-history.set']; - this.messageHandle['messaging-history.set'](payload, database); + this.messageHandle['messaging-history.set'](payload); } if (events['messages.upsert']) { this.logger.verbose('Listening event: messages.upsert'); const payload = events['messages.upsert']; - this.messageHandle['messages.upsert'](payload, database, settings); + this.messageHandle['messages.upsert'](payload, settings); } if (events['messages.update']) { this.logger.verbose('Listening event: messages.update'); const payload = events['messages.update']; - this.messageHandle['messages.update'](payload, database, settings); + this.messageHandle['messages.update'](payload, settings); } if (events['presence.update']) { this.logger.verbose('Listening event: presence.update'); const payload = events['presence.update']; - if (settings.groups_ignore && payload.id.includes('@g.us')) { + if (settings.groupsIgnore && payload.id.includes('@g.us')) { this.logger.verbose('group ignored'); return; } this.sendDataWebhook(Events.PRESENCE_UPDATE, payload); } - if (!settings?.groups_ignore) { + if (!settings?.groupsIgnore) { if (events['groups.upsert']) { this.logger.verbose('Listening event: groups.upsert'); const payload = events['groups.upsert']; @@ -1624,7 +1677,7 @@ export class BaileysStartupService extends ChannelStartupService { if (events['chats.upsert']) { this.logger.verbose('Listening event: chats.upsert'); const payload = events['chats.upsert']; - this.chatHandle['chats.upsert'](payload, database); + this.chatHandle['chats.upsert'](payload); } if (events['chats.update']) { @@ -1642,13 +1695,13 @@ export class BaileysStartupService extends ChannelStartupService { if (events['contacts.upsert']) { this.logger.verbose('Listening event: contacts.upsert'); const payload = events['contacts.upsert']; - this.contactHandle['contacts.upsert'](payload, database); + this.contactHandle['contacts.upsert'](payload); } if (events['contacts.update']) { this.logger.verbose('Listening event: contacts.update'); const payload = events['contacts.update']; - this.contactHandle['contacts.update'](payload, database); + this.contactHandle['contacts.update'](payload); } if (events[Events.LABELS_ASSOCIATION]) { @@ -1661,7 +1714,7 @@ export class BaileysStartupService extends ChannelStartupService { if (events[Events.LABELS_EDIT]) { this.logger.verbose('Listening event: labels.edit'); const payload = events[Events.LABELS_EDIT]; - this.labelHandle[Events.LABELS_EDIT](payload, database); + this.labelHandle[Events.LABELS_EDIT](payload); return; } } @@ -1673,7 +1726,7 @@ export class BaileysStartupService extends ChannelStartupService { if ( this.localChatwoot.enabled && - this.localChatwoot.import_messages && + this.localChatwoot.importMessages && this.isSyncNotificationFromUsedSyncType(msg) ) { if (msg.chunkOrder === 1) { @@ -1692,8 +1745,8 @@ export class BaileysStartupService extends ChannelStartupService { private isSyncNotificationFromUsedSyncType(msg: proto.Message.IHistorySyncNotification) { return ( - (this.localSettings.sync_full_history && msg?.syncType === 2) || - (!this.localSettings.sync_full_history && msg?.syncType === 3) + (this.localSettings.syncFullHistory && msg?.syncType === 2) || + (!this.localSettings.syncFullHistory && msg?.syncType === 3) ); } @@ -2015,14 +2068,14 @@ export class BaileysStartupService extends ChannelStartupService { const contentMsg = messageSent.message[getContentType(messageSent.message)] as any; - const messageRaw: MessageRaw = { + const messageRaw: any = { key: messageSent.key, pushName: messageSent.pushName, message: { ...messageSent.message }, contextInfo: contentMsg?.contextInfo, messageType: getContentType(messageSent.message), - messageTimestamp: messageSent.messageTimestamp as number, - owner: this.instance.name, + messageTimestamp: Long.fromValue(messageSent.messageTimestamp).toString(), + instanceId: this.instanceId, source: getDevice(messageSent.key.id), }; @@ -2036,11 +2089,9 @@ export class BaileysStartupService extends ChannelStartupService { } this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.message.insert( - [messageRaw], - this.instance.name, - this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE, - ); + await this.prismaRepository.message.create({ + data: messageRaw, + }); return messageSent; } catch (error) { @@ -2155,8 +2206,8 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('All contacts defined as true'); this.logger.verbose('Getting contacts from database'); - const contacts = await this.mongodbRepository.contact.find({ - where: { owner: this.instance.name }, + const contacts = await this.prismaRepository.contact.findMany({ + where: { instanceId: this.instanceId }, }); if (!contacts.length) { @@ -2164,7 +2215,7 @@ export class BaileysStartupService extends ChannelStartupService { } this.logger.verbose('Getting contacts with push name'); - status.statusJidList = contacts.filter((contact) => contact.pushName).map((contact) => contact.id); + status.statusJidList = contacts.filter((contact) => contact.pushName).map((contact) => contact.remoteJid); this.logger.verbose(status.statusJidList); } @@ -2681,10 +2732,15 @@ export class BaileysStartupService extends ChannelStartupService { onWhatsapp.push(...groups); // USERS - const contacts: ContactRaw[] = await this.mongodbRepository.contact.findManyById({ - owner: this.instance.name, - ids: jids.users.map(({ jid }) => (jid.startsWith('+') ? jid.substring(1) : jid)), + const contacts: any[] = await this.prismaRepository.contact.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: { + in: jids.users.map(({ jid }) => jid), + }, + }, }); + const numbersToVerify = jids.users.map(({ jid }) => jid.replace('+', '')); const verify = await this.client.onWhatsApp(...numbersToVerify); const users: OnWhatsAppDto[] = await Promise.all( @@ -3172,16 +3228,16 @@ export class BaileysStartupService extends ChannelStartupService { public async fetchLabels(): Promise { this.logger.verbose('Fetching labels'); - const labels = await this.mongodbRepository.labels.find({ + const labels = await this.prismaRepository.label.findMany({ where: { - owner: this.instance.name, + instanceId: this.instanceId, }, }); return labels.map((label) => ({ color: label.color, name: label.name, - id: label.id, + id: label.labelId, predefinedId: label.predefinedId, })); } @@ -3480,16 +3536,20 @@ export class BaileysStartupService extends ChannelStartupService { this.logger.verbose('Fetching participants for group: ' + id.groupJid); try { const participants = (await this.client.groupMetadata(id.groupJid)).participants; - const contacts = await this.mongodbRepository.contact.findManyById({ - owner: this.instance.name, - ids: participants.map((p) => p.id), + const contacts = await this.prismaRepository.contact.findMany({ + where: { + instanceId: this.instanceId, + remoteJid: { + in: participants.map((p) => p.id), + }, + }, }); const parsedParticipants = participants.map((participant) => { - const contact = contacts.find((c) => c.id === participant.id); + const contact = contacts.find((c) => c.remoteJid === participant.id); return { ...participant, name: participant.name ?? contact?.pushName, - imgUrl: participant.imgUrl ?? contact?.profilePictureUrl, + imgUrl: participant.imgUrl ?? contact?.profilePicUrl, }; }); return { participants: parsedParticipants }; diff --git a/src/api/services/channels/whatsapp.business.service.ts b/src/api/services/channels/whatsapp.business.service.ts index 3c4ab4e0..82fbe764 100644 --- a/src/api/services/channels/whatsapp.business.service.ts +++ b/src/api/services/channels/whatsapp.business.service.ts @@ -22,10 +22,8 @@ import { SendTemplateDto, SendTextDto, } from '../../dto/sendMessage.dto'; -import { ContactRaw, MessageRaw, MessageUpdateRaw, SettingsRaw } from '../../models'; import { ProviderFiles } from '../../provider/sessions'; -import { MongodbRepository } from '../../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../../repository/prisma/repository.service'; +import { PrismaRepository } from '../../repository/repository.service'; import { Events, wa } from '../../types/wa.types'; import { CacheService } from './../cache.service'; import { ChannelStartupService } from './../channel.service'; @@ -34,14 +32,13 @@ export class BusinessStartupService extends ChannelStartupService { constructor( public readonly configService: ConfigService, public readonly eventEmitter: EventEmitter2, - public readonly mongodbRepository: MongodbRepository, public readonly prismaRepository: PrismaRepository, public readonly cache: CacheService, public readonly chatwootCache: CacheService, public readonly baileysCache: CacheService, private readonly providerFiles: ProviderFiles, ) { - super(configService, eventEmitter, mongodbRepository, prismaRepository, chatwootCache); + super(configService, eventEmitter, prismaRepository, chatwootCache); this.logger.verbose('BusinessStartupService initialized'); this.cleanStore(); } @@ -318,9 +315,9 @@ export class BusinessStartupService extends ChannelStartupService { return messageType; } - protected async messageHandle(received: any, database: Database, settings: SettingsRaw) { + protected async messageHandle(received: any, database: Database, settings: any) { try { - let messageRaw: MessageRaw; + let messageRaw: any; let pushName: any; if (received.contacts) pushName = received.contacts[0].profile.name; @@ -398,11 +395,11 @@ export class BusinessStartupService extends ChannelStartupService { }; } - if (this.localSettings.read_messages && received.key.id !== 'status@broadcast') { + if (this.localSettings.readMessages && received.key.id !== 'status@broadcast') { // await this.client.readMessages([received.key]); } - if (this.localSettings.read_status && received.key.id === 'status@broadcast') { + if (this.localSettings.readStatus && received.key.id === 'status@broadcast') { // await this.client.readMessages([received.key]); } @@ -433,7 +430,7 @@ export class BusinessStartupService extends ChannelStartupService { ); if (this.localTypebot.enabled || typebotSessionRemoteJid) { - if (!(this.localTypebot.listening_from_me === false && key.fromMe === true)) { + if (!(this.localTypebot.listeningFromMe === false && key.fromMe === true)) { if (messageRaw.messageType !== 'reactionMessage') await this.typebotService.sendTypebot( { instanceName: this.instance.name }, @@ -444,32 +441,34 @@ export class BusinessStartupService extends ChannelStartupService { } this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.message.insert([messageRaw], this.instance.name, database.SAVE_DATA.NEW_MESSAGE); - - this.logger.verbose('Verifying contact from message'); - const contact = await this.mongodbRepository.contact.find({ - where: { owner: this.instance.name, id: key.remoteJid }, + await this.prismaRepository.message.create({ + data: messageRaw, }); - const contactRaw: ContactRaw = { - id: received.contacts[0].profile.phone, + this.logger.verbose('Verifying contact from message'); + const contact = await this.prismaRepository.contact.findFirst({ + where: { instanceId: this.instanceId, remoteJid: key.remoteJid }, + }); + + const contactRaw: any = { + remoteJid: received.contacts[0].profile.phone, pushName, - //profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + // profilePicUrl: '', + instanceId: this.instanceId, }; - if (contactRaw.id === 'status@broadcast') { + if (contactRaw.remoteJid === 'status@broadcast') { this.logger.verbose('Contact is status@broadcast'); return; } - if (contact?.length) { + if (contact) { this.logger.verbose('Contact found in database'); - const contactRaw: ContactRaw = { - id: received.contacts[0].profile.phone, + const contactRaw: any = { + remoteJid: received.contacts[0].profile.phone, pushName, - //profilePictureUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, - owner: this.instance.name, + // profilePicUrl: '', + instanceId: this.instanceId, }; this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE'); @@ -484,7 +483,10 @@ export class BusinessStartupService extends ChannelStartupService { } this.logger.verbose('Updating contact in database'); - await this.mongodbRepository.contact.update([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + await this.prismaRepository.contact.updateMany({ + where: { remoteJid: contact.remoteJid }, + data: contactRaw, + }); return; } @@ -494,7 +496,9 @@ export class BusinessStartupService extends ChannelStartupService { this.sendDataWebhook(Events.CONTACTS_UPSERT, contactRaw); this.logger.verbose('Inserting contact in database'); - this.mongodbRepository.contact.insert([contactRaw], this.instance.name, database.SAVE_DATA.CONTACTS); + this.prismaRepository.contact.create({ + data: contactRaw, + }); } this.logger.verbose('Event received: messages.update'); if (received.statuses) { @@ -513,27 +517,38 @@ export class BusinessStartupService extends ChannelStartupService { if (item.status === 'read' && !key.fromMe) return; + const findMessage = await this.prismaRepository.message.findFirst({ + where: { + instanceId: this.instanceId, + key: { + path: ['id'], + equals: key.id, + }, + }, + }); + if (item.message === null && item.status === undefined) { this.logger.verbose('Message deleted'); this.logger.verbose('Sending data to webhook in event MESSAGE_DELETE'); this.sendDataWebhook(Events.MESSAGES_DELETE, key); - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: 'DELETED', - datetime: Date.now(), - owner: this.instance.name, + dateTime: Date.now(), }; this.logger.verbose(message); this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.messageUpdate.insert( - [message], - this.instance.name, - database.SAVE_DATA.MESSAGE_UPDATE, - ); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); if (this.localChatwoot.enabled) { this.chatwootService.eventWhatsapp( @@ -546,11 +561,14 @@ export class BusinessStartupService extends ChannelStartupService { return; } - const message: MessageUpdateRaw = { - ...key, + const message: any = { + messageId: findMessage.id, + keyId: key.id, + remoteJid: key.remoteJid, + fromMe: key.fromMe, + participant: key?.remoteJid, status: item.status.toUpperCase(), - datetime: Date.now(), - owner: this.instance.name, + dateTime: Date.now(), }; this.logger.verbose(message); @@ -559,11 +577,9 @@ export class BusinessStartupService extends ChannelStartupService { this.sendDataWebhook(Events.MESSAGES_UPDATE, message); this.logger.verbose('Inserting message in database'); - this.mongodbRepository.messageUpdate.insert( - [message], - this.instance.name, - database.SAVE_DATA.MESSAGE_UPDATE, - ); + await this.prismaRepository.messageUpdate.create({ + data: message, + }); } } } @@ -848,13 +864,13 @@ export class BusinessStartupService extends ChannelStartupService { console.log(content); - const messageRaw: MessageRaw = { + const messageRaw: any = { key: { fromMe: true, id: messageSent?.messages[0]?.id, remoteJid: this.createJid(number) }, //pushName: messageSent.pushName, message: this.convertMessageToRaw(message, content), messageType: this.renderMessageType(content.type), messageTimestamp: (messageSent?.messages[0]?.timestamp as number) || Math.round(new Date().getTime() / 1000), - owner: this.instance.name, + instanceId: this.instanceId, //ource: getDevice(messageSent.key.id), }; @@ -868,11 +884,9 @@ export class BusinessStartupService extends ChannelStartupService { } this.logger.verbose('Inserting message in database'); - await this.mongodbRepository.message.insert( - [messageRaw], - this.instance.name, - this.configService.get('DATABASE').SAVE_DATA.NEW_MESSAGE, - ); + await this.prismaRepository.message.create({ + data: messageRaw, + }); return messageRaw; } catch (error) { diff --git a/src/api/services/integration.service.ts b/src/api/services/integration.service.ts index c457fa93..d6d2bc9c 100644 --- a/src/api/services/integration.service.ts +++ b/src/api/services/integration.service.ts @@ -1,7 +1,8 @@ +import { Integration } from '@prisma/client'; + import { Logger } from '../../config/logger.config'; import { InstanceDto } from '../dto/instance.dto'; import { IntegrationDto } from '../dto/integration.dto'; -import { IntegrationRaw } from '../models'; import { WAMonitoringService } from './monitor.service'; export class IntegrationService { @@ -16,19 +17,19 @@ export class IntegrationService { return { integration: { ...instance, integration: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find integration: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findIntegration(); if (Object.keys(result).length === 0) { this.create(instance, { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }); - return { integration: 'WHATSAPP-BAILEYS', number: '', token: '' }; + return null; } return result; } catch (error) { - return { integration: '', number: '', token: '' }; + return null; } } } diff --git a/src/api/services/monitor.service.ts b/src/api/services/monitor.service.ts index f9dbafe4..ce6c742d 100644 --- a/src/api/services/monitor.service.ts +++ b/src/api/services/monitor.service.ts @@ -1,8 +1,6 @@ import { execSync } from 'child_process'; import EventEmitter2 from 'eventemitter2'; import { existsSync, mkdirSync, opendirSync, readdirSync, rmSync, writeFileSync } from 'fs'; -import { Db } from 'mongodb'; -import { Collection } from 'mongoose'; import { join } from 'path'; import { @@ -17,21 +15,8 @@ import { import { Logger } from '../../config/logger.config'; import { INSTANCE_DIR, STORE_DIR } from '../../config/path.config'; import { NotFoundException } from '../../exceptions'; -import { - AuthModel, - ChatwootModel, - ContactModel, - LabelModel, - ProxyModel, - RabbitmqModel, - SettingsModel, - TypebotModel, - WebhookModel, - WebsocketModel, -} from '../models'; import { ProviderFiles } from '../provider/sessions'; -import { MongodbRepository } from '../repository/mongodb/repository.manager'; -import { PrismaRepository } from '../repository/prisma/repository.service'; +import { PrismaRepository } from '../repository/repository.service'; import { Integration } from '../types/wa.types'; import { CacheService } from './cache.service'; import { BaileysStartupService } from './channels/whatsapp.baileys.service'; @@ -41,12 +26,11 @@ export class WAMonitoringService { constructor( private readonly eventEmitter: EventEmitter2, private readonly configService: ConfigService, - private readonly monogodbRepository: MongodbRepository, - private readonly primaRepository: PrismaRepository, + private readonly prismaRepository: PrismaRepository, + private readonly providerFiles: ProviderFiles, private readonly cache: CacheService, private readonly chatwootCache: CacheService, private readonly baileysCache: CacheService, - private readonly providerFiles: ProviderFiles, ) { this.logger.verbose('instance created'); @@ -55,17 +39,11 @@ export class WAMonitoringService { Object.assign(this.db, configService.get('DATABASE')); Object.assign(this.redis, configService.get('CACHE')); - - this.dbInstance = this.db.ENABLED - ? this.monogodbRepository.mongodbServer?.db(this.db.CONNECTION.DB_PREFIX_NAME + '-instances') - : undefined; } private readonly db: Partial = {}; private readonly redis: Partial = {}; - private dbInstance: Db; - private readonly logger = new Logger(WAMonitoringService.name); public readonly waInstances: Record = {}; @@ -126,7 +104,7 @@ export class WAMonitoringService { if (findIntegration) { integration = { ...findIntegration, - webhook_wa_business: `${urlServer}/webhook/whatsapp/${encodeURIComponent(key)}`, + webhookWaBusiness: `${urlServer}/webhook/whatsapp/${encodeURIComponent(key)}`, }; } @@ -136,7 +114,7 @@ export class WAMonitoringService { const instanceData = { instance: { instanceName: key, - instanceId: (await this.monogodbRepository.auth.find(key))?.instanceId, + instanceId: this.waInstances[key].instanceId, owner: value.wuid, profileName: (await value.getProfileName()) || 'not loaded', profilePictureUrl: value.profilePictureUrl, @@ -148,7 +126,11 @@ export class WAMonitoringService { if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - instanceData.instance['apikey'] = (await this.monogodbRepository.auth.find(key))?.apikey; + instanceData.instance['apikey'] = ( + await this.prismaRepository.auth.findFirst({ + where: { instanceId: this.waInstances[key].instanceId }, + }) + )?.apikey; instanceData.instance['chatwoot'] = chatwoot; @@ -162,7 +144,7 @@ export class WAMonitoringService { const instanceData = { instance: { instanceName: key, - instanceId: (await this.monogodbRepository.auth.find(key))?.instanceId, + instanceId: this.waInstances[key].instanceId, status: value.connectionStatus.state, }, }; @@ -170,7 +152,11 @@ export class WAMonitoringService { if (this.configService.get('AUTHENTICATION').EXPOSE_IN_FETCH_INSTANCES) { instanceData.instance['serverUrl'] = this.configService.get('SERVER').URL; - instanceData.instance['apikey'] = (await this.monogodbRepository.auth.find(key))?.apikey; + instanceData.instance['apikey'] = ( + await this.prismaRepository.auth.findFirst({ + where: { instanceId: this.waInstances[key].instanceId }, + }) + )?.apikey; instanceData.instance['chatwoot'] = chatwoot; @@ -194,12 +180,14 @@ export class WAMonitoringService { this.logger.verbose('get instance info'); let instanceName: string; if (instanceId) { - instanceName = await this.monogodbRepository.auth.findInstanceNameById(instanceId); + instanceName = await this.prismaRepository.instance.findFirst({ where: { id: instanceId } }).then((r) => r?.name); if (!instanceName) { throw new NotFoundException(`Instance "${instanceId}" not found`); } } else if (number) { - instanceName = await this.monogodbRepository.auth.findInstanceNameByNumber(number); + const id = await this.prismaRepository.integration.findFirst({ where: { number } }).then((r) => r?.instanceId); + + instanceName = await this.prismaRepository.instance.findFirst({ where: { id } }).then((r) => r?.name); if (!instanceName) { throw new NotFoundException(`Instance "${number}" not found`); } @@ -216,50 +204,12 @@ export class WAMonitoringService { return this.instanceInfo(instanceName); } - private delInstanceFiles() { - this.logger.verbose('cron to delete instance files started'); - setInterval(async () => { - if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - const collections = await this.dbInstance.collections(); - collections.forEach(async (collection) => { - const name = collection.namespace.replace(/^[\w-]+./, ''); - await this.dbInstance.collection(name).deleteMany({ - $or: [{ _id: { $regex: /^app.state.*/ } }, { _id: { $regex: /^session-.*/ } }], - }); - this.logger.verbose('instance files deleted: ' + name); - }); - } else if (!this.redis.REDIS.ENABLED && !this.redis.REDIS.SAVE_INSTANCES) { - const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); - for await (const dirent of dir) { - if (dirent.isDirectory()) { - const files = readdirSync(join(INSTANCE_DIR, dirent.name), { - encoding: 'utf-8', - }); - files.forEach(async (file) => { - if (file.match(/^app.state.*/) || file.match(/^session-.*/)) { - rmSync(join(INSTANCE_DIR, dirent.name, file), { - recursive: true, - force: true, - }); - } - }); - this.logger.verbose('instance files deleted: ' + dirent.name); - } - } - } - }, 3600 * 1000 * 2); - } - public async cleaningUp(instanceName: string) { this.logger.verbose('cleaning up instance: ' + instanceName); if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { this.logger.verbose('cleaning up instance in database: ' + instanceName); - await this.monogodbRepository.mongodbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - if (collections.length > 0) { - await this.dbInstance.dropCollection(instanceName); - } + // TODO: deleta instancia return; } @@ -304,20 +254,7 @@ export class WAMonitoringService { this.logger.verbose('cleaning store database instance: ' + instanceName); - if (this.db.PROVIDER === 'mongodb') { - await AuthModel.deleteMany({ _id: instanceName }); - await WebhookModel.deleteMany({ _id: instanceName }); - await ChatwootModel.deleteMany({ _id: instanceName }); - await ProxyModel.deleteMany({ _id: instanceName }); - await RabbitmqModel.deleteMany({ _id: instanceName }); - await TypebotModel.deleteMany({ _id: instanceName }); - await WebsocketModel.deleteMany({ _id: instanceName }); - await SettingsModel.deleteMany({ _id: instanceName }); - await LabelModel.deleteMany({ owner: instanceName }); - await ContactModel.deleteMany({ owner: instanceName }); - - return; - } + // TODO: deleta dados da instancia } public async loadInstance() { @@ -329,8 +266,7 @@ export class WAMonitoringService { } else if (this.redis.REDIS.ENABLED && this.redis.REDIS.SAVE_INSTANCES) { await this.loadInstancesFromRedis(); } else if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - if (this.db.PROVIDER === 'mongodb') await this.loadInstancesFromDatabaseMongoDB(); - else if (this.db.PROVIDER === 'postgresql') await this.loadInstancesFromDatabasePostgres(); + await this.loadInstancesFromDatabasePostgres(); } else { await this.loadInstancesFromFiles(); } @@ -345,9 +281,22 @@ export class WAMonitoringService { try { const msgParsed = JSON.parse(JSON.stringify(data)); if (this.db.ENABLED && this.db.SAVE_DATA.INSTANCE) { - await this.monogodbRepository.mongodbServer.connect(); - await this.dbInstance.collection(data.instanceName).replaceOne({ _id: 'integration' }, msgParsed, { - upsert: true, + await this.prismaRepository.instance.create({ + data: { + id: data.instanceId, + name: data.instanceName, + connectionStatus: 'close', + }, + }); + + console.log('saveInstance'); + await this.prismaRepository.integration.create({ + data: { + instanceId: data.instanceId, + integration: data.integration, + number: data.number, + token: data.token, + }, }); } else { const path = join(INSTANCE_DIR, data.instanceName); @@ -359,16 +308,18 @@ export class WAMonitoringService { } } - private async setInstance(name: string) { - const integration = await this.monogodbRepository.integration.find(name); + private async setInstance(id: string, name: string) { + console.log('setInstance', name); + const integration = await this.prismaRepository.integration.findUnique({ + where: { instanceId: id }, + }); let instance: BaileysStartupService | BusinessStartupService; if (integration && integration.integration === Integration.WHATSAPP_BUSINESS) { instance = new BusinessStartupService( this.configService, this.eventEmitter, - this.monogodbRepository, - this.primaRepository, + this.prismaRepository, this.cache, this.chatwootCache, this.baileysCache, @@ -376,12 +327,12 @@ export class WAMonitoringService { ); instance.instanceName = name; + instance.instanceId = id; } else { instance = new BaileysStartupService( this.configService, this.eventEmitter, - this.monogodbRepository, - this.primaRepository, + this.prismaRepository, this.cache, this.chatwootCache, this.baileysCache, @@ -389,9 +340,10 @@ export class WAMonitoringService { ); instance.instanceName = name; + instance.instanceId = id; if (!integration) { - await instance.setIntegration({ integration: Integration.WHATSAPP_BAILEYS }); + await instance.setIntegration({ integration: Integration.WHATSAPP_BAILEYS, number: '', token: '' }); } } @@ -403,45 +355,34 @@ export class WAMonitoringService { } private async loadInstancesFromRedis() { + console.log('loadInstancesFromRedis'); this.logger.verbose('Redis enabled'); const keys = await this.cache.keys(); if (keys?.length > 0) { this.logger.verbose('Reading instance keys and setting instances'); - await Promise.all(keys.map((k) => this.setInstance(k.split(':')[2]))); + await Promise.all(keys.map((k) => this.setInstance(k.split(':')[1], k.split(':')[2]))); } else { this.logger.verbose('No instance keys found'); } } - private async loadInstancesFromDatabaseMongoDB() { - this.logger.verbose('Database enabled'); - await this.monogodbRepository.mongodbServer.connect(); - const collections: any[] = await this.dbInstance.collections(); - await this.deleteTempInstances(collections); - if (collections.length > 0) { - this.logger.verbose('Reading collections and setting instances'); - await Promise.all(collections.map((coll) => this.setInstance(coll.namespace.replace(/^[\w-]+\./, '')))); - } else { - this.logger.verbose('No collections found'); - } - } - private async loadInstancesFromDatabasePostgres() { + console.log('loadInstancesFromDatabasePostgres'); this.logger.verbose('Database enabled'); - await this.primaRepository.onModuleInit(); - - const instances = await this.primaRepository.instance.findMany(); + const instances = await this.prismaRepository.instance.findMany(); + console.log('instances', instances); if (instances.length === 0) { this.logger.verbose('No instances found'); return; } - await Promise.all(instances.map(async (instance) => this.setInstance(instance.name))); + await Promise.all(instances.map(async (instance) => this.setInstance(instance.id, instance.name))); } private async loadInstancesFromProvider() { + console.log('loadInstancesFromProvider'); this.logger.verbose('Provider in files enabled'); const [instances] = await this.providerFiles.allInstances(); @@ -450,10 +391,11 @@ export class WAMonitoringService { return; } - await Promise.all(instances?.data?.map(async (instanceName: string) => this.setInstance(instanceName))); + await Promise.all(instances?.data?.map(async (instanceName: string) => this.setInstance('', instanceName))); } private async loadInstancesFromFiles() { + console.log('loadInstancesFromFiles'); this.logger.verbose('Store in files enabled'); const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); const instanceDirs = []; @@ -474,7 +416,7 @@ export class WAMonitoringService { if (files.length === 0) { rmSync(join(INSTANCE_DIR, instanceName), { recursive: true, force: true }); } else { - await this.setInstance(instanceName); + await this.setInstance('', instanceName); } }), ); @@ -534,25 +476,42 @@ export class WAMonitoringService { }); } - private async deleteTempInstances(collections: Collection[]) { + private delInstanceFiles() { + this.logger.verbose('cron to delete instance files started'); + setInterval(async () => { + const dir = opendirSync(INSTANCE_DIR, { encoding: 'utf-8' }); + for await (const dirent of dir) { + if (dirent.isDirectory()) { + const files = readdirSync(join(INSTANCE_DIR, dirent.name), { + encoding: 'utf-8', + }); + files.forEach(async (file) => { + if (file.match(/^app.state.*/) || file.match(/^session-.*/)) { + rmSync(join(INSTANCE_DIR, dirent.name, file), { + recursive: true, + force: true, + }); + } + }); + this.logger.verbose('instance files deleted: ' + dirent.name); + } + } + }, 3600 * 1000 * 2); + } + + private async deleteTempInstances() { const shouldDelete = this.configService.get('DEL_TEMP_INSTANCES'); if (!shouldDelete) { this.logger.verbose('Temp instances deletion is disabled'); return; } this.logger.verbose('Cleaning up temp instances'); - const auths = await this.monogodbRepository.auth.list(); - if (auths.length === 0) { - this.logger.verbose('No temp instances found'); - return; - } + const instancesClosed = await this.prismaRepository.instance.findMany({ where: { connectionStatus: 'close' } }); + let tempInstances = 0; - auths.forEach((auth) => { - if (collections.find((coll) => coll.namespace.replace(/^[\w-]+\./, '') === auth._id)) { - return; - } + instancesClosed.forEach((instance) => { tempInstances++; - this.eventEmitter.emit('remove.instance', auth._id, 'inner'); + this.eventEmitter.emit('remove.instance', instance.id, 'inner'); }); this.logger.verbose('Temp instances removed: ' + tempInstances); } diff --git a/src/api/services/proxy.service.ts b/src/api/services/proxy.service.ts index f86933c1..b2f70fc1 100644 --- a/src/api/services/proxy.service.ts +++ b/src/api/services/proxy.service.ts @@ -1,7 +1,8 @@ +import { Proxy } from '@prisma/client'; + import { Logger } from '../../config/logger.config'; import { InstanceDto } from '../dto/instance.dto'; import { ProxyDto } from '../dto/proxy.dto'; -import { ProxyRaw } from '../models'; import { WAMonitoringService } from './monitor.service'; export class ProxyService { @@ -16,7 +17,7 @@ export class ProxyService { return { proxy: { ...instance, proxy: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find proxy: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findProxy(); @@ -27,7 +28,7 @@ export class ProxyService { return result; } catch (error) { - return { enabled: false, proxy: null }; + return null; } } } diff --git a/src/api/services/settings.service.ts b/src/api/services/settings.service.ts index 741a2cbc..035a988b 100644 --- a/src/api/services/settings.service.ts +++ b/src/api/services/settings.service.ts @@ -26,7 +26,7 @@ export class SettingsService { return result; } catch (error) { - return { reject_call: false, msg_call: '', groups_ignore: true }; + return null; } } } diff --git a/src/api/services/webhook.service.ts b/src/api/services/webhook.service.ts index 810ce96d..9494c3ad 100644 --- a/src/api/services/webhook.service.ts +++ b/src/api/services/webhook.service.ts @@ -1,3 +1,5 @@ +import { Webhook } from '@prisma/client'; + import { Logger } from '../../config/logger.config'; import { InstanceDto } from '../dto/instance.dto'; import { WebhookDto } from '../dto/webhook.dto'; @@ -15,7 +17,7 @@ export class WebhookService { return { webhook: { ...instance, webhook: data } }; } - public async find(instance: InstanceDto): Promise { + public async find(instance: InstanceDto): Promise { try { this.logger.verbose('find webhook: ' + instance.instanceName); const result = await this.waMonitor.waInstances[instance.instanceName].findWebhook(); @@ -26,7 +28,7 @@ export class WebhookService { return result; } catch (error) { - return { enabled: false, url: '', events: [], webhook_by_events: false, webhook_base64: false }; + return null; } } } diff --git a/src/api/types/wa.types.ts b/src/api/types/wa.types.ts index c9ffc5d9..76a3e992 100644 --- a/src/api/types/wa.types.ts +++ b/src/api/types/wa.types.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/no-namespace */ +import { TypebotSession } from '@prisma/client'; +import { JsonValue } from '@prisma/client/runtime/library'; import { AuthenticationState, WAConnectionState } from '@whiskeysockets/baileys'; export enum Events { @@ -41,6 +43,7 @@ export declare namespace wa { code?: string; }; export type Instance = { + id?: string; qrcode?: QrCode; pairingCode?: string; authState?: { state: AuthenticationState; saveCreds: () => void }; @@ -53,50 +56,51 @@ export declare namespace wa { export type LocalWebHook = { enabled?: boolean; url?: string; - events?: string[]; - webhook_by_events?: boolean; - webhook_base64?: boolean; + events?: JsonValue; + webhookByEvents?: boolean; + webhookBase64?: boolean; }; export type LocalChatwoot = { enabled?: boolean; - account_id?: string; + accountId?: string; token?: string; url?: string; - name_inbox?: string; - sign_msg?: boolean; + nameInbox?: string; + signMsg?: boolean; + signDelimiter?: string; number?: string; - reopen_conversation?: boolean; - conversation_pending?: boolean; - merge_brazil_contacts?: boolean; - import_contacts?: boolean; - import_messages?: boolean; - days_limit_import_messages?: number; + reopenConversation?: boolean; + conversationPending?: boolean; + mergeBrazilContacts?: boolean; + importContacts?: boolean; + importMessages?: boolean; + daysLimitImportMessages?: number; }; export type LocalSettings = { - reject_call?: boolean; - msg_call?: string; - groups_ignore?: boolean; - always_online?: boolean; - read_messages?: boolean; - read_status?: boolean; - sync_full_history?: boolean; + rejectCall?: boolean; + msgCall?: string; + groupsIgnore?: boolean; + alwaysOnline?: boolean; + readMessages?: boolean; + readStatus?: boolean; + syncFullHistory?: boolean; }; export type LocalWebsocket = { enabled?: boolean; - events?: string[]; + events?: JsonValue; }; export type LocalRabbitmq = { enabled?: boolean; - events?: string[]; + events?: JsonValue; }; export type LocalSqs = { enabled?: boolean; - events?: string[]; + events?: JsonValue; }; type Session = { @@ -110,11 +114,11 @@ export declare namespace wa { url?: string; typebot?: string; expire?: number; - keyword_finish?: string; - delay_message?: number; - unknown_message?: string; - listening_from_me?: boolean; - sessions?: Session[]; + keywordFinish?: string; + delayMessage?: number; + unknownMessage?: string; + listeningFromMe?: boolean; + sessions?: TypebotSession[]; }; type Proxy = { diff --git a/src/config/env.config.ts b/src/config/env.config.ts index d878d03a..793e6a63 100644 --- a/src/config/env.config.ts +++ b/src/config/env.config.ts @@ -301,7 +301,7 @@ export class ConfigService { DB_PREFIX_NAME: process.env.DATABASE_CONNECTION_DB_PREFIX_NAME || 'evolution', }, ENABLED: process.env?.DATABASE_ENABLED === 'true', - PROVIDER: process.env.DATABASE_PROVIDER || 'mongodb', + PROVIDER: process.env.DATABASE_PROVIDER || 'postgresql', SAVE_DATA: { INSTANCE: process.env?.DATABASE_SAVE_DATA_INSTANCE === 'true', NEW_MESSAGE: process.env?.DATABASE_SAVE_DATA_NEW_MESSAGE === 'true', diff --git a/src/libs/mongodb.connect.ts b/src/libs/mongodb.connect.ts deleted file mode 100644 index 539b4d96..00000000 --- a/src/libs/mongodb.connect.ts +++ /dev/null @@ -1,25 +0,0 @@ -import mongoose from 'mongoose'; - -import { configService, Database } from '../config/env.config'; -import { Logger } from '../config/logger.config'; - -const logger = new Logger('MongoDB'); - -const db = configService.get('DATABASE'); -export const mongodbServer = (() => { - if (db.ENABLED && db.PROVIDER === 'mongodb') { - logger.verbose('connecting'); - const dbs = mongoose.createConnection(db.CONNECTION.URI, { - dbName: db.CONNECTION.DB_PREFIX_NAME + '-whatsapp-api', - }); - logger.verbose('connected in ' + db.CONNECTION.URI); - logger.info('ON - dbName: ' + dbs['$dbName']); - - process.on('beforeExit', () => { - logger.verbose('instance destroyed'); - mongodbServer.destroy(true, (error) => logger.error(error)); - }); - - return dbs; - } -})(); diff --git a/src/libs/prisma.connect.ts b/src/libs/prisma.connect.ts index 0ac126bd..2bf72571 100644 --- a/src/libs/prisma.connect.ts +++ b/src/libs/prisma.connect.ts @@ -3,11 +3,12 @@ import { PrismaClient } from '@prisma/client'; import { configService, Database } from '../config/env.config'; import { Logger } from '../config/logger.config'; -const logger = new Logger('MongoDB'); +const logger = new Logger('Prisma'); const db = configService.get('DATABASE'); + export const prismaServer = (() => { - if (db.ENABLED && db.PROVIDER !== 'mongodb') { + if (db.ENABLED) { logger.verbose('connecting'); const db = new PrismaClient(); diff --git a/src/main.ts b/src/main.ts index dd7322b0..4bd259ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,6 +10,7 @@ import { initAMQP, initGlobalQueues } from './api/integrations/rabbitmq/libs/amq import { initSQS } from './api/integrations/sqs/libs/sqs.server'; import { initIO } from './api/integrations/websocket/libs/socket.server'; import { ProviderFiles } from './api/provider/sessions'; +import { PrismaRepository } from './api/repository/repository.service'; import { HttpStatus, router } from './api/routes/index.router'; import { waMonitor } from './api/server.module'; import { Auth, configService, Cors, HttpServer, Rabbitmq, Sqs, Webhook } from './config/env.config'; @@ -29,6 +30,8 @@ async function bootstrap() { const providerFiles = new ProviderFiles(configService); await providerFiles.onModuleInit(); logger.info('Provider:Files - ON'); + const prismaRepository = new PrismaRepository(configService); + await prismaRepository.onModuleInit(); app.use( cors({ diff --git a/src/utils/use-multi-file-auth-state-mongodb.ts b/src/utils/use-multi-file-auth-state-mongodb.ts deleted file mode 100644 index 2bd2289b..00000000 --- a/src/utils/use-multi-file-auth-state-mongodb.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { - AuthenticationCreds, - AuthenticationState, - BufferJSON, - initAuthCreds, - proto, - SignalDataTypeMap, -} from '@whiskeysockets/baileys'; - -import { configService, Database } from '../config/env.config'; -import { Logger } from '../config/logger.config'; -import { mongodbServer } from '../libs/mongodb.connect'; - -export async function useMultiFileAuthStateMongoDb( - coll: string, -): Promise<{ state: AuthenticationState; saveCreds: () => Promise }> { - const logger = new Logger(useMultiFileAuthStateMongoDb.name); - - const client = mongodbServer.getClient(); - - const collection = client - .db(configService.get('DATABASE').CONNECTION.DB_PREFIX_NAME + '-instances') - .collection(coll); - - const writeData = async (data: any, key: string): Promise => { - try { - await client.connect(); - let msgParsed = JSON.parse(JSON.stringify(data, BufferJSON.replacer)); - if (Array.isArray(msgParsed)) { - msgParsed = { - _id: key, - content_array: msgParsed, - }; - } - return await collection.replaceOne({ _id: key }, msgParsed, { - upsert: true, - }); - } catch (error) { - logger.error(error); - } - }; - - const readData = async (key: string): Promise => { - try { - await client.connect(); - let data = (await collection.findOne({ _id: key })) as any; - if (data?.content_array) { - data = data.content_array; - } - const creds = JSON.stringify(data); - return JSON.parse(creds, BufferJSON.reviver); - } catch (error) { - logger.error(error); - } - }; - - const removeData = async (key: string) => { - try { - await client.connect(); - return await collection.deleteOne({ _id: key }); - } catch (error) { - logger.error(error); - } - }; - - const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds(); - - return { - state: { - creds, - keys: { - get: async (type, ids: string[]) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const data: { [_: string]: SignalDataTypeMap[type] } = {}; - await Promise.all( - ids.map(async (id) => { - let value = await readData(`${type}-${id}`); - if (type === 'app-state-sync-key' && value) { - value = proto.Message.AppStateSyncKeyData.fromObject(value); - } - - data[id] = value; - }), - ); - - return data; - }, - set: async (data: any) => { - const tasks: Promise[] = []; - for (const category in data) { - for (const id in data[category]) { - const value = data[category][id]; - const key = `${category}-${id}`; - tasks.push(value ? writeData(value, key) : removeData(key)); - } - } - - await Promise.all(tasks); - }, - }, - }, - saveCreds: async () => { - return await writeData(creds, 'creds'); - }, - }; -} diff --git a/src/utils/use-multi-file-auth-state-prisma.ts b/src/utils/use-multi-file-auth-state-prisma.ts index 39170696..17bcb2ba 100644 --- a/src/utils/use-multi-file-auth-state-prisma.ts +++ b/src/utils/use-multi-file-auth-state-prisma.ts @@ -1,9 +1,11 @@ -import { PrismaClient } from '@prisma/client'; import { BufferJSON, initAuthCreds, WAProto as proto } from '@whiskeysockets/baileys'; import fs from 'fs/promises'; import path from 'path'; -const prisma = new PrismaClient(); +import { INSTANCE_DIR } from '../config/path.config'; +import { prismaServer } from '../libs/prisma.connect'; + +const prisma = prismaServer; const fixFileName = (file) => { if (!file) { @@ -28,8 +30,16 @@ export async function saveKey(sessionId, keyJson) { const jaExiste = await keyExists(sessionId); try { if (!jaExiste) - return await prisma.session.create({ data: { sessionId: sessionId, creds: JSON.stringify(keyJson) } as any }); - await prisma.session.update({ where: { sessionId: sessionId }, data: { creds: JSON.stringify(keyJson) } }); + return await prisma.session.create({ + data: { + sessionId: sessionId, + creds: JSON.stringify(keyJson), + }, + }); + await prisma.session.update({ + where: { sessionId: sessionId }, + data: { creds: JSON.stringify(keyJson) }, + }); } catch (error) { console.log(`${error}`); return null; @@ -68,7 +78,7 @@ async function fileExists(file) { } export default async function useMultiFileAuthStatePrisma(sessionId) { - const localFolder = path.join(process.cwd(), 'sessions', sessionId); + const localFolder = path.join(INSTANCE_DIR, sessionId); const localFile = (key) => path.join(localFolder, fixFileName(key) + '.json'); await fs.mkdir(localFolder, { recursive: true });