Skip to content

Conversation

@leandrosroc
Copy link
Contributor

@leandrosroc leandrosroc commented Apr 21, 2025

fix(api): modifica fetchChats para trazer mensagens de contatos não salvos

  • Muda tabela base da consulta de Contact para Message
  • Altera INNER JOIN para LEFT JOIN entre Message e Contact
  • Usa COALESCE para campos que podem estar vazios
  • Adiciona flag isSaved para identificar contatos salvos/não salvos
  • Preserva toda funcionalidade de filtros existente

Resolve issue #1376

Summary by Sourcery

Modify the fetchChats method to retrieve messages from unsaved contacts by changing the base query table and adjusting join conditions

Bug Fixes:

  • Fixed issue with fetching messages from unsaved contacts by modifying the database query logic

Enhancements:

  • Improved database query to support retrieving messages from contacts not saved in the contact list
  • Added flag to identify saved and unsaved contacts

joaosouz4dev and others added 30 commits December 27, 2024 10:40
- Update Docker image repository to evoapicloud/evolution-api
- Modify contact email to contato@evolution-api.com
- Update Docker Compose, Dockerfile, and workflow files
- Add Docker image badge to README
- Include additional content creator in README
- Implement message deduplication cache in Baileys service
…leys service

- Refactor edited message detection logic
- Prevent duplicate message processing for edited messages
- Optimize message key caching mechanism
…{baseUrl}}/chat/fetchCatalogs' and '{{baseUrl}}/chat/fetchCollections'
Refactor edit and delete message functionality in BaileyStartupService
Feat: Adicionei suporte para obter o Catálogos de Produtos e as Coleções de Produtos para a versão 2.2.3
- Added NATS package to dependencies
- Created Prisma schema models for NATS configuration
- Implemented NATS controller, router, and event management
- Updated instance controller and event manager to support NATS
- Added NATS configuration options in environment configuration
- Included NATS events in instance validation schema
…gos de produtos e Coleções evitando alterações desnecessárias em arquivos do repositório
Adicionado suporte para obter Catálogos e Coleções no WhatsApp Business
feat: notconvertsticket for animated stickers
Fix instance creation on v2.2.3
…-location

feat: add message location support whatsapp meta
Fix audio send duplicate from chatwoot.
…twoot

fix: chatwoot csat creating new conversation in another language
ygorsantana and others added 26 commits February 13, 2025 22:35
Refactor Editing Message events and update message handler
…se-message

fix: change mediaId optional chaining and list response message text obtain
…fix/missing-wavoipToken-mysql

hotfix(migration): add missing wavoipToken column in MySQL schema
- Implement dynamic queue creation based on enabled events - Add method to list existing queues for an instance - Improve error handling and logging for SQS operations - Remove unused queue removal methods - Update set method to handle queue creation/deletion on event changes - Add comments for future feature of forced queue deletion
…avoipToken-create

🐛 Corrige problema na API relacionado à migration. Fixes EvolutionAPI#1234
✨ Feat: Remover a reação de uma mensagem.
fix: Refactor SQS controller to correct bug in sqs events by instance
…useless

Fix: Expiration being useless on awaitUser false
- Create Nats table in PostgreSQL migration
- Disable message recovery logic in Baileys service
- Remove console log in instance creation route
- Add robust authentication mechanism for WebSocket connections
- Implement API key validation for both instance-specific and global tokens
- Improve connection request handling with detailed logging
- Refactor WebSocket controller to support more secure connection validation
fix: adjusting cloud api send audio and video
Corrige validação de URL para permitir localhost e endereços IP
Add eventos referente a instancia que estavam faltando
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Apr 21, 2025

Reviewer's Guide by Sourcery

This pull request includes several bug fixes and new features. It fixes an issue where messages from unsaved contacts were not being fetched, implements message editing functionality, adds catalog and collection fetching for business accounts, implements SQS and NATS event queue management, enhances Websocket authentication and security, improves Webhook URL validation, fixes a bug where Typebot was not processing messages correctly, and adds support for location messages in Business API.

Sequence diagram for fetching catalog

sequenceDiagram
    participant Client
    participant BaileysService
    participant WhatsApp

    Client->>BaileysService: fetchCatalog(instanceName, data)
    activate BaileysService
    BaileysService->>WhatsApp: client.getCatalog(jid, limit, cursor)
    activate WhatsApp
    WhatsApp-->>BaileysService: Returns catalog data
    deactivate WhatsApp
    BaileysService-->>Client: Returns catalog data
    deactivate BaileysService
Loading

Sequence diagram for fetching collections

sequenceDiagram
    participant Client
    participant BaileysService
    participant WhatsApp

    Client->>BaileysService: fetchCollections(instanceName, data)
    activate BaileysService
    BaileysService->>WhatsApp: client.getCollections(jid, limit)
    activate WhatsApp
    WhatsApp-->>BaileysService: Returns collections data
    deactivate WhatsApp
    BaileysService-->>Client: Returns collections data
    deactivate BaileysService
Loading

Sequence diagram for SQS event creation

sequenceDiagram
    participant Client
    participant SqsController
    participant PrismaRepository
    participant AWS SQS

    Client->>SqsController: set(instanceName, data)
    activate SqsController
    SqsController->>SqsController: saveQueues(instanceName, events, enable)
    activate SqsController
    loop for each event in events
      SqsController->>AWS SQS: createQueue(queueName)
      activate AWS SQS
      AWS SQS-->>SqsController: Returns QueueUrl
      deactivate AWS SQS
    end
    SqsController->>PrismaRepository: upsert(payload)
    activate PrismaRepository
    PrismaRepository-->>SqsController: Returns Sqs data
    deactivate PrismaRepository
    SqsController-->>Client: Returns Sqs data
    deactivate SqsController
    deactivate SqsController
Loading

File-Level Changes

Change Details Files
Modified the fetchChats function to retrieve messages from unsaved contacts.
  • Changed the base table of the query from Contact to Message.
  • Changed the INNER JOIN to a LEFT JOIN between Message and Contact.
  • Used COALESCE for fields that may be empty.
  • Added an isSaved flag to identify saved/unsaved contacts.
  • Preserved all existing filter functionality.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Implemented message editing functionality.
  • Added logic to handle edited messages, updating the message in the database and creating a message update record.
  • Implemented checks to prevent editing messages from others, deleted messages, or messages older than 15 minutes.
  • Added a webhook event for message edits.
  • Added cache to avoid duplicate messages.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Added catalog and collection fetching for business accounts.
  • Implemented fetchCatalog and fetchCollections functions to retrieve product catalogs and collections from WhatsApp Business accounts.
  • Added logic to handle pagination and retrieve all products/collections.
  • Added new DTOs for business catalog and collections.
  • Added new routes for business catalog and collections.
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
src/api/dto/business.dto.ts
src/api/controllers/business.controller.ts
src/api/routes/business.router.ts
src/validate/business.schema.ts
Implemented SQS event queue management.
  • Added functionality to create and remove SQS queues based on instance events.
  • Implemented logic to save SQS queue configurations to the database.
  • Added a method to list queues by instance.
src/api/integrations/event/sqs/sqs.controller.ts
src/config/env.config.ts
src/validate/instance.schema.ts
Implemented NATS event queue management.
  • Added NATS integration for event streaming.
  • Implemented logic to publish events to NATS topics.
  • Added functionality to initialize global subscriptions for all events.
  • Added NATS configuration to the environment variables.
  • Added NATS DTOs and routes.
src/api/integrations/event/nats/nats.controller.ts
src/config/env.config.ts
src/validate/instance.schema.ts
src/api/integrations/event/nats/nats.router.ts
src/api/integrations/event/event.manager.ts
Enhanced Websocket authentication and security.
  • Implemented API key authentication for WebSocket connections.
  • Added logic to verify API keys against instance tokens or a global token.
  • Improved error handling and logging for authentication failures.
src/api/integrations/event/websocket/websocket.controller.ts
Improved Webhook URL validation.
  • Updated the Webhook URL validation to allow only http or https protocols.
  • Updated the Webhook URL validation to use a regex.
src/api/integrations/event/webhook/webhook.controller.ts
Fixed a bug where Typebot was not processing messages correctly.
  • Fixed a bug where Typebot was not processing messages correctly when awaitUser was false.
src/api/integrations/chatbot/typebot/services/typebot.service.ts
src/api/integrations/chatbot/typebot/controllers/typebot.controller.ts
Added support for location messages in Business API.
  • Added support for location messages in Business API.
  • Added messageLocationJson method to handle location messages.
src/api/integrations/channel/meta/whatsapp.business.service.ts
Improved reaction message validation.
  • Updated the reaction message validation to allow only a single emoji or an empty string.
src/api/controllers/sendMessage.controller.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @leandrosroc - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a description of the purpose and usage of the baileysCache to improve readability.
  • The addition of NATS is a significant change; ensure that the configuration and usage are well-documented for operators.
Here's what I looked at during the review
  • 🟡 General issues: 1 issue found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 2 issues found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

cors: {
origin: this.cors,
cors: { origin: this.cors },
allowRequest: async (req, callback) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Review URL parsing in allowRequest callback.

The use of 'new URL(req.url || '', 'http://localhost')' works for many cases, but ensure that all incoming requests have a format that can be correctly parsed. It might be useful to have additional checks or to log malformed URLs to aid debugging.

Suggested implementation:

        } catch (error) {
          Logger.error('Malformed URL in allowRequest callback', { error, url: req.url });
          return callback(new Error('Malformed URL'));
        }

Ensure that the Logger from '@config/logger.config' is properly configured and imported.
If other parts of your error handling strategy require modifications to accommodate the new error handling, please update them accordingly.

const editedMessage =
received?.message?.protocolMessage || received?.message?.editedMessage?.message?.protocolMessage;

if (received.message?.protocolMessage?.editedMessage || received.message?.editedMessage?.message) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider extracting the duplicate message caching and edited message handling logic into helper functions to improve readability and reduce nesting complexity within the code.

Consider breaking out repeated clustered logic into dedicated helper functions to improve readability and reduce nesting. For example, you can extract the duplicate message caching functionality and the edited message handling logic:

1. Cache Check Helper

Extract the cache check into a single helper:

// cacheHelpers.ts
export async function isCachedMessage(cache: CacheStore, key: string, logger: Logger): Promise<boolean> {
  const cached = await cache.get(key);
  if (cached) {
    logger.info(`Message duplicated ignored: ${key}`);
    return true;
  }
  await cache.set(key, true, 30 * 60);
  return false;
}

Then in your main code:

import { isCachedMessage } from './cacheHelpers';

const messageKey = `${this.instance.id}_${received.key.id}`;
if (await isCachedMessage(this.baileysCache, messageKey, this.logger) && !editedMessage) {
  continue;
}

2. Edited Message Handler

Consolidate the complicated edited message processing into a dedicated helper:

// messageHelpers.ts
export async function handleEditedMessage(
  editedMessage: any,
  chatwootService: any,
  configService: any,
  localChatwoot: any,
  instance: any,
  sendDataWebhook: Function,
  prismaRepository: any,
  getMessage: Function
) {
  if (configService.get('CHATWOOT').ENABLED && localChatwoot?.enabled) {
    chatwootService.eventWhatsapp('messages.edit', {
      instanceName: instance.name,
      instanceId: instance.id,
    }, editedMessage);
  }
  await sendDataWebhook('MESSAGES_EDITED', editedMessage);

  const oldMessage = await getMessage(editedMessage.key, true);
  if (oldMessage?.id) {
    await prismaRepository.message.update({
      where: { id: oldMessage.id },
      data: {
        message: editedMessage.editedMessage,
        messageTimestamp: Number(editedMessage.timestampMs),
        status: 'EDITED',
      },
    });
    await prismaRepository.messageUpdate.create({
      data: {
        fromMe: editedMessage.key.fromMe,
        keyId: editedMessage.key.id,
        remoteJid: editedMessage.key.remoteJid,
        status: 'EDITED',
        instanceId: instance.id,
        messageId: oldMessage.id,
      },
    });
  }
}

And then simplify the main block:

const editedMessageValue = received?.message?.protocolMessage || 
                           received?.message?.editedMessage?.message?.protocolMessage;
if (received.message?.protocolMessage?.editedMessage || 
    received.message?.editedMessage?.message) {
  if (editedMessageValue) {
    await handleEditedMessage(
      editedMessageValue,
      this.chatwootService,
      this.configService,
      this.localChatwoot,
      this.instance,
      this.sendDataWebhook.bind(this),
      this.prismaRepository,
      this.getMessage.bind(this)
    );
  }
}

These steps refactor the nested logic into focused helper functions without reverting functionality, improving maintainability.


public get channel(): SQS {
return this.sqs;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring repeated patterns in helper methods into dedicated utility functions to reduce complexity and improve readability by reducing nested control flows and duplicated code.

The new helper methods are functionally solid but have complexity due to nested control flows. Consider refactoring the repeated patterns (like creating or extracting queue names and handling SQS commands) into dedicated utility functions. For example, extract the logic to build normalized queue names and abstract the try/catch for SQS commands.

Suggested Refactor:

  1. Extract Queue Name Construction

    // utils/sqsHelpers.ts
    export const getQueueName = (instanceName: string, event: string): string => {
      return `${instanceName}_${event.toLowerCase()}.fifo`;
    };
  2. Abstract SQS Command Execution

    // utils/sqsHelpers.ts
    import { SQS } from '@aws-sdk/client-sqs';
    
    export const executeSqsCommand = async (
      sqs: SQS,
      command: any,
      onSuccess: (data: any) => void,
      onError: (err: any) => void
    ): Promise<void> => {
      try {
        const data = await sqs.send(command);
        onSuccess(data);
      } catch (err: any) {
        onError(err);
      }
    };
  3. Refactor saveQueues Using the Helpers

    import { getQueueName, executeSqsCommand } from '../utils/sqsHelpers';
    import { CreateQueueCommand } from '@aws-sdk/client-sqs';
    
    private async saveQueues(instanceName: string, events: string[], enable: boolean) {
      if (enable) {
        const eventsFound = await this.listQueuesByInstance(instanceName);
        for (const event of events) {
          const normalizedEvent = event.toLowerCase();
          if (eventsFound.includes(normalizedEvent)) {
            this.logger.info(`Queue for event "${normalizedEvent}" already exists. Skipping creation.`);
            continue;
          }
          const queueName = getQueueName(instanceName, normalizedEvent);
          const createCommand = new CreateQueueCommand({
            QueueName: queueName,
            Attributes: { FifoQueue: 'true' },
          });
          await executeSqsCommand(
            this.sqs,
            createCommand,
            (data) => this.logger.info(`Queue ${queueName} created: ${data.QueueUrl}`),
            (err) => this.logger.error(`Error creating queue ${queueName}: ${err.message}`)
          );
        }
      }
    }

Applying similar patterns to initQueues and removeQueues will reduce nesting and duplicate code, hence lowering cognitive load while keeping the functionality intact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.