8000 chore: change baileys contact name preferences by CayoPOliveira · Pull Request #30 · fazer-ai/chatwoot · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

chore: change baileys contact name preferences #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

CayoPOliveira
Copy link
Collaborator
@CayoPOliveira CayoPOliveira commented Apr 24, 2025

Pull Request Template

Description

Please include a summary of the change and issue(s) fixed. Also, mention relevant motivation, context, and any dependencies that this change requires.
Fixes # (issue)

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality not to work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented on my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

This change is Reviewable

Summary by CodeRabbit

  • New Features
    • Added support for receiving and sending various media message types (image, video, file, audio, sticker) in WhatsApp conversations.
    • Improved error handling and user notifications for unsupported message types, with clear instructions in multiple languages.
  • Bug Fixes
    • Updated HTTP response codes for certain WhatsApp webhook errors to provide more accurate feedback.
  • Refactor
    • Enhanced contact name resolution, prioritizing verified business names when available.
    • Modularized and streamlined message processing for better maintainability.
  • Tests
    • Expanded test coverage for media message handling, unsupported message scenarios, and contact name updates.
  • Documentation
    • Added and updated localized error messages in English and Portuguese.

@CayoPOliveira CayoPOliveira added enhancement New feature or request review needed labels Apr 24, 2025
@CayoPOliveira CayoPOliveira self-assigned this 8000 Apr 24, 2025
@Copilot Copilot AI review requested due to automatic review settings April 24, 2025 22:24
Copy link
coderabbitai bot commented Apr 24, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This update refactors and extends the WhatsApp message handling pipeline. The IncomingMessageBaileysService now modularizes contact name extraction, supports additional media message types (image, video, file, audio, sticker), and improves unsupported message handling. The WhatsappBaileysService is refactored to handle sending attachments and introduces robust error handling for failed sends. Localization files are updated with new error messages for unsupported content. Test suites are expanded to cover the new media types, contact name resolution logic, and error scenarios. The HTTP response for missing messages in the webhooks controller is changed from 400 to 404.

Changes

File(s) Change Summary
app/services/whatsapp/incoming_message_baileys_service.rb Refactored contact extraction and name resolution, added support for multiple media types, unified message creation, improved handling of unsupported messages, and introduced helper methods for media attachment and content extraction.
app/services/whatsapp/providers/whatsapp_baileys_service.rb Refactored message sending logic to handle attachments, introduced error handling for failed sends, added methods for sending attachments and text messages, and added a new exception class for send failures.
app/controllers/webhooks/whatsapp_controller.rb Changed HTTP response for MessageNotFoundError from 400 (bad request) to 404 (not found).
config/locales/en.yml, config/locales/pt_BR.yml Added new localized error messages for unsupported WhatsApp messages (viewing and sending), with instructions for users. Minor formatting change in integration descriptions.
spec/services/whatsapp/incoming_message_baileys_service_spec.rb Added tests for unsupported message types, contact name resolution (including precedence rules), and handling of image, video, file, audio, and sticker messages with media attachment validation.
spec/services/whatsapp/providers/whatsapp_baileys_service_spec.rb Updated and extended tests for unsupported message types to validate message status and content after error handling during send attempts.
spec/models/attachment_spec.rb Extended attachment metadata tests to verify filename and content type preservation for file attachments.

Sequence Diagram(s)

sequenceDiagram
    participant WebhookController
    participant IncomingMessageBaileysService
    participant Message
    participant Attachment

    WebhookController->>IncomingMessageBaileysService: perform_sync(payload)
    IncomingMessageBaileysService->>IncomingMessageBaileysService: set_contact(payload)
    IncomingMessageBaileysService->>IncomingMessageBaileysService: handle_create_message(payload)
    alt Supported Media Type
        IncomingMessageBaileysService->>Message: create_message(type, content)
        IncomingMessageBaileysService->>Attachment: attach_media(base64, type, filename)
        Attachment-->>Message: link attachment
    else Unsupported Type
        IncomingMessageBaileysService->>Message: create_unsupported_message()
    end
Loading
sequenceDiagram
    participant WhatsappBaileysService
    participant Message

    WhatsappBaileysService->>Message: send_message(phone_number, message)
    alt Message has attachment
        WhatsappBaileysService->>WhatsappBaileysService: send_attachment_message()
        alt Send fails
            WhatsappBaileysService->>Message: update status to 'failed'
            WhatsappBaileysService->>WhatsappBaileysService: raise MessageSendFailed
        end
    else No attachment
        alt Content blank
            WhatsappBaileysService->>Message: update status to 'failed'
            WhatsappBaileysService->>WhatsappBaileysService: raise MessageContentTypeNotSupported
        else
            WhatsappBaileysService->>WhatsappBaileysService: send_text_message()
            alt Send fails
                WhatsappBaileysService->>Message: update status to 'failed'
                WhatsappBaileysService->>WhatsappBaileysService: raise MessageSendFailed
            end
        end
    end
Loading

Possibly related PRs

Suggested labels

approved for merge

Poem

A rabbit hopped through WhatsApp's code,
Now media flows down every road!
Attachments stick, and names are neat,
Unsupported? We won't repeat!
New tests abound, translations bloom,
This patch brings spring to every room.
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors and updates the Baileys WhatsApp integration with improvements to message handling, contact name updates, and error management. Key changes include:

  • Refactoring tests for unsupported messages, outgoing and incoming message scenarios.
  • Updating error handling and message sending logic in the Baileys service.
  • Adjusting locale files and attachment tests for improved consistency and error messages.

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
spec/services/whatsapp/providers/whatsapp_baileys_service_spec.rb Updates test context and assertions for unsupported message types and status updates.
spec/services/whatsapp/incoming_message_baileys_service_spec.rb Adds multiple tests covering alerts, contact name updates, and media attachment scenarios.
spec/models/attachment_spec.rb Adds expectations for file metadata consistency.
config/locales/pt_BR.yml, config/locales/en.yml Updates error message texts and quote styles.
app/services/whatsapp/providers/whatsapp_baileys_service.rb Refactors message sending logic, adds attachment handling and new error class.
app/services/whatsapp/incoming_message_baileys_service.rb Refactors contact setting and message creation logic (including media attachment processing).
app/controllers/webhooks/whatsapp_controller.rb Updates HTTP status response for message not found.
Comments suppressed due to low confidence (1)

app/services/whatsapp/incoming_message_baileys_service.rb:170

  • The method name 'create_unsuported_message' appears to be misspelled. Consider renaming it to 'create_unsupported_message' for clarity and consistency.
def create_unsuported_message

@@ -164,6 +164,18 @@
}
end

it 'create an alert of unsupported message' do
Copy link
Preview
Copilot AI Apr 24, 2025

Choose a reason for hiding this comment

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

[nitpick] Consider updating the test description to 'creates an alert of unsupported message' for proper grammar.

Suggested change
it 'create an alert of unsupported message' do
it 'creates an alert of unsupported message' do

Copilot uses AI. Check for mistakes.

Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🔭 Outside diff range comments (1)
app/services/whatsapp/incoming_message_baileys_service.rb (1)

67-78: 🛠️ Refactor suggestion

Avoid overwriting saved contact names with an empty string
contact_name can legitimately return '' when neither verifiedBizName nor pushName is present.
Persisting that blank string will erase an existing, useful name and force every subsequent message to keep the record blank.

-@contact.update!(name: push_name) if @contact.name != push_name
+if push_name.present? && @contact.name != push_name
+  @contact.update!(name: push_name)
+end
♻️ Duplicate comments (1)
app/services/whatsapp/incoming_message_baileys_service.rb (1)

170-177: Align method name with corrected caller
After fixing the typo in the previous comment, please rename the definition as well to keep the codebase coherent.

-def create_unsuported_message
+def create_unsupported_message
🧹 Nitpick comments (6)
spec/services/whatsapp/incoming_message_baileys_service_spec.rb (2)

359-413: Consider replacing gigantic Base-64 literals with fixture helpers

Long in-line strings (hundreds of KB) bloat the spec file, impede diff readability and slow editors/CI linters.
Store them under spec/fixtures/files/… and read with file_fixture('sample.png').binread (Rails ≥ 5.2) or Rails.root.join('spec/fixtures', 'sample.png').binread.
You still get deterministic tests while keeping the spec concise.

No functional change, purely maintainability.


497-510: Assertion duplicates previous coverage – verify at most once per media-type

Each media-type block (image/video/file/…) repeats the same set of expectations (be_present, file_type, filename, content_type).
Extract a shared example and drive with table-style data to cut spec size in half and reduce future drift.

Example outline:

shared_examples 'media attachment' do |type:, mime:, filename: nil|
  it "stores #{type} correctly" do
    subject.perform
    att = inbox.conversations.last.messages.last.attachments.last
    expect(att.file_type).to eq(type)
    expect(att.file.content_type).to eq(mime)
    expect(att.file.filename.to_s).to eq(filename) if filename
  end
end

Call via include_examples.

app/services/whatsapp/providers/whatsapp_baileys_service.rb (2)

90-94: Updating channel to close for every MessageSendFailed may be excessive

with_error_handling wraps send_message; any raised error – even a client-side “unsupported content” – triggers handle_channel_error, forcing provider_connection to 'close'.

That is probably intended only for transport/5xx failures.
Differentiate :

rescue MessageContentTypeNotSupported
  raise
rescue StandardError => e
  handle_channel_error
  raise

to avoid unnecessary disconnections.


96-117: Large Base64 encode in memory – potential memory spike

Base64.strict_encode64(@attachment.file.download) loads the entire blob into memory; for 20 MB videos this means 30 MB Ruby string.
If provider supports streaming or multipart upload, switch to Base64.encode_stream. Otherwise, at least guard with a filesize limit and fail gracefully.

app/services/whatsapp/incoming_message_baileys_service.rb (2)

179-202: Large Base64 payloads are decoded in-memory – consider streamable processing
Base64.decode64 loads the entire attachment into RAM. Very large videos or documents will increase memory usage for every webhook worker.

If the Baileys callback can give you a URL (or stream) instead of the inline payload, prefer downloading to a Tempfile. Otherwise at least wrap the decoding in a size guard:

return if attachment_payload.bytesize > 50.megabytes

to prevent worker OOMs.


219-228: message_content returns nil for several handled media types
For 'file', 'audio', and 'sticker' the method returns nil, so their content column will be empty.
If Chatwoot relies on that field for UI placeholders (“sent a sticker”, “sent an audio”), consider adding fallbacks:

when 'audio'
  I18n.t('messages.placeholders.audio')

This will make the timeline clearer to agents.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0eb84d and 5b2ea4d.

📒 Files selected for processing (8)
  • app/controllers/webhooks/whatsapp_controller.rb (1 hunks)
  • app/services/whatsapp/incoming_message_baileys_service.rb (4 hunks)
  • app/services/whatsapp/providers/whatsapp_baileys_service.rb (3 hunks)
  • config/locales/en.yml (1 hunks)
  • config/locales/pt_BR.yml (3 hunks)
  • spec/models/attachment_spec.rb (1 hunks)
  • spec/services/whatsapp/incoming_message_baileys_service_spec.rb (4 hunks)
  • spec/services/whatsapp/providers/whatsapp_baileys_service_spec.rb (1 hunks)
🔇 Additional comments (7)
config/locales/en.yml (1)

40-43: Well-structured localization additions for WhatsApp error messages.

These new error messages provide clear guidance to users when encountering unsupported WhatsApp message types. The messages are appropriately formatted with emoji and markdown styling, maintaining consistency with other error messages in the file.

app/controllers/webhooks/whatsapp_controller.rb (1)

29-29: Improved HTTP status code for message not found errors.

Changing from :bad_request (400) to :not_found (404) is semantically more accurate for this error condition. A 404 status code better represents the case where a resource (message) couldn't be found, rather than indicating a malformed request.

spec/models/attachment_spec.rb (1)

128-130: Enhanced test coverage for file attachment metadata.

The new assertions verify that the filename and content type are correctly preserved on file attachments. This aligns with the broader changes in attachment handling for WhatsApp media messages and ensures metadata integrity throughout the system.

config/locales/pt_BR.yml (3)

26-29: Good addition of Portuguese translations for WhatsApp error messages.

These translations match the new error messages added to the English locale, providing consistent user guidance across languages for unsupported WhatsApp message scenarios.


213-213: Minor formatting change from double to single quotes.

This change maintains consistency in string formatting without altering the content of the description.


222-222: Minor formatting change from double to single quotes.

Similar to the previous change, this ensures consistency in the use of single quotes for string literals throughout the file.

app/services/whatsapp/providers/whatsapp_baileys_service.rb (1)

32-46:

❓ Verification inconclusive

API contract drift – messageContent vs message

Specs (and previous provider version) POST
{ type: 'text', recipient: …, message: 'hello' }.

Recent refactor switched to

messageContent: { text: @message.content }

without adjust 8000 ing tests or documenting the provider-side change.
If the Baileys gateway still expects the old payload, outgoing messages will start failing in production.

Action items

  1. Verify remote API expectation.
  2. Whichever key is correct, update both service and specs consistently.
-        messageContent: { text: @message.content }
+        message: @message.content

(or vice-versa).


🏁 Script executed:

#!/bin/bash
# Inspect send_text_message implementation
rg -n "def send_text_message" -A 20 app/services/whatsapp/providers/whatsapp_baileys_service.rb

# Inspect send_attachment_message implementation
rg -n "def send_attachment_message" -A 20 app/services/whatsapp/providers/whatsapp_baileys_service.rb

# Search for occurrences of messageContent to confirm key usage
rg -n "messageContent" -R .

Length of output: 2042


#!/bin/bash
# Locate any usage of `messageContent` across the repo
rg -n "messageContent" .

# Inspect spec files for expected payload keys
rg -n "type: 'text'" -g "*spec.rb" -C 3
rg -n "message:" -g "*spec.rb" -C 3
rg -n "HTTParty.post" -g "*spec.rb" -C 5

🏁 Script executed:

#!/bin/bash
# Find the spec file for WhatsappBaileysService
fd --type f "whatsapp_baileys_service_spec.rb" spec/

# Inspect tests for HTTParty.post usage in spec files
rg -n "HTTParty.post" -g "spec/**/*.rb" -A 3 -C 3

# Search for messageContent key usage in specs
rg -n "messageContent" -g "spec/**/*.rb" -C 3

# Search for old payload key 'message:' in specs
rg -n "message:" -g "spec/**/*.rb" -C 3

Length of output: 84962


Align WhatsApp payload key between service and specs

The service is posting

body: {
  type: 'text',
  recipient: @phone_number,
  messageContent: { text: @message.content }
}.to_json

but the spec stubs expect

body: {
  type: 'text',
  recipient: test_send_phone_number,
  message: message.content
}.to_json

Before deciding on a fix, please confirm the Baileys gateway’s API contract (does it expect message or messageContent?). Once confirmed, update both the service implementation and all related specs to use the same key.

Locations to update:

  • app/services/whatsapp/providers/whatsapp_baileys_service.rb
    • send_text_message (lines ~124–131)
    • send_attachment_message (lines ~83–87)
  • spec/services/whatsapp/providers/whatsapp_baileys_service_spec.rb
    • bodies at lines ~100, 126, and 200

Example diff if switching to message:

--- a/app/services/whatsapp/providers/whatsapp_baileys_service.rb
+++ b/app/services/whatsapp/providers/whatsapp_baileys_service.rb
@@ -128,7 +128,7 @@ def send_text_message
       body: {
         type: 'text',
         recipient: @phone_number,
-        messageContent: { text: @message.content }
+        message: @message.content
       }.to_json

And similarly for send_attachment_message.

Comment on lines 144 to 190
context 'when message type is not supported' do
it 'updates the message status to failed and raises an error' do
message.update!(content_type: 'sticker')

expect do
service.send_message(test_send_phone_number, message)
end.to raise_error(Whatsapp::Providers::WhatsappBaileysService::MessageContentTypeNotSupported)

message.reload
expect(message.status).to eq('failed')
expect(message.content).to eq(I18n.t('errors.messages.send.unsupported'))
end
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Spec currently fails – mismatch between expectations and implementation

send_message in the service raises MessageContentTypeNotSupported only when the message has no attachments and message.content.blank?.
Here, the test merely mutates content_type to 'sticker', leaving message.content populated.
Execution path therefore falls through to send_text_message, which performs an actual HTTP call (no stub) and will explode with WebMock::NetConnectNotAllowed long before your expectation is evaluated.

Diff showing a minimal test-side fix (set content to nil and stub request) – or drop the exception check and assert the HTTP branch – whichever better matches the new contract:

- message.update!(content_type: 'sticker')
+ message.update!(content_type: 'sticker', content: nil)
+
+ stub_request(:post, "#{whatsapp_channel.provider_config['provider_url']}/connections/#{whatsapp_channel.phone_number}/send-message")
+   .with(
+     headers: stub_headers(whatsapp_channel),
+     body: hash_including(type: 'text')
+   ).to_return(status: 400, body: '', headers: {})

Alternatively, enhance the service to inspect content_type and fail early. Decide once and keep both layers consistent.


Here’s to confirm how send_message handles unsupported content types and whether the spec is out of sync with the implementation:

This will confirm the guard clause around message.content.blank? and attachments, so we can decide whether the test or the service needs updating.


🏁 Script executed:

#!/bin/bash
set -e

# 1. Locate send_message implementation in the WhatsappBaileysService
echo ">>> Finding send_message in app/services/whatsapp/providers"
rg -n "class WhatsappBaileysService" -n app/services/whatsapp/providers || true
rg -n "def send_message" -n app/services/whatsapp/providers || true

# 2. Dump the relevant method body for inspection
FILE=$(rg --files-with-matches "class WhatsappBaileysService" -n app/services/whatsapp/providers | head -1)
START=$(rg -n "def send_message" "$FILE" | cut -d: -f1)
END=$(wc -l < "$FILE")
echo ">>> Showing send_message implementation from $FILE (lines $START to $((START+30)))"
sed -n "${START},$((START+30))p" "$FILE"

Length of output: 1013


Update the spec to clear content and stub the HTTP call

The current test mutates only content_type, so send_message falls through to the real HTTP branch and blows up with WebMock::NetConnectNotAllowed. To exercise the unsupported‐type guard you must both clear content and stub the outbound request.

• File: spec/services/whatsapp/providers/whatsapp_baileys_service_spec.rb
Context: when message type is not supported
– Add content: nil when you update the message
– Stub the POST to the provider URL before calling send_message

Example diff:

   context 'when message type is not supported' do
     it 'updates the message status to failed and raises an error' do
-      message.update!(content_type: 'sticker')
+      message.update!(content_type: 'sticker', content: nil)
+
+      stub_request(:post, "#{whatsapp_channel.provider_config['provider_url']}/connections/#{whatsapp_channel.phone_number}/send-message")
+        .with(
+          headers: stub_headers(whatsapp_channel),
+          body: hash_including(type: 'text')
+        ).to_return(status: 400, body: '', headers: {})
 
       expect do
         service.send_message(test_send_phone_number, message)
       end.to raise_error(Whatsapp::Providers::WhatsappBaileysService::MessageContentTypeNotSupported)
 
       message.reload
       expect(message.status).to eq('failed')
       expect(message.content).to eq(I18n.t('errors.messages.send.unsupported'))
     end

This ensures you hit the “no attachments && blank content” guard without triggering an un-stubbed HTTP call.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
context 'when message type is not supported' do
it 'updates the message status to failed and raises an error' do
message.update!(content_type: 'sticker')
expect do
service.send_message(test_send_phone_number, message)
end.to raise_error(Whatsapp::Providers::WhatsappBaileysService::MessageContentTypeNotSupported)
message.reload
expect(message.status).to eq('failed')
expect(message.content).to eq(I18n.t('errors.messages.send.unsupported'))
end
context 'when message type is not supported' do
it 'updates the message status to failed and raises an error' do
message.update!(content_type: 'sticker', content: nil)
stub_request(:post, "#{whatsapp_channel.provider_config['provider_url']}/connections/#{whatsapp_channel.phone_number}/send-message")
.with(
headers: stub_headers(whatsapp_channel),
body: hash_including(type: 'text')
).to_return(status: 400, body: '', headers: {})
expect do
service.send_message(test_send_phone_number, message)
end.to raise_error(Whatsapp::Providers::WhatsappBaileysService::MessageContentTypeNotSupported)
message.reload
expect(message.status).to eq('failed')
expect(message.content).to eq(I18n.t('errors.messages.send.unsupported'))
end
end

Comment on lines 77 to 88
def send_attachment_message
@attachment = @message.attachments.first

response = HTTParty.post(
"#{provider_url}/connections/#{whatsapp_channel.phone_number}/send-message",
headers: api_headers,
body: {
type: @attachment.file_type == 'file' ? 'document' : @attachment.file_type,
recipient: @phone_number,
messageContent: message_content
}.to_json
)

return response.parsed_response.dig('data', 'key', 'id') if process_response(response)

@message.update!(status: 'failed')
raise MessageSendFailed
end
Copy link
@coderabbitai coderabbitai bot Apr 24, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Only the first attachment is sent – clarify or support multiple

@attachment = @message.attachments.first

If a user attaches two photos in one reply, only the first goes out and the UI shows them all as “sent” – silent data loss.
Either:

  • document this limitation in code & UI, or
  • iterate over attachments and dispatch each.
- @attachment = @message.attachments.first
+ @message.attachments.each do |attachment|
+   @attachment = attachment
+   send_single_attachment! # extract rest of method here
+ end
+ return true

Committable suggestion skipped: line range outside the PR's diff.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually, it is a problem, similar services use only the first attachment, but I can use two approaches:

  • Divide each attachment into multiple messages (however, this generates a problem with the message ID in chatwoot having multiple message IDs in baileys)
  • Limit the maximum number of attachments to 1 for baileys, both in front-end and back-end

@gabrieljablonski help

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 96 to 109
def handle_create_message
case message_type
when 'text'
create_text_message
create_message
when 'image', 'file', 'video', 'audio', 'sticker'
create_message
attach_media
else
create_unsuported_message
Rails.logger.warn "Baileys unsupported message type: #{message_type}"
end
end
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Spelling & coverage of video_note lead to unreachable branch

  1. create_unsuported_message is miss-spelled (missing the second “p”).
  2. message_type can return video_note, yet that branch falls through to the unsupported path, even though media is present and should be processed like a video.
-when 'image', 'file', 'video', 'audio', 'sticker'
+when 'image', 'file', 'video', 'audio', 'sticker', 'video_note'
   create_message
   attach_media
 else
-  create_unsuported_message
+  create_unsupported_message

and rename the method:

-def create_unsuported_message
+def create_unsupported_message

Failing to standardise the name risks future maintenance bugs and makes grep-based discovery harder.

@CayoPOliveira CayoPOliveira changed the base branch from fazer-ai/main to feat/baileys-send-audio April 25, 2025 00:01
Copy link
@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

-(review needed) +(questions/changes requested)

Reviewed 3 of 8 files at r1, 6 of 6 files at r2, all commit messages.
Dismissed @coderabbitai[bot] and @copilot-pull-request-reviewer[bot] from 4 discussions.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @CayoPOliveira)


app/services/whatsapp/incoming_message_baileys_service.rb line 93 at r1 (raw file):

    # NOTE: If the message don't have a 'verifiedBizName' or 'pushName', we use the phone number as the name.
    phone_number_from_jid

NIT

Comment not needed.

Suggestion:

    phone_number_from_jid

app/services/whatsapp/incoming_message_baileys_service.rb line 77 at r2 (raw file):

    @contact = contact_inbox.contact

    @contact.update!(name: push_name) if @contact.name != push_name

Do not override existing names. Only override if contact name is phone number.


app/services/whatsapp/incoming_message_baileys_service.rb line 84 at r2 (raw file):

    # https://github.com/WhiskeySockets/Baileys/blob/v6.7.16/src/WABinary/jid-utils.ts#L19
    @raw_message[:key][:remoteJid].split('@').first.split(':').first.split('_').first
  end

Suggestion:

  def phone_number_from_jid
    # NOTE: jid shape is `<user>_<agent>:<device>@<server>`
    # https://github.com/WhiskeySockets/Baileys/blob/v6.7.16/src/WABinary/jid-utils.ts#L19
    @phone_number_from_jid ||= @raw_message[:key][:remoteJid].split('@').first.split(':').first.split('_').first
  end

spec/services/whatsapp/incoming_message_baileys_service_spec.rb line 215 at r2 (raw file):

      context 'when message type is text' do
        let(:number) { '5511912345678' }

NIT

Suggestion:

        let(:phone_number) { '5511912345678' }

spec/services/whatsapp/incoming_message_baileys_service_spec.rb line 265 at r2 (raw file):

          end

          it 'updates the contact name when name is the number and message has a pushName' do

Reminder to update other descriptions below.

Suggestion:

          it 'updates the contact name when name is the phone number and message has a pushName' do

Copy link
@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

Reviewable status: all files reviewed, 6 unresolved discussions (waiting on @CayoPOliveira)


app/services/whatsapp/incoming_message_baileys_service.rb line 0 at r2 (raw file):
Investigate bug with creating new contact when sending message from connected whatsapp to new contact.

Copy link
Collaborator Author
@CayoPOliveira CayoPOliveira left a comment

Choose a reason for hiding this comment

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

-(questions/changes requested) +(review needed)

Reviewed 1 of 6 files at r2.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @gabrieljablonski)


app/services/whatsapp/incoming_message_baileys_service.rb line 77 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Do not override existing names. Only override if contact name is phone number.

Done.


app/services/whatsapp/incoming_message_baileys_service.rb line at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Investigate bug with creating new contact when sending message from connected whatsapp to new contact.

TODO


spec/services/whatsapp/incoming_message_baileys_service_spec.rb line 265 at r2 (raw file):

Previously, gabrieljablonski (Gabriel Jablonski) wrote…

Reminder to update other descriptions below.

Done.

Comment on lines 77 to 88
def send_attachment_message
@attachment = @message.attachments.first

response = HTTParty.post(
"#{provider_url}/connections/#{whatsapp_channel.phone_number}/send-message",
headers: api_headers,
body: {
type: @attachment.file_type == 'file' ? 'document' : @attachment.file_type,
recipient: @phone_number,
messageContent: message_content
}.to_json
)

return response.parsed_response.dig('data', 'key', 'id') if process_response(response)

@message.update!(status: 'failed')
raise MessageSendFailed
end
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually, it is a problem, similar services use only the first attachment, but I can use two approaches:

  • Divide each attachment into multiple messages (however, this generates a problem with the message ID in chatwoot having multiple message IDs in baileys)
  • Limit the maximum number of attachments to 1 for baileys, both in front-end and back-end

@gabrieljablonski help

Copy link
@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

-(review needed) +(approved for merge)

Reviewed 3 of 3 files at r3, 1 of 1 files at r4, 2 of 2 files at r5, 1 of 1 files at r6, all commit messages.
Dismissed @CayoPOliveira and @coderabbitai[bot] from 2 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @CayoPOliveira)

@gabrieljablonski gabrieljablonski force-pushed the chore/change-baileys-contact-name-preferences branch from b99359d to 68a1fc4 Compare April 25, 2025 19:14
Copy link
@gabrieljablonski gabrieljablonski left a comment

Choose a reason for hiding this comment

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

Reviewed 1 of 1 files at r7, 1 of 1 files at r8, all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @CayoPOliveira)

@gabrieljablonski gabrieljablonski merged commit 0d3b13d into feat/baileys-send-audio Apr 25, 2025
1 of 2 checks passed
@gabrieljablonski gabrieljablonski deleted the chore/change-baileys-contact-name-preferences branch April 25, 2025 19:17
gabrieljablonski added a commit that referenced this pull request Apr 25, 2025
* feat: enhance message sending logic with support for attachments and interactive messages

* fix: update message format to use messageContent for text messages

* feat: attachment message sending

* fix: use strict encoding for attachment file download

* chore: streamline message sending logic and remove unused error classes

* chore: remove type from message sending logic

* chore: update message sending specs

* chore: raise MessageNotSentError instead of updating message status to failed

* chore: change baileys contact name preferences (#30)

* refactor: improve contact name handling and extraction from JID

* test: enhance message handling to update contact names based on pushName and verifiedBizName

* chore: update contact name condition to match phone number from JID

* chore: correct method name typo

* chore: correct variable names for phone number consistency in tests

* chore: update message payload structure and improve error handling in send_message

* test: re-add testing for error handling

* feat: enhance contact name handling and add self-message detection

* fix: ensure presence check for verified business name in contact name retrieval

* test: improve specs

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>
gabrieljablonski added a commit that referenced this pull request Apr 25, 2025
* feat: create alert message for unsupported message types

* chore: fail message when try send not supported type in baileys

* chore: add tests for unsupported message handling in Baileys service

* chore: correct spelling

* chore: NIT in spec name

* chore: remove unnecessary message reload in unsupported message type test

* feat: baileys support to send attachments (#28)

* feat: enhance message sending logic with support for attachments and interactive messages

* fix: update message format to use messageContent for text messages

* feat: attachment message sending

* fix: use strict encoding for attachment file download

* chore: streamline message sending logic and remove unused error classes

* chore: remove type from message sending logic

* chore: update message sending specs

* chore: raise MessageNotSentError instead of updating message status to failed

* chore: change baileys contact name preferences (#30)

* refactor: improve contact name handling and extraction from JID

* test: enhance message handling to update contact names based on pushName and verifiedBizName

* chore: update contact name condition to match phone number from JID

* chore: correct method name typo

* chore: correct variable names for phone number consistency in tests

* chore: update message payload structure and improve error handling in send_message

* test: re-add testing for error handling

* feat: enhance contact name handling and add self-message detection

* fix: ensure presence check for verified business name in contact name retrieval

* test: improve specs

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>
gabrieljablonski added a commit that referenced this pull request Apr 25, 2025
…dle unsupported messages (#26)

* fix: return not_found status for missing messages in WhatsApp webhook

* feat: enhance message handling to support image attachments

* chore: Handle incoming whatsapp baileys service attachments and implement specs for images and videos

* fix: add file_content_type method to incoming baileys messages

* chore: specs for stickers, audio and files

* fix: handle media attachment errors

* chore: convert file_content_type to string when attaching media

* fix: add handling for attachment not found error in incoming message service

* chore: refactor file_content_type method and simplify filename method

* chore: update media attachment tests

* feat: baileys unsupported message alert (#27)

* feat: create alert message for unsupported message types

* chore: fail message when try send not supported type in baileys

* chore: add tests for unsupported message handling in Baileys service

* chore: correct spelling

* chore: NIT in spec name

* chore: remove unnecessary message reload in unsupported message type test

* feat: baileys support to send attachments (#28)

* feat: enhance message sending logic with support for attachments and interactive messages

* fix: update message format to use messageContent for text messages

* feat: attachment message sending

* fix: use strict encoding for attachment file download

* chore: streamline message sending logic and remove unused error classes

* chore: remove type from message sending logic

* chore: update message sending specs

* chore: raise MessageNotSentError instead of updating message status to failed

* chore: change baileys contact name preferences (#30)

* refactor: improve contact name handling and extraction from JID

* test: enhance message handling to update contact names based on pushName and verifiedBizName

* chore: update contact name condition to match phone number from JID

* chore: correct method name typo

* chore: correct variable names for phone number consistency in tests

* chore: update message payload structure and improve error handling in send_message

* test: re-add testing for error handling

* feat: enhance contact name handling and add self-message detection

* fix: ensure presence check for verified business name in contact name retrieval

* test: improve specs

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>

* fix: try to disconnect baileys before destroy inbox (#29)

* fix: ensure proper disconnection of Baileys provider on channel destruction

* test: add callback tests for disconnecting channel provider in Whatsapp spec

* refactor: simplify condition for disconnecting Baileys provider on channel destruction

* refactor: enhance disconnect_channel_provider specs for Baileys provider

* test: verify channel destruction does not call disconnect_channel_provider

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>

---------

Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
Co-authored-by: Gabriel Jablonski <gabriel@fazer.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved for merge enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0