fix: Handle application errors in Sentry (#1982)

- Handle notification errors for attachment messages
- Fix empty identifiers being passed
- Fix 404 when invalid source id
- Handle webhook exceptions
This commit is contained in:
Sojan Jose 2021-03-27 12:27:48 +05:30 committed by GitHub
parent 9903e47896
commit c453455ad1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 43 additions and 6 deletions

View file

@ -34,7 +34,9 @@ class ContactIdentifyAction
def update_contact def update_contact
custom_attributes = params[:custom_attributes] ? @contact.custom_attributes.merge(params[:custom_attributes]) : @contact.custom_attributes custom_attributes = params[:custom_attributes] ? @contact.custom_attributes.merge(params[:custom_attributes]) : @contact.custom_attributes
@contact.update!(params.slice(:name, :email, :identifier).merge({ custom_attributes: custom_attributes })) # blank identifier or email will throw unique index error
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
@contact.update!(params.slice(:name, :email, :identifier).reject { |_k, v| v.blank? }.merge({ custom_attributes: custom_attributes }))
ContactAvatarJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present? ContactAvatarJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
end end

View file

@ -32,7 +32,8 @@ class Api::V1::Widget::BaseController < ApplicationController
@contact_inbox = @web_widget.inbox.contact_inboxes.find_by( @contact_inbox = @web_widget.inbox.contact_inboxes.find_by(
source_id: auth_token_params[:source_id] source_id: auth_token_params[:source_id]
) )
@contact = @contact_inbox.contact @contact = @contact_inbox&.contact
raise ActiveRecord::RecordNotFound unless @contact
end end
def create_conversation def create_conversation

View file

@ -6,7 +6,7 @@ class ApplicationMailbox < ActionMailbox::Base
def self.reply_mail? def self.reply_mail?
proc do |inbound_mail_obj| proc do |inbound_mail_obj|
is_a_reply_email = false is_a_reply_email = false
inbound_mail_obj.mail.to.each do |email| inbound_mail_obj.mail.to&.each do |email|
username = email.split('@')[0] username = email.split('@')[0]
match_result = username.match(REPLY_EMAIL_USERNAME_PATTERN) match_result = username.match(REPLY_EMAIL_USERNAME_PATTERN)
if match_result if match_result
@ -21,7 +21,7 @@ class ApplicationMailbox < ActionMailbox::Base
def self.support_mail? def self.support_mail?
proc do |inbound_mail_obj| proc do |inbound_mail_obj|
is_a_support_email = false is_a_support_email = false
inbound_mail_obj.mail.to.each do |email| inbound_mail_obj.mail.to&.each do |email|
channel = Channel::Email.find_by('email = ? OR forward_to_email = ?', email, email) channel = Channel::Email.find_by('email = ? OR forward_to_email = ?', email, email)
if channel.present? if channel.present?
is_a_support_email = true is_a_support_email = true

View file

@ -70,7 +70,7 @@ class Notification < ApplicationRecord
I18n.t( I18n.t(
'notifications.notification_title.assigned_conversation_new_message', 'notifications.notification_title.assigned_conversation_new_message',
display_id: conversation.display_id, display_id: conversation.display_id,
content: primary_actor.content.truncate_words(10) content: primary_actor.content&.truncate_words(10)
) )
when 'conversation_mention' when 'conversation_mention'
I18n.t('notifications.notification_title.conversation_mention', display_id: conversation.display_id, name: secondary_actor.name) I18n.t('notifications.notification_title.conversation_mention', display_id: conversation.display_id, name: secondary_actor.name)

View file

@ -1,4 +1,5 @@
module ExceptionList module ExceptionList
URI_EXCEPTIONS = [Errno::ETIMEDOUT, Errno::ECONNREFUSED, URI::InvalidURIError, Net::OpenTimeout, SocketError].freeze URI_EXCEPTIONS = [Errno::ETIMEDOUT, Errno::ECONNREFUSED, URI::InvalidURIError, Net::OpenTimeout, SocketError].freeze
REST_CLIENT_EXCEPTIONS = [RestClient::NotFound, RestClient::GatewayTimeout, RestClient::BadRequest, RestClient::MethodNotAllowed].freeze REST_CLIENT_EXCEPTIONS = [RestClient::NotFound, RestClient::GatewayTimeout, RestClient::BadRequest,
RestClient::MethodNotAllowed, RestClient::Forbidden].freeze
end end

View file

@ -44,5 +44,15 @@ describe ::ContactIdentifyAction do
expect { contact.reload }.to raise_error(ActiveRecord::RecordNotFound) expect { contact.reload }.to raise_error(ActiveRecord::RecordNotFound)
end end
end end
context 'when contacts with blank identifiers exist and identify action is called with blank identifier' do
it 'updates the attributes of contact passed in to identify action' do
create(:contact, account: account, identifier: '')
params = { identifier: '', name: 'new name' }
result = described_class.new(contact: contact, params: params).perform
expect(result.id).to eq contact.id
expect(result.name).to eq 'new name'
end
end
end end
end end

View file

@ -25,6 +25,21 @@ RSpec.describe '/api/v1/widget/conversations/toggle_typing', type: :request do
expect(json_response['status']).to eq(conversation.status) expect(json_response['status']).to eq(conversation.status)
end end
end end
context 'with a conversation but invalid source id' do
it 'returns the correct conversation params' do
allow(Rails.configuration.dispatcher).to receive(:dispatch)
payload = { source_id: 'invalid source id', inbox_id: web_widget.inbox.id }
token = ::Widget::TokenService.new(payload: payload).generate_token
get '/api/v1/widget/conversations',
headers: { 'X-Auth-Token' => token },
params: { website_token: web_widget.website_token },
as: :json
expect(response).to have_http_status(:not_found)
end
end
end end
describe 'POST /api/v1/widget/conversations' do describe 'POST /api/v1/widget/conversations' do

View file

@ -41,6 +41,14 @@ RSpec.describe Notification do
#{message.content.truncate_words(10)}" #{message.content.truncate_words(10)}"
end end
it 'returns appropriate title suited for the notification type assigned_conversation_new_message when attachment message' do
# checking content nil should be suffice for attachments
message = create(:message, sender: create(:user), content: nil)
notification = create(:notification, notification_type: 'assigned_conversation_new_message', primary_actor: message)
expect(notification.push_message_title).to eq "[New message] - ##{notification.conversation.display_id} "
end
it 'returns appropriate title suited for the notification type conversation_mention' do it 'returns appropriate title suited for the notification type conversation_mention' do
message = create(:message, sender: create(:user)) message = create(:message, sender: create(:user))
notification = create(:notification, notification_type: 'conversation_mention', primary_actor: message, secondary_actor: message.sender) notification = create(:notification, notification_type: 'conversation_mention', primary_actor: message, secondary_actor: message.sender)