diff --git a/app/controllers/api/v1/accounts/channels/twilio_channels_controller.rb b/app/controllers/api/v1/accounts/channels/twilio_channels_controller.rb index ebf8e49dd..58ec3bfca 100644 --- a/app/controllers/api/v1/accounts/channels/twilio_channels_controller.rb +++ b/app/controllers/api/v1/accounts/channels/twilio_channels_controller.rb @@ -1,3 +1,6 @@ +# TODO : Move this to inboxes controller and deprecate this controller +# No need to retain this controller as we could handle everything centrally in inboxes controller + class Api::V1::Accounts::Channels::TwilioChannelsController < Api::V1::Accounts::BaseController before_action :authorize_request diff --git a/app/javascript/dashboard/store/modules/conversations/index.js b/app/javascript/dashboard/store/modules/conversations/index.js index ca0759320..fc6f10979 100644 --- a/app/javascript/dashboard/store/modules/conversations/index.js +++ b/app/javascript/dashboard/store/modules/conversations/index.js @@ -78,10 +78,7 @@ export const mutations = { } }, [types.SET_ALL_ATTACHMENTS](_state, { id, data }) { - const attachments = _state.attachments[id] || []; - - attachments.push(...data); - _state.attachments[id] = [...attachments]; + _state.attachments[id] = [...data]; }, [types.SET_MISSING_MESSAGES](_state, { id, data }) { const [chat] = _state.allConversations.filter(c => c.id === id); diff --git a/app/models/channel/twilio_sms.rb b/app/models/channel/twilio_sms.rb index 8dbe47703..e4575f58a 100644 --- a/app/models/channel/twilio_sms.rb +++ b/app/models/channel/twilio_sms.rb @@ -30,6 +30,11 @@ class Channel::TwilioSms < ApplicationRecord # The same parameter is used to store api_key_secret if api_key authentication is opted validates :auth_token, presence: true + EDITABLE_ATTRS = [ + :account_sid, + :auth_token + ].freeze + # Must have _one_ of messaging_service_sid _or_ phone_number, and messaging_service_sid is preferred validates :messaging_service_sid, uniqueness: true, presence: true, unless: :phone_number? validates :phone_number, absence: true, if: :messaging_service_sid? diff --git a/app/services/instagram/message_text.rb b/app/services/instagram/message_text.rb index 66445f5a5..e4b88c64d 100644 --- a/app/services/instagram/message_text.rb +++ b/app/services/instagram/message_text.rb @@ -41,10 +41,20 @@ class Instagram::MessageText < Instagram::BaseMessageText # Access token has expired or become invalid. channel.authorization_error! if error_code == 190 + # TODO: Remove this once we have a better way to handle this error. + # https://developers.facebook.com/docs/messenger-platform/instagram/features/user-profile/#user-consent + # The error typically occurs when the connected Instagram account attempts to send a message to a user + # who has never messaged this Instagram account before. + # We can only get consent to access a user's profile if they have previously sent a message to the connected Instagram account. + # In such cases, we receive the error "User consent is required to access user profile". + # We can safely ignore this error. + return if error_code == 230 + Rails.logger.warn("[InstagramUserFetchError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}") Rails.logger.warn("[InstagramUserFetchError]: #{error_message} #{error_code}") - ChatwootExceptionTracker.new(parsed_response, account: @inbox.account).capture_exception + exception = StandardError.new("#{error_message} (Code: #{error_code})") + ChatwootExceptionTracker.new(exception, account: @inbox.account).capture_exception end def base_uri diff --git a/app/views/api/v1/models/_inbox.json.jbuilder b/app/views/api/v1/models/_inbox.json.jbuilder index 42a1a7370..0747924d9 100644 --- a/app/views/api/v1/models/_inbox.json.jbuilder +++ b/app/views/api/v1/models/_inbox.json.jbuilder @@ -62,6 +62,10 @@ json.instagram_id resource.channel.try(:instagram_id) if resource.instagram? json.messaging_service_sid resource.channel.try(:messaging_service_sid) json.phone_number resource.channel.try(:phone_number) json.medium resource.channel.try(:medium) if resource.twilio? +if resource.twilio? && Current.account_user&.administrator? + json.auth_token resource.channel.try(:auth_token) + json.account_sid resource.channel.try(:account_sid) +end if resource.email? ## Email Channel Attributes diff --git a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb index 7b3dafccb..f8655da44 100644 --- a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb @@ -147,6 +147,32 @@ RSpec.describe 'Inboxes API', type: :request do expect(data[:imap_login]).to eq('test@test.com') end + context 'when it is a Twilio inbox' do + let(:twilio_channel) { create(:channel_twilio_sms, account: account, account_sid: 'AC123', auth_token: 'secrettoken') } + let(:twilio_inbox) { create(:inbox, channel: twilio_channel, account: account) } + + it 'returns auth_token and account_sid for admin' do + get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}", + headers: admin.create_new_auth_token, + as: :json + expect(response).to have_http_status(:success) + data = JSON.parse(response.body, symbolize_names: true) + expect(data[:auth_token]).to eq('secrettoken') + expect(data[:account_sid]).to eq('AC123') + end + + it "doesn't return auth_token and account_sid for agent" do + create(:inbox_member, user: agent, inbox: twilio_inbox) + get "/api/v1/accounts/#{account.id}/inboxes/#{twilio_inbox.id}", + headers: agent.create_new_auth_token, + as: :json + expect(response).to have_http_status(:success) + data = JSON.parse(response.body, symbolize_names: true) + expect(data[:auth_token]).to be_nil + expect(data[:account_sid]).to be_nil + end + end + it 'fetch API inbox without hmac token when agent' do api_channel = create(:channel_api, account: account) api_inbox = create(:inbox, channel: api_channel, account: account) @@ -518,6 +544,22 @@ RSpec.describe 'Inboxes API', type: :request do expect(email_channel.reload.email).to eq('emailtest@email.test') end + it 'updates twilio sms inbox when administrator' do + twilio_sms_channel = create(:channel_twilio_sms, account: account) + twilio_sms_inbox = create(:inbox, channel: twilio_sms_channel, account: account) + expect(twilio_sms_inbox.reload.channel.account_sid).not_to eq('account_sid') + expect(twilio_sms_inbox.reload.channel.auth_token).not_to eq('new_auth_token') + + patch "/api/v1/accounts/#{account.id}/inboxes/#{twilio_sms_inbox.id}", + headers: admin.create_new_auth_token, + params: { channel: { account_sid: 'account_sid', auth_token: 'new_auth_token' } }, + as: :json + + expect(response).to have_http_status(:success) + expect(twilio_sms_inbox.reload.channel.account_sid).to eq('account_sid') + expect(twilio_sms_inbox.reload.channel.auth_token).to eq('new_auth_token') + end + it 'updates email inbox with imap when administrator' do email_channel = create(:channel_email, account: account) email_inbox = create(:inbox, channel: email_channel, account: account)