mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	feat: Add support for Instagram delivery reports (#8125)
This commit is contained in:
		@@ -231,7 +231,11 @@ export default {
 | 
			
		||||
        return contactLastSeenAt >= this.createdAt;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.isAWhatsAppChannel || this.isATwilioChannel) {
 | 
			
		||||
      if (
 | 
			
		||||
        this.isAWhatsAppChannel ||
 | 
			
		||||
        this.isATwilioChannel ||
 | 
			
		||||
        this.isAFacebookInbox
 | 
			
		||||
      ) {
 | 
			
		||||
        return this.sourceId && this.isRead;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ class Webhooks::InstagramEventsJob < MutexApplicationJob
 | 
			
		||||
  base_uri 'https://graph.facebook.com/v11.0/me'
 | 
			
		||||
 | 
			
		||||
  # @return [Array] We will support further events like reaction or seen in future
 | 
			
		||||
  SUPPORTED_EVENTS = [:message].freeze
 | 
			
		||||
  SUPPORTED_EVENTS = [:message, :read].freeze
 | 
			
		||||
 | 
			
		||||
  def perform(entries)
 | 
			
		||||
    @entries = entries
 | 
			
		||||
@@ -45,6 +45,10 @@ class Webhooks::InstagramEventsJob < MutexApplicationJob
 | 
			
		||||
    ::Instagram::MessageText.new(messaging).perform
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def read(messaging)
 | 
			
		||||
    ::Instagram::ReadStatusService.new(params: messaging).perform
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def messages(entry)
 | 
			
		||||
    (entry[:messaging].presence || entry[:standby] || [])
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								app/services/instagram/read_status_service.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/services/instagram/read_status_service.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
class Instagram::ReadStatusService
 | 
			
		||||
  pattr_initialize [:params!]
 | 
			
		||||
 | 
			
		||||
  def perform
 | 
			
		||||
    return if instagram_channel.blank?
 | 
			
		||||
 | 
			
		||||
    process_status if message.present?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def process_status
 | 
			
		||||
    @message.status = 'read'
 | 
			
		||||
    @message.save!
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def instagram_id
 | 
			
		||||
    params[:recipient][:id]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def instagram_channel
 | 
			
		||||
    @instagram_channel ||= Channel::FacebookPage.find_by(instagram_id: instagram_id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def message
 | 
			
		||||
    return unless params[:read][:mid]
 | 
			
		||||
 | 
			
		||||
    @message ||= @instagram_channel.inbox.messages.find_by(source_id: params[:read][:mid])
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -242,4 +242,30 @@ FactoryBot.define do
 | 
			
		||||
    end
 | 
			
		||||
    initialize_with { attributes }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  factory :messaging_seen_event, class: Hash do
 | 
			
		||||
    entry do
 | 
			
		||||
      [
 | 
			
		||||
        {
 | 
			
		||||
          'id': 'instagram-message-id-123',
 | 
			
		||||
          'time': '2021-09-08T06:34:04+0000',
 | 
			
		||||
          'messaging': [
 | 
			
		||||
            {
 | 
			
		||||
              'sender': {
 | 
			
		||||
                'id': 'Sender-id-1'
 | 
			
		||||
              },
 | 
			
		||||
              'recipient': {
 | 
			
		||||
                'id': 'chatwoot-app-user-id-1'
 | 
			
		||||
              },
 | 
			
		||||
              'timestamp': '2021-09-08T06:34:04+0000',
 | 
			
		||||
              'read': {
 | 
			
		||||
                'mid': 'message-id-1'
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    end
 | 
			
		||||
    initialize_with { attributes }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@ describe Webhooks::InstagramEventsJob do
 | 
			
		||||
  let!(:attachment_params) { build(:instagram_message_attachment_event).with_indifferent_access }
 | 
			
		||||
  let!(:story_mention_params) { build(:instagram_story_mention_event).with_indifferent_access }
 | 
			
		||||
  let!(:story_mention_echo_params) { build(:instagram_story_mention_event_with_echo).with_indifferent_access }
 | 
			
		||||
  let!(:messaging_seen_event) { build(:messaging_seen_event).with_indifferent_access }
 | 
			
		||||
  let(:fb_object) { double }
 | 
			
		||||
 | 
			
		||||
  describe '#perform' do
 | 
			
		||||
@@ -151,6 +152,11 @@ describe Webhooks::InstagramEventsJob do
 | 
			
		||||
        expect(instagram_inbox.contact_inboxes.count).to be 0
 | 
			
		||||
        expect(instagram_inbox.messages.count).to be 0
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'handle messaging_seen callback' do
 | 
			
		||||
        expect(Instagram::ReadStatusService).to receive(:new).with(params: messaging_seen_event[:entry][0][:messaging][0]).and_call_original
 | 
			
		||||
        instagram_webhook.perform_now(messaging_seen_event[:entry])
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								spec/services/instagram/read_status_service_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								spec/services/instagram/read_status_service_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
describe Instagram::ReadStatusService do
 | 
			
		||||
  before do
 | 
			
		||||
    create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation,
 | 
			
		||||
                     source_id: 'chatwoot-app-user-id-1')
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  let!(:account) { create(:account) }
 | 
			
		||||
  let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') }
 | 
			
		||||
  let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) }
 | 
			
		||||
  let!(:contact) { create(:contact, account: account) }
 | 
			
		||||
  let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: instagram_inbox) }
 | 
			
		||||
  let(:conversation) { create(:conversation, contact: contact, inbox: instagram_inbox, contact_inbox: contact_inbox) }
 | 
			
		||||
 | 
			
		||||
  describe '#perform' do
 | 
			
		||||
    context 'when messaging_seen callback is fired' do
 | 
			
		||||
      let(:message) { conversation.messages.last }
 | 
			
		||||
 | 
			
		||||
      it 'updates the message status to read if the status is delivered' do
 | 
			
		||||
        params = {
 | 
			
		||||
          recipient: {
 | 
			
		||||
            id: 'chatwoot-app-user-id-1'
 | 
			
		||||
          },
 | 
			
		||||
          read: {
 | 
			
		||||
            mid: message.source_id
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        described_class.new(params: params).perform
 | 
			
		||||
        expect(conversation.reload.messages.last.status).to eq('read')
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it 'does not update the status if message is not found' do
 | 
			
		||||
        params = {
 | 
			
		||||
          recipient: {
 | 
			
		||||
            id: 'chatwoot-app-user-id-1'
 | 
			
		||||
          },
 | 
			
		||||
          read: {
 | 
			
		||||
            mid: 'random-message-id'
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        described_class.new(params: params).perform
 | 
			
		||||
        expect(conversation.reload.messages.last.status).not_to eq('read')
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user