fix: z-api read message (#165)
* fix: z-api read messages * fix: use threads for parallel requests * feat: use jobs instead * fix: refactor ZapiReadMessageJob to use service method for sending read messages
This commit is contained in:
parent
0f56c51e68
commit
774c168d94
8
app/jobs/channels/whatsapp/zapi_read_message_job.rb
Normal file
8
app/jobs/channels/whatsapp/zapi_read_message_job.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class Channels::Whatsapp::ZapiReadMessageJob < ApplicationJob
|
||||||
|
queue_as :default
|
||||||
|
|
||||||
|
def perform(whatsapp_channel, phone, message_source_id)
|
||||||
|
service = Whatsapp::Providers::WhatsappZapiService.new(whatsapp_channel: whatsapp_channel)
|
||||||
|
service.send_read_message(phone, message_source_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -81,21 +81,28 @@ class Whatsapp::Providers::WhatsappZapiService < Whatsapp::Providers::BaseServic
|
|||||||
end
|
end
|
||||||
|
|
||||||
def read_messages(messages, recipient_id:, **)
|
def read_messages(messages, recipient_id:, **)
|
||||||
# NOTE: Z-API will handle marking previous messages as read.
|
phone = recipient_id.delete('+')
|
||||||
last_message = messages.last
|
|
||||||
|
|
||||||
|
messages.each do |message|
|
||||||
|
next if message.source_id.blank?
|
||||||
|
|
||||||
|
Channels::Whatsapp::ZapiReadMessageJob.perform_later(whatsapp_channel, phone, message.source_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_read_message(phone, message_source_id)
|
||||||
response = HTTParty.post(
|
response = HTTParty.post(
|
||||||
"#{api_instance_path_with_token}/read-message",
|
"#{api_instance_path_with_token}/read-message",
|
||||||
headers: api_headers,
|
headers: api_headers,
|
||||||
body: {
|
body: {
|
||||||
phone: recipient_id.delete('+'),
|
phone: phone,
|
||||||
messageId: last_message.source_id
|
messageId: message_source_id
|
||||||
}.to_json
|
}.to_json
|
||||||
)
|
)
|
||||||
|
|
||||||
raise ProviderUnavailableError unless process_response(response)
|
process_response(response)
|
||||||
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_whatsapp(phone_number)
|
def on_whatsapp(phone_number)
|
||||||
|
|||||||
71
spec/jobs/channels/whatsapp/zapi_read_message_job_spec.rb
Normal file
71
spec/jobs/channels/whatsapp/zapi_read_message_job_spec.rb
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Channels::Whatsapp::ZapiReadMessageJob do
|
||||||
|
let(:whatsapp_channel) do
|
||||||
|
create(:channel_whatsapp,
|
||||||
|
provider: 'zapi',
|
||||||
|
sync_templates: false,
|
||||||
|
validate_provider_config: false,
|
||||||
|
provider_config: {
|
||||||
|
'instance_id' => 'test-instance',
|
||||||
|
'token' => 'test-token',
|
||||||
|
'client_token' => 'test-client-token'
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:phone) { '551187654321' }
|
||||||
|
let(:message_source_id) { 'msg_123' }
|
||||||
|
let(:api_base_path) { Whatsapp::Providers::WhatsappZapiService::API_BASE_PATH }
|
||||||
|
let(:api_instance_path_with_token) { "#{api_base_path}/instances/test-instance/token/test-token" }
|
||||||
|
|
||||||
|
def stub_headers
|
||||||
|
{
|
||||||
|
'Accept' => '*/*',
|
||||||
|
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
'Client-Token' => 'test-client-token',
|
||||||
|
'User-Agent' => 'Ruby'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#perform' do
|
||||||
|
context 'when response is successful' do
|
||||||
|
it 'sends a read message request to Z-API' do
|
||||||
|
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
||||||
|
.with(
|
||||||
|
headers: stub_headers,
|
||||||
|
body: {
|
||||||
|
phone: phone,
|
||||||
|
messageId: message_source_id
|
||||||
|
}.to_json
|
||||||
|
)
|
||||||
|
.to_return(status: 200)
|
||||||
|
|
||||||
|
described_class.perform_now(whatsapp_channel, phone, message_source_id)
|
||||||
|
|
||||||
|
expect(a_request(:post, "#{api_instance_path_with_token}/read-message")
|
||||||
|
.with(
|
||||||
|
headers: stub_headers,
|
||||||
|
body: {
|
||||||
|
phone: phone,
|
||||||
|
messageId: message_source_id
|
||||||
|
}.to_json
|
||||||
|
)).to have_been_made.once
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when response is unsuccessful' do
|
||||||
|
it 'logs the error' do
|
||||||
|
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
||||||
|
.with(headers: stub_headers)
|
||||||
|
.to_return(status: 400, body: 'error message')
|
||||||
|
|
||||||
|
allow(Rails.logger).to receive(:error)
|
||||||
|
|
||||||
|
described_class.perform_now(whatsapp_channel, phone, message_source_id)
|
||||||
|
|
||||||
|
expect(Rails.logger).to have_received(:error).with('error message')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -194,37 +194,55 @@ describe Whatsapp::Providers::WhatsappZapiService do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe '#read_messages' do
|
describe '#read_messages' do
|
||||||
let(:messages) { [create(:message), message] }
|
let(:first_message) { create(:message, source_id: 'msg_first') }
|
||||||
|
let(:second_message) { create(:message, source_id: 'msg_second') }
|
||||||
|
let(:messages) { [first_message, second_message] }
|
||||||
|
|
||||||
context 'when response is successful' do
|
it 'enqueues a job for each message' do
|
||||||
it 'marks messages as read by referencing last message id' do
|
service.read_messages(messages, recipient_id: "+#{test_send_phone_number}")
|
||||||
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
|
||||||
.with(
|
|
||||||
headers: stub_headers,
|
|
||||||
body: {
|
|
||||||
phone: test_send_phone_number,
|
|
||||||
messageId: message.source_id
|
|
||||||
}.to_json
|
|
||||||
)
|
|
||||||
.to_return(status: 200)
|
|
||||||
|
|
||||||
|
expect(Channels::Whatsapp::ZapiReadMessageJob).to have_been_enqueued.with(whatsapp_channel, test_send_phone_number, first_message.source_id)
|
||||||
|
expect(Channels::Whatsapp::ZapiReadMessageJob).to have_been_enqueued.with(whatsapp_channel, test_send_phone_number, second_message.source_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
result = service.read_messages(messages, recipient_id: "+#{test_send_phone_number}")
|
result = service.read_messages(messages, recipient_id: "+#{test_send_phone_number}")
|
||||||
|
|
||||||
expect(result).to be(true)
|
expect(result).to be(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#send_read_message' do
|
||||||
|
let(:phone) { test_send_phone_number }
|
||||||
|
let(:message_source_id) { 'msg_123' }
|
||||||
|
|
||||||
|
context 'when response is successful' do
|
||||||
|
it 'sends a read message request to Z-API' do
|
||||||
|
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
||||||
|
.with(
|
||||||
|
headers: stub_headers,
|
||||||
|
body: { phone: phone, messageId: message_source_id }.to_json
|
||||||
|
)
|
||||||
|
.to_return(status: 200)
|
||||||
|
|
||||||
|
result = service.send_read_message(phone, message_source_id)
|
||||||
|
|
||||||
|
expect(result).to be(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when response is unsuccessful' do
|
context 'when response is unsuccessful' do
|
||||||
it 'raises ProviderUnavailableError' do
|
it 'logs the error and returns false' do
|
||||||
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
stub_request(:post, "#{api_instance_path_with_token}/read-message")
|
||||||
.with(headers: stub_headers)
|
.with(headers: stub_headers)
|
||||||
.to_return(status: 400, body: 'error message', headers: {})
|
.to_return(status: 400, body: 'error message')
|
||||||
|
|
||||||
allow(Rails.logger).to receive(:error)
|
allow(Rails.logger).to receive(:error)
|
||||||
|
|
||||||
expect do
|
result = service.send_read_message(phone, message_source_id)
|
||||||
service.read_messages(messages, recipient_id: "+#{test_send_phone_number}")
|
|
||||||
end.to raise_error(Whatsapp::Providers::WhatsappZapiService::ProviderUnavailableError)
|
expect(result).to be(false)
|
||||||
|
expect(Rails.logger).to have_received(:error).with('error message')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user