Fix Wuzapi webhook handling
This commit is contained in:
parent
14dbc0f423
commit
58f5ae6157
@ -30,19 +30,33 @@ class Webhooks::WhatsappController < ActionController::API
|
|||||||
end
|
end
|
||||||
|
|
||||||
def valid_token?(token)
|
def valid_token?(token)
|
||||||
channel = Channel::Whatsapp.find_by(phone_number: params[:phone_number])
|
channel = find_channel_by_phone_number(params[:phone_number])
|
||||||
whatsapp_webhook_verify_token = channel.provider_config['webhook_verify_token'] if channel.present?
|
whatsapp_webhook_verify_token = channel.provider_config['webhook_verify_token'] if channel.present?
|
||||||
token == whatsapp_webhook_verify_token if whatsapp_webhook_verify_token.present?
|
token == whatsapp_webhook_verify_token if whatsapp_webhook_verify_token.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def inactive_whatsapp_number?
|
def inactive_whatsapp_number?
|
||||||
phone_number = params[:phone_number]
|
phone_number = normalize_phone(params[:phone_number])
|
||||||
return false if phone_number.blank?
|
return false if phone_number.blank?
|
||||||
|
|
||||||
inactive_numbers = GlobalConfig.get_value('INACTIVE_WHATSAPP_NUMBERS').to_s
|
inactive_numbers = GlobalConfig.get_value('INACTIVE_WHATSAPP_NUMBERS').to_s
|
||||||
return false if inactive_numbers.blank?
|
return false if inactive_numbers.blank?
|
||||||
|
|
||||||
inactive_numbers_array = inactive_numbers.split(',').map(&:strip)
|
inactive_numbers_array = inactive_numbers.split(',').map(&:strip)
|
||||||
inactive_numbers_array.include?(phone_number)
|
inactive_numbers_array.map { |number| normalize_phone(number) }.include?(phone_number)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_channel_by_phone_number(phone_number)
|
||||||
|
raw_phone = phone_number.to_s.strip
|
||||||
|
digits_only = normalize_phone(raw_phone)
|
||||||
|
return if raw_phone.blank? && digits_only.blank?
|
||||||
|
|
||||||
|
Channel::Whatsapp.find_by(phone_number: raw_phone) ||
|
||||||
|
Channel::Whatsapp.find_by(phone_number: "+#{digits_only}") ||
|
||||||
|
Channel::Whatsapp.where("regexp_replace(phone_number, '[^0-9]', '', 'g') = ?", digits_only).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_phone(phone_number)
|
||||||
|
phone_number.to_s.gsub(/\D/, '')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -79,7 +79,7 @@ class Webhooks::WhatsappEventsJob < ApplicationJob
|
|||||||
|
|
||||||
return unless params[:phone_number]
|
return unless params[:phone_number]
|
||||||
|
|
||||||
Channel::Whatsapp.find_by(phone_number: params[:phone_number])
|
find_channel_by_phone_number(params[:phone_number])
|
||||||
end
|
end
|
||||||
|
|
||||||
def channel_is_inactive?(channel)
|
def channel_is_inactive?(channel)
|
||||||
@ -96,8 +96,18 @@ class Webhooks::WhatsappEventsJob < ApplicationJob
|
|||||||
# we will give priority to the phone_number in the payload
|
# we will give priority to the phone_number in the payload
|
||||||
phone_number = "+#{params[:entry].first[:changes].first.dig(:value, :metadata, :display_phone_number)}"
|
phone_number = "+#{params[:entry].first[:changes].first.dig(:value, :metadata, :display_phone_number)}"
|
||||||
phone_number_id = params[:entry].first[:changes].first.dig(:value, :metadata, :phone_number_id)
|
phone_number_id = params[:entry].first[:changes].first.dig(:value, :metadata, :phone_number_id)
|
||||||
channel = Channel::Whatsapp.find_by(phone_number: phone_number)
|
channel = find_channel_by_phone_number(phone_number)
|
||||||
# validate to ensure the phone number id matches the whatsapp channel
|
# validate to ensure the phone number id matches the whatsapp channel
|
||||||
channel if channel && channel.provider_config['phone_number_id'] == phone_number_id
|
channel if channel && channel.provider_config['phone_number_id'] == phone_number_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_channel_by_phone_number(phone_number)
|
||||||
|
raw_phone = phone_number.to_s.strip
|
||||||
|
digits_only = raw_phone.gsub(/\D/, '')
|
||||||
|
return if raw_phone.blank? && digits_only.blank?
|
||||||
|
|
||||||
|
Channel::Whatsapp.find_by(phone_number: raw_phone) ||
|
||||||
|
Channel::Whatsapp.find_by(phone_number: "+#{digits_only}") ||
|
||||||
|
Channel::Whatsapp.where("regexp_replace(phone_number, '[^0-9]', '', 'g') = ?", digits_only).first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -46,6 +46,16 @@ RSpec.describe 'Webhooks::WhatsappController', type: :request do
|
|||||||
expect(response).to have_http_status(:unprocessable_entity)
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
expect(response.parsed_body['error']).to eq('Inactive WhatsApp number')
|
expect(response.parsed_body['error']).to eq('Inactive WhatsApp number')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns service unavailable even when incoming phone has different formatting' do
|
||||||
|
allow(Rails.logger).to receive(:warn)
|
||||||
|
allow(GlobalConfig).to receive(:get_value).with('INACTIVE_WHATSAPP_NUMBERS').and_return('+55 (61) 91234-5678')
|
||||||
|
|
||||||
|
post '/webhooks/whatsapp/5561912345678', params: { content: 'hello' }
|
||||||
|
|
||||||
|
expect(Rails.logger).to have_received(:warn).with('Rejected webhook for inactive WhatsApp number: 5561912345678')
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when INACTIVE_WHATSAPP_NUMBERS config is not set' do
|
context 'when INACTIVE_WHATSAPP_NUMBERS config is not set' do
|
||||||
|
|||||||
@ -109,6 +109,38 @@ RSpec.describe Webhooks::WhatsappEventsJob do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when phone number format differs in webhook payload' do
|
||||||
|
it 'finds channel by normalized phone number and processes event' do
|
||||||
|
wuzapi_channel = create(
|
||||||
|
:channel_whatsapp,
|
||||||
|
provider: 'wuzapi',
|
||||||
|
phone_number: '+55 (61) 99186-8492',
|
||||||
|
sync_templates: false,
|
||||||
|
validate_provider_config: false
|
||||||
|
)
|
||||||
|
wuzapi_params = {
|
||||||
|
phone_number: '5561991868492',
|
||||||
|
type: 'Message',
|
||||||
|
event: {
|
||||||
|
Info: {
|
||||||
|
ID: '3A721AC0A215F23ACFA9',
|
||||||
|
IsFromMe: false,
|
||||||
|
IsGroup: false,
|
||||||
|
Type: 'text',
|
||||||
|
Sender: '556182098580@s.whatsapp.net',
|
||||||
|
Timestamp: Time.current.iso8601
|
||||||
|
},
|
||||||
|
Message: { conversation: 'Ola terse' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allow(Whatsapp::IncomingMessageWuzapiService).to receive(:new).and_return(process_service)
|
||||||
|
expect(Whatsapp::IncomingMessageWuzapiService).to receive(:new).with(inbox: wuzapi_channel.inbox, params: wuzapi_params)
|
||||||
|
|
||||||
|
job.perform_now(wuzapi_params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when whatsapp business params' do
|
context 'when whatsapp business params' do
|
||||||
it 'enqueue Whatsapp::IncomingMessageWhatsappCloudService based on the number in payload' do
|
it 'enqueue Whatsapp::IncomingMessageWhatsappCloudService based on the number in payload' do
|
||||||
other_channel = create(:channel_whatsapp, phone_number: '+1987654', provider: 'whatsapp_cloud', sync_templates: false,
|
other_channel = create(:channel_whatsapp, phone_number: '+1987654', provider: 'whatsapp_cloud', sync_templates: false,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user