mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-29 18:22:53 +00:00
feat: Handle instagram test service (#11244)
This PR will handle the Instagram test events. We are using the last created Instagram channel as the test channel since we don't have any other channels for testing purposes at the time of Meta approval. https://github.com/user-attachments/assets/98302b7a-d72c-4950-9660-861a5e08d55f --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
@@ -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]
|
||||
|
||||
79
app/services/instagram/test_event_service.rb
Normal file
79
app/services/instagram/test_event_service.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
71
spec/services/instagram/test_event_service_spec.rb
Normal file
71
spec/services/instagram/test_event_service_spec.rb
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user