diff --git a/.rubocop.yml b/.rubocop.yml index 133f8e15c..00b581c0d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -13,6 +13,7 @@ Metrics/ClassLength: - 'app/models/conversation.rb' - 'app/mailers/conversation_reply_mailer.rb' - 'app/models/message.rb' + - 'app/builders/messages/facebook/message_builder.rb' RSpec/ExampleLength: Max: 25 Style/Documentation: diff --git a/app/builders/messages/facebook/message_builder.rb b/app/builders/messages/facebook/message_builder.rb index f0fc21f7d..dedc14be7 100644 --- a/app/builders/messages/facebook/message_builder.rb +++ b/app/builders/messages/facebook/message_builder.rb @@ -17,10 +17,15 @@ class Messages::Facebook::MessageBuilder end def perform + # This channel might require reauthorization, may be owner might have changed the fb password + return if @inbox.channel.reauthorization_required? + ActiveRecord::Base.transaction do build_contact build_message end + rescue Koala::Facebook::AuthenticationError + Rails.logger.info "Facebook Authorization expired for Inbox #{@inbox.id}" rescue StandardError => e Raven.capture_exception(e) true @@ -136,6 +141,9 @@ class Messages::Facebook::MessageBuilder begin k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook? result = k.get_object(@sender_id) || {} + rescue Koala::Facebook::AuthenticationError + @inbox.channel.authorization_error! + raise rescue StandardError => e result = {} Raven.capture_exception(e) diff --git a/app/mailers/administrator_notifications/channel_notifications_mailer.rb b/app/mailers/administrator_notifications/channel_notifications_mailer.rb index 6eee1ef42..4408a9a94 100644 --- a/app/mailers/administrator_notifications/channel_notifications_mailer.rb +++ b/app/mailers/administrator_notifications/channel_notifications_mailer.rb @@ -1,10 +1,23 @@ class AdministratorNotifications::ChannelNotificationsMailer < ApplicationMailer - def slack_disconnect(account) + def slack_disconnect return unless smtp_config_set_or_development? - emails = account.administrators.pluck(:email) subject = 'Your Slack integration has expired' - @action_url = "#{ENV['FRONTEND_URL']}/app/accounts/#{account.id}/settings/integrations/slack" - send_mail_with_liquid(to: emails, subject: subject) and return + @action_url = "#{ENV['FRONTEND_URL']}/app/accounts/#{Current.account.id}/settings/integrations/slack" + send_mail_with_liquid(to: admin_emails, subject: subject) and return + end + + def facebook_disconnect(inbox) + return unless smtp_config_set_or_development? + + subject = 'Your Facebook page connection has expired' + @action_url = "#{ENV['FRONTEND_URL']}/app/accounts/#{Current.account.id}/settings/inboxes/#{inbox.id}" + send_mail_with_liquid(to: admin_emails, subject: subject) and return + end + + private + + def admin_emails + Current.account.administrators.pluck(:email) end end diff --git a/app/models/concerns/reauthorizable.rb b/app/models/concerns/reauthorizable.rb index a0c43310b..5af92124a 100644 --- a/app/models/concerns/reauthorizable.rb +++ b/app/models/concerns/reauthorizable.rb @@ -36,9 +36,13 @@ module Reauthorizable # could used to manually prompt reauthorization if auth scope changes def prompt_reauthorization! ::Redis::Alfred.set(reauthorization_required_key, true) - return unless (is_a? Integrations::Hook) && slack? - AdministratorNotifications::ChannelNotificationsMailer.with(account: account).slack_disconnect(account)&.deliver_later + if (is_a? Integrations::Hook) && slack? + AdministratorNotifications::ChannelNotificationsMailer.with(account: account).slack_disconnect.deliver_later + end + return unless is_a? Channel::FacebookPage + + AdministratorNotifications::ChannelNotificationsMailer.with(account: account).facebook_disconnect(inbox).deliver_later end # call this after you successfully Reauthorized the object in UI diff --git a/app/views/mailers/administrator_notifications/channel_notifications_mailer/facebook_disconnect.liquid b/app/views/mailers/administrator_notifications/channel_notifications_mailer/facebook_disconnect.liquid new file mode 100644 index 000000000..c20f57da5 --- /dev/null +++ b/app/views/mailers/administrator_notifications/channel_notifications_mailer/facebook_disconnect.liquid @@ -0,0 +1,8 @@ +

Hello,

+ +

Your Facebook Inbox Access has expired.

+

Please reconnect Facebook Page to continue receiving messages in Chatwoot

+ +

+Click here to re-connect. +

diff --git a/spec/builders/messages/facebook/message_builder_spec.rb b/spec/builders/messages/facebook/message_builder_spec.rb index 52edd0413..dbfdb0c3d 100644 --- a/spec/builders/messages/facebook/message_builder_spec.rb +++ b/spec/builders/messages/facebook/message_builder_spec.rb @@ -8,20 +8,17 @@ describe ::Messages::Facebook::MessageBuilder do let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) } let(:fb_object) { double } - before do - allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) - allow(fb_object).to receive(:get_object).and_return( - { - first_name: 'Jane', - last_name: 'Dae', - account_id: facebook_channel.inbox.account_id, - profile_pic: 'https://via.placeholder.com/250x250.png' - }.with_indifferent_access - ) - end - describe '#perform' do it 'creates contact and message for the facebook inbox' do + allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) + allow(fb_object).to receive(:get_object).and_return( + { + first_name: 'Jane', + last_name: 'Dae', + account_id: facebook_channel.inbox.account_id, + profile_pic: 'https://via.placeholder.com/250x250.png' + }.with_indifferent_access + ) message_builder contact = facebook_channel.inbox.contacts.first @@ -30,5 +27,13 @@ describe ::Messages::Facebook::MessageBuilder do expect(contact.name).to eq('Jane Dae') expect(message.content).to eq('facebook message') end + + it 'increments channel authorization_error_count when error is thrown' do + allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) + allow(fb_object).to receive(:get_object).and_raise(Koala::Facebook::AuthenticationError.new(500, 'Error validating access token')) + message_builder + + expect(facebook_channel.authorization_error_count).to eq(1) + end end end diff --git a/spec/mailers/administrator_notifications/channel_notifications_mailer_spec.rb b/spec/mailers/administrator_notifications/channel_notifications_mailer_spec.rb new file mode 100644 index 000000000..b75a899c9 --- /dev/null +++ b/spec/mailers/administrator_notifications/channel_notifications_mailer_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe AdministratorNotifications::ChannelNotificationsMailer, type: :mailer do + let(:class_instance) { described_class.new } + let!(:account) { create(:account) } + let!(:administrator) { create(:user, :administrator, email: 'agent1@example.com', account: account) } + + before do + allow(described_class).to receive(:new).and_return(class_instance) + allow(class_instance).to receive(:smtp_config_set_or_development?).and_return(true) + end + + describe 'slack_disconnect' do + let(:mail) { described_class.with(account: account).slack_disconnect.deliver_now } + + it 'renders the subject' do + expect(mail.subject).to eq('Your Slack integration has expired') + end + + it 'renders the receiver email' do + expect(mail.to).to eq([administrator.email]) + end + end + + describe 'facebook_disconnect' do + let!(:facebook_channel) { create(:channel_facebook_page, account: account) } + let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } + let(:mail) { described_class.with(account: account).facebook_disconnect(facebook_inbox).deliver_now } + + it 'renders the subject' do + expect(mail.subject).to eq('Your Facebook page connection has expired') + end + + it 'renders the receiver email' do + expect(mail.to).to eq([administrator.email]) + end + end +end diff --git a/spec/mailers/agent_notifications/conversation_notifications_mailer_spec.rb b/spec/mailers/agent_notifications/conversation_notifications_mailer_spec.rb index 3f909fb97..54dd9dae3 100644 --- a/spec/mailers/agent_notifications/conversation_notifications_mailer_spec.rb +++ b/spec/mailers/agent_notifications/conversation_notifications_mailer_spec.rb @@ -14,7 +14,7 @@ RSpec.describe AgentNotifications::ConversationNotificationsMailer, type: :maile end describe 'conversation_creation' do - let(:mail) { described_class.conversation_creation(conversation, agent).deliver_now } + let(:mail) { described_class.with(account: account).conversation_creation(conversation, agent).deliver_now } it 'renders the subject' do expect(mail.subject).to eq("#{agent.available_name}, A new conversation [ID - #{conversation @@ -27,7 +27,7 @@ RSpec.describe AgentNotifications::ConversationNotificationsMailer, type: :maile end describe 'conversation_assignment' do - let(:mail) { described_class.conversation_assignment(conversation, agent).deliver_now } + let(:mail) { described_class.with(account: account).conversation_assignment(conversation, agent).deliver_now } it 'renders the subject' do expect(mail.subject).to eq("#{agent.available_name}, A new conversation [ID - #{conversation.display_id}] has been assigned to you.") @@ -40,7 +40,7 @@ RSpec.describe AgentNotifications::ConversationNotificationsMailer, type: :maile describe 'conversation_mention' do let(:message) { create(:message, conversation: conversation, account: account) } - let(:mail) { described_class.conversation_mention(message, agent).deliver_now } + let(:mail) { described_class.with(account: account).conversation_mention(message, agent).deliver_now } it 'renders the subject' do expect(mail.subject).to eq("#{agent.available_name}, You have been mentioned in conversation [ID - #{conversation.display_id}]") @@ -53,7 +53,7 @@ RSpec.describe AgentNotifications::ConversationNotificationsMailer, type: :maile describe 'assigned_conversation_new_message' do let(:message) { create(:message, conversation: conversation, account: account) } - let(:mail) { described_class.assigned_conversation_new_message(message, agent).deliver_now } + let(:mail) { described_class.with(account: account).assigned_conversation_new_message(message, agent).deliver_now } it 'renders the subject' do expect(mail.subject).to eq("#{agent.available_name}, New message in your assigned conversation [ID - #{message.conversation.display_id}].") diff --git a/spec/models/channel/facebook_page_spec.rb b/spec/models/channel/facebook_page_spec.rb index bcd468556..343b0de09 100644 --- a/spec/models/channel/facebook_page_spec.rb +++ b/spec/models/channel/facebook_page_spec.rb @@ -13,6 +13,17 @@ RSpec.describe Channel::FacebookPage do describe 'concerns' do it_behaves_like 'reauthorizable' + + context 'when prompt_reauthorization!' do + it 'calls channel notifier mail for facebook' do + admin_mailer = double + mailer_double = double + expect(AdministratorNotifications::ChannelNotificationsMailer).to receive(:with).and_return(admin_mailer) + expect(admin_mailer).to receive(:facebook_disconnect).with(channel.inbox).and_return(mailer_double) + expect(mailer_double).to receive(:deliver_later) + channel.prompt_reauthorization! + end + end end it 'has a valid name' do