diff --git a/app/jobs/webhooks/instagram_events_job.rb b/app/jobs/webhooks/instagram_events_job.rb index eb08f2ebb..3db8b6ba9 100644 --- a/app/jobs/webhooks/instagram_events_job.rb +++ b/app/jobs/webhooks/instagram_events_job.rb @@ -24,6 +24,11 @@ class Webhooks::InstagramEventsJob < MutexApplicationJob private def process_single_entry(entry) + if test_event?(entry) + process_test_event(entry) + return + end + process_messages(entry) end @@ -46,6 +51,20 @@ class Webhooks::InstagramEventsJob < MutexApplicationJob messaging[:message].present? && messaging[:message][:is_echo].present? end + def test_event?(entry) + entry[:changes].present? + end + + def process_test_event(entry) + messaging = extract_messaging_from_test_event(entry) + + Instagram::TestEventService.new(messaging).perform if messaging.present? + end + + def extract_messaging_from_test_event(entry) + entry[:changes].first&.dig(:value) if entry[:changes].present? + end + def instagram_id(messaging) if agent_message_via_echo?(messaging) messaging[:sender][:id] diff --git a/app/services/instagram/test_event_service.rb b/app/services/instagram/test_event_service.rb new file mode 100644 index 000000000..6fe242494 --- /dev/null +++ b/app/services/instagram/test_event_service.rb @@ -0,0 +1,79 @@ +class Instagram::TestEventService + def initialize(messaging) + @messaging = messaging + end + + def perform + Rails.logger.info("Processing Instagram test webhook event, #{@messaging}") + + return false unless test_webhook_event? + + create_test_text + end + + private + + def test_webhook_event? + @messaging[:sender][:id] == '12334' && @messaging[:recipient][:id] == '23245' + end + + def create_test_text + # As of now, we are using the last created instagram channel as the test channel, + # since we don't have any other channel for testing purpose at the time of meta approval + channel = Channel::Instagram.last + + @inbox = ::Inbox.find_by(channel: channel) + return unless @inbox + + @contact = create_test_contact + + @conversation ||= create_test_conversation(conversation_params) + + @message = @conversation.messages.create!(test_message_params) + end + + def create_test_contact + @contact_inbox = @inbox.contact_inboxes.where(source_id: @messaging[:sender][:id]).first + unless @contact_inbox + @contact_inbox ||= @inbox.channel.create_contact_inbox( + 'sender_username', 'sender_username' + ) + end + + @contact_inbox.contact + end + + def create_test_conversation(conversation_params) + Conversation.find_by(conversation_params) || build_conversation(conversation_params) + end + + def test_message_params + { + account_id: @conversation.account_id, + inbox_id: @conversation.inbox_id, + message_type: 'incoming', + source_id: @messaging[:message][:mid], + content: @messaging[:message][:text], + sender: @contact + } + end + + def build_conversation(conversation_params) + Conversation.create!( + conversation_params.merge( + contact_inbox_id: @contact_inbox.id + ) + ) + end + + def conversation_params + { + account_id: @inbox.account_id, + inbox_id: @inbox.id, + contact_id: @contact.id, + additional_attributes: { + type: 'instagram_direct_message' + } + } + end +end diff --git a/spec/factories/instagram/instagram_message_create_event.rb b/spec/factories/instagram/instagram_message_create_event.rb index 99572d620..66d5e8a81 100644 --- a/spec/factories/instagram/instagram_message_create_event.rb +++ b/spec/factories/instagram/instagram_message_create_event.rb @@ -361,4 +361,34 @@ FactoryBot.define do end initialize_with { attributes } end + + factory :instagram_test_event, class: Hash do + entry do + [ + { + 'id': '0', + 'time': '2021-09-08T06:34:04+0000', + 'changes': [ + { + 'field': 'messages', + 'value': { + 'sender': { + 'id': '12334' + }, + 'recipient': { + 'id': '23245' + }, + 'timestamp': '1527459824', + 'message': { + 'mid': 'random_mid', + 'text': 'random_text' + } + } + } + ] + } + ] + end + initialize_with { attributes } + end end diff --git a/spec/services/instagram/test_event_service_spec.rb b/spec/services/instagram/test_event_service_spec.rb new file mode 100644 index 000000000..a783197e6 --- /dev/null +++ b/spec/services/instagram/test_event_service_spec.rb @@ -0,0 +1,71 @@ +require 'rails_helper' + +describe Instagram::TestEventService do + let(:account) { create(:account) } + let(:instagram_channel) { create(:channel_instagram, account: account) } + let(:inbox) { create(:inbox, channel: instagram_channel, account: account) } + + describe '#perform' do + context 'when validating test webhook event' do + let(:test_messaging) do + { + 'sender': { + 'id': '12334' + }, + 'recipient': { + 'id': '23245' + }, + 'timestamp': '1527459824', + 'message': { + 'mid': 'random_mid', + 'text': 'random_text' + } + }.with_indifferent_access + end + + it 'creates test message for valid test webhook event' do + # Ensure inbox exists before test + inbox + + service = described_class.new(test_messaging) + + expect { service.perform }.to change(Message, :count).by(1) + + message = Message.last + expect(message.content).to eq('random_text') + expect(message.source_id).to eq('random_mid') + expect(message.message_type).to eq('incoming') + end + + it 'creates a contact with sender_username' do + # Ensure inbox exists before test + inbox + + service = described_class.new(test_messaging) + service.perform + + contact = Contact.last + expect(contact.name).to eq('sender_username') + end + + it 'returns false for non-test webhook events' do + invalid_messaging = test_messaging.deep_dup + invalid_messaging[:sender][:id] = 'different_id' + + service = described_class.new(invalid_messaging) + + expect(service.perform).to be(false) + end + + it 'returns nil when no Instagram channel exists' do + # Delete all inboxes and channels + Inbox.destroy_all + Channel::Instagram.destroy_all + + service = described_class.new(test_messaging) + + expect(service.perform).to be_nil + end + end + end +end