feat: Add Instagram Channel (#2955)
This commit is contained in:
49
app/services/instagram/message_text.rb
Normal file
49
app/services/instagram/message_text.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
class Instagram::MessageText < Instagram::WebhooksBaseService
|
||||
include HTTParty
|
||||
|
||||
attr_reader :messaging
|
||||
|
||||
base_uri 'https://graph.facebook.com/v11.0/'
|
||||
|
||||
def initialize(messaging)
|
||||
super()
|
||||
@messaging = messaging
|
||||
end
|
||||
|
||||
def perform
|
||||
instagram_id, contact_id = if agent_message_via_echo?
|
||||
[@messaging[:sender][:id], @messaging[:recipient][:id]]
|
||||
else
|
||||
[@messaging[:recipient][:id], @messaging[:sender][:id]]
|
||||
end
|
||||
inbox_channel(instagram_id)
|
||||
ensure_contact(contact_id)
|
||||
|
||||
create_message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_contact(ig_scope_id)
|
||||
begin
|
||||
k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook?
|
||||
result = k.get_object(ig_scope_id) || {}
|
||||
rescue Koala::Facebook::AuthenticationError
|
||||
@inbox.channel.authorization_error!
|
||||
raise
|
||||
rescue StandardError => e
|
||||
result = {}
|
||||
Sentry.capture_exception(e)
|
||||
end
|
||||
|
||||
find_or_create_contact(result)
|
||||
end
|
||||
|
||||
def agent_message_via_echo?
|
||||
@messaging[:message][:is_echo].present?
|
||||
end
|
||||
|
||||
def create_message
|
||||
Messages::Instagram::MessageBuilder.new(@messaging, @inbox, outgoing_echo: agent_message_via_echo?).perform
|
||||
end
|
||||
end
|
||||
99
app/services/instagram/send_on_instagram_service.rb
Normal file
99
app/services/instagram/send_on_instagram_service.rb
Normal file
@@ -0,0 +1,99 @@
|
||||
class Instagram::SendOnInstagramService < Base::SendOnChannelService
|
||||
include HTTParty
|
||||
|
||||
pattr_initialize [:message!]
|
||||
|
||||
base_uri 'https://graph.facebook.com/v11.0/me'
|
||||
|
||||
private
|
||||
|
||||
delegate :additional_attributes, to: :contact
|
||||
|
||||
def channel_class
|
||||
Channel::FacebookPage
|
||||
end
|
||||
|
||||
def perform_reply
|
||||
send_to_facebook_page attachament_message_params if message.attachments.present?
|
||||
send_to_facebook_page message_params
|
||||
rescue StandardError => e
|
||||
Sentry.capture_exception(e)
|
||||
channel.authorization_error!
|
||||
end
|
||||
|
||||
def message_params
|
||||
{
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: {
|
||||
text: message.content
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def attachament_message_params
|
||||
attachment = message.attachments.first
|
||||
{
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: {
|
||||
attachment: {
|
||||
type: attachment_type(attachment),
|
||||
payload: {
|
||||
url: attachment.file_url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# Deliver a message with the given payload.
|
||||
# @see https://developers.facebook.com/docs/messenger-platform/instagram/features/send-message
|
||||
def send_to_facebook_page(message_content)
|
||||
access_token = channel.page_access_token
|
||||
app_secret_proof = calculate_app_secret_proof(ENV['FB_APP_SECRET'], access_token)
|
||||
|
||||
query = { access_token: access_token }
|
||||
query[:appsecret_proof] = app_secret_proof if app_secret_proof
|
||||
|
||||
# url = "https://graph.facebook.com/v11.0/me/messages?access_token=#{access_token}"
|
||||
|
||||
response = HTTParty.post(
|
||||
'https://graph.facebook.com/v11.0/me/messages',
|
||||
body: message_content,
|
||||
query: query
|
||||
)
|
||||
# response = HTTParty.post(url, options)
|
||||
|
||||
Rails.logger.info("Instagram response: #{response} : #{message_content}") if response[:body][:error]
|
||||
|
||||
response[:body]
|
||||
end
|
||||
|
||||
def calculate_app_secret_proof(app_secret, access_token)
|
||||
Facebook::Messenger::Configuration::AppSecretProofCalculator.call(
|
||||
app_secret, access_token
|
||||
)
|
||||
end
|
||||
|
||||
def attachment_type(attachment)
|
||||
return attachment.file_type if %w[image audio video file].include? attachment.file_type
|
||||
|
||||
'file'
|
||||
end
|
||||
|
||||
def conversation_type
|
||||
conversation.additional_attributes['type']
|
||||
end
|
||||
|
||||
def sent_first_outgoing_message_after_24_hours?
|
||||
# we can send max 1 message after 24 hour window
|
||||
conversation.messages.outgoing.where('id > ?', last_incoming_message.id).count == 1
|
||||
end
|
||||
|
||||
def last_incoming_message
|
||||
conversation.messages.incoming.last
|
||||
end
|
||||
|
||||
def config
|
||||
Facebook::Messenger.config
|
||||
end
|
||||
end
|
||||
21
app/services/instagram/webhooks_base_service.rb
Normal file
21
app/services/instagram/webhooks_base_service.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
class Instagram::WebhooksBaseService
|
||||
private
|
||||
|
||||
def inbox_channel(instagram_id)
|
||||
messenger_channel = Channel::FacebookPage.where(instagram_id: instagram_id)
|
||||
@inbox = ::Inbox.find_by!(channel: messenger_channel)
|
||||
end
|
||||
|
||||
def find_or_create_contact(user)
|
||||
@contact_inbox = @inbox.contact_inboxes.where(source_id: user['id']).first
|
||||
@contact = @contact_inbox.contact if @contact_inbox
|
||||
return if @contact
|
||||
|
||||
@contact_inbox = @inbox.channel.create_contact_inbox(
|
||||
user['id'], user['name']
|
||||
)
|
||||
|
||||
@contact = @contact_inbox.contact
|
||||
ContactAvatarJob.perform_later(@contact, user['profile_pic']) if user['profile_pic']
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user