From 46b75e1b035a81d6f8c5fc36f64df311a903394a Mon Sep 17 00:00:00 2001 From: Eduardo Policarpo <30879448+edupoli@users.noreply.github.com> Date: Tue, 23 Sep 2025 00:46:59 -0300 Subject: [PATCH] feat(whatsapp): add optional phone_number_id parameter to media retrieval API (#11823) ## Description This pull request introduces an optional parameter, `phone_number_id`, to the WhatsApp API call responsible for retrieving media. The addition of this parameter allows for greater flexibility when interacting with the WhatsApp API, as it can now accommodate scenarios where specifying a particular phone number ID is necessary. This change is backward compatible and does not affect existing functionality if the parameter is not provided. Fixes # (issue) ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? The changes were tested locally by invoking the WhatsApp media retrieval API with and without the `phone_number_id` parameter. Both scenarios were verified to ensure that: - When `phone_number_id` is provided, the API call includes the parameter and functions as expected. - When `phone_number_id` is omitted, the API call continues to work as before, maintaining backward compatibility. No errors or warnings were observed during testing, and all relevant unit tests passed successfully. ## Checklist - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Muhsin Keloth --- ...incoming_message_whatsapp_cloud_service.rb | 8 +- .../providers/whatsapp_cloud_service.rb | 6 +- ...ing_message_whatsapp_cloud_service_spec.rb | 81 ++++++++++++++----- 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/app/services/whatsapp/incoming_message_whatsapp_cloud_service.rb b/app/services/whatsapp/incoming_message_whatsapp_cloud_service.rb index 97051a2cf..f8ac8c85a 100644 --- a/app/services/whatsapp/incoming_message_whatsapp_cloud_service.rb +++ b/app/services/whatsapp/incoming_message_whatsapp_cloud_service.rb @@ -9,7 +9,13 @@ class Whatsapp::IncomingMessageWhatsappCloudService < Whatsapp::IncomingMessageB end def download_attachment_file(attachment_payload) - url_response = HTTParty.get(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers) + url_response = HTTParty.get( + inbox.channel.media_url( + attachment_payload[:id], + inbox.channel.provider_config['phone_number_id'] + ), + headers: inbox.channel.api_headers + ) # This url response will be failure if the access token has expired. inbox.channel.authorization_error! if url_response.unauthorized? Down.download(url_response.parsed_response['url'], headers: inbox.channel.api_headers) if url_response.success? diff --git a/app/services/whatsapp/providers/whatsapp_cloud_service.rb b/app/services/whatsapp/providers/whatsapp_cloud_service.rb index 124e1e5d3..1968693ff 100644 --- a/app/services/whatsapp/providers/whatsapp_cloud_service.rb +++ b/app/services/whatsapp/providers/whatsapp_cloud_service.rb @@ -62,8 +62,10 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi { 'Authorization' => "Bearer #{whatsapp_channel.provider_config['api_key']}", 'Content-Type' => 'application/json' } end - def media_url(media_id) - "#{api_base_path}/v13.0/#{media_id}" + def media_url(media_id, phone_number_id = nil) + url = "#{api_base_path}/v13.0/#{media_id}" + url += "?phone_number_id=#{phone_number_id}" if phone_number_id + url end def api_base_path diff --git a/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb b/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb index b222354a4..b162250bf 100644 --- a/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb +++ b/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb @@ -29,32 +29,23 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do context 'when valid attachment message params' do it 'creates appropriate conversations, message and contacts' do - stub_request(:get, whatsapp_channel.media_url('b1c68f38-8734-4ad3-b4a1-ef0c10d683')).to_return( - status: 200, - body: { - messaging_product: 'whatsapp', - url: 'https://chatwoot-assets.local/sample.png', - mime_type: 'image/jpeg', - sha256: 'sha256', - file_size: 'SIZE', - id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683' - }.to_json, - headers: { 'content-type' => 'application/json' } - ) - stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return( - status: 200, - body: File.read('spec/assets/sample.png') - ) - + stub_media_url_request + stub_sample_png_request described_class.new(inbox: whatsapp_channel.inbox, params: params).perform - expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) - expect(Contact.all.first.name).to eq('Sojan Jose') - expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!') - expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true + expect_conversation_created + expect_contact_name + expect_message_content + expect_message_has_attachment end it 'increments reauthorization count if fetching attachment fails' do - stub_request(:get, whatsapp_channel.media_url('b1c68f38-8734-4ad3-b4a1-ef0c10d683')).to_return( + stub_request( + :get, + whatsapp_channel.media_url( + 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', + whatsapp_channel.provider_config['phone_number_id'] + ) + ).to_return( status: 401 ) @@ -115,4 +106,50 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do end end end + + # Métodos auxiliares para reduzir o tamanho do exemplo + + def stub_media_url_request + stub_request( + :get, + whatsapp_channel.media_url( + 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', + whatsapp_channel.provider_config['phone_number_id'] + ) + ).to_return( + status: 200, + body: { + messaging_product: 'whatsapp', + url: 'https://chatwoot-assets.local/sample.png', + mime_type: 'image/jpeg', + sha256: 'sha256', + file_size: 'SIZE', + id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683' + }.to_json, + headers: { 'content-type' => 'application/json' } + ) + end + + def stub_sample_png_request + stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return( + status: 200, + body: File.read('spec/assets/sample.png') + ) + end + + def expect_conversation_created + expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) + end + + def expect_contact_name + expect(Contact.all.first.name).to eq('Sojan Jose') + end + + def expect_message_content + expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!') + end + + def expect_message_has_attachment + expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true + end end