From 026e03c3073284be4e5d02b71d7027be95f9f8b2 Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Tue, 18 Apr 2023 07:48:23 -0600 Subject: [PATCH 001/101] fix: Handle spaces in CC/BCC email lists (#6788) When the CC field is generated in the UI, the email values are joined together with ", " but when they are parsed, we currently split by just ",". This causes an error on the backend and on the frontend. It seems reasonable to update the code to allow whitespace in the input and to split by `\s*,\s` and also to trim leading and trailing whitespace from the CC list. --------- Co-authored-by: Sojan --- app/builders/messages/message_builder.rb | 4 ++-- .../widgets/conversation/helpers/emailHeadHelper.js | 2 +- .../helpers/specs/emailHeadHelper.spec.js | 3 +++ spec/builders/messages/message_builder_spec.rb | 11 +++++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/builders/messages/message_builder.rb b/app/builders/messages/message_builder.rb index ba5861859..aca06cd04 100644 --- a/app/builders/messages/message_builder.rb +++ b/app/builders/messages/message_builder.rb @@ -49,10 +49,10 @@ class Messages::MessageBuilder return unless @conversation.inbox&.inbox_type == 'Email' cc_emails = [] - cc_emails = @params[:cc_emails].split(',') if @params[:cc_emails].present? + cc_emails = @params[:cc_emails].gsub(/\s+/, '').split(',') if @params[:cc_emails].present? bcc_emails = [] - bcc_emails = @params[:bcc_emails].split(',') if @params[:bcc_emails].present? + bcc_emails = @params[:bcc_emails].gsub(/\s+/, '').split(',') if @params[:bcc_emails].present? all_email_addresses = cc_emails + bcc_emails validate_email_addresses(all_email_addresses) diff --git a/app/javascript/dashboard/components/widgets/conversation/helpers/emailHeadHelper.js b/app/javascript/dashboard/components/widgets/conversation/helpers/emailHeadHelper.js index ad36393a7..5304627c4 100644 --- a/app/javascript/dashboard/components/widgets/conversation/helpers/emailHeadHelper.js +++ b/app/javascript/dashboard/components/widgets/conversation/helpers/emailHeadHelper.js @@ -2,6 +2,6 @@ import emailValidator from 'vuelidate/lib/validators/email'; export const validEmailsByComma = value => { if (!value.length) return true; - const emails = value.split(','); + const emails = value.replace(/\s+/g, '').split(','); return emails.every(email => emailValidator(email)); }; diff --git a/app/javascript/dashboard/components/widgets/conversation/helpers/specs/emailHeadHelper.spec.js b/app/javascript/dashboard/components/widgets/conversation/helpers/specs/emailHeadHelper.spec.js index 2275a810b..7c9142ee4 100644 --- a/app/javascript/dashboard/components/widgets/conversation/helpers/specs/emailHeadHelper.spec.js +++ b/app/javascript/dashboard/components/widgets/conversation/helpers/specs/emailHeadHelper.spec.js @@ -10,4 +10,7 @@ describe('#validEmailsByComma', () => { it('returns false when one of the email passed is invalid', () => { expect(validEmailsByComma('ni@njan.com,pova.da')).toEqual(false); }); + it('strips spaces between emails before validating', () => { + expect(validEmailsByComma('1@test.com , 2@test.com')).toEqual(true); + }); }); diff --git a/spec/builders/messages/message_builder_spec.rb b/spec/builders/messages/message_builder_spec.rb index 845c1ab99..be5d60834 100644 --- a/spec/builders/messages/message_builder_spec.rb +++ b/spec/builders/messages/message_builder_spec.rb @@ -98,6 +98,17 @@ describe ::Messages::MessageBuilder do params = ActionController::Parameters.new({ cc_emails: 'test.com', bcc_emails: 'test_bcc.com' }) expect { described_class.new(user, conversation, params).perform }.to raise_error 'Invalid email address' end + + it 'strips off whitespace before saving cc_emails and bcc_emails' do + cc_emails = ' test1@test.com , test2@test.com, test3@test.com' + bcc_emails = 'test1@test.com,test2@test.com, test3@test.com ' + params = ActionController::Parameters.new({ cc_emails: cc_emails, bcc_emails: bcc_emails }) + + message = described_class.new(user, conversation, params).perform + + expect(message.content_attributes[:cc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] + expect(message.content_attributes[:bcc_emails]).to eq ['test1@test.com', 'test2@test.com', 'test3@test.com'] + end end end end From c5c36af5291d532b78bfe15a006b4c14ec4a057f Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Tue, 18 Apr 2023 18:30:01 -0700 Subject: [PATCH 002/101] fix: Remove fallback phone_number search in WhatsApp event processing (#6904) --- app/jobs/webhooks/whatsapp_events_job.rb | 8 ++--- spec/factories/channel/channel_whatsapp.rb | 2 +- .../jobs/webhooks/whatsapp_events_job_spec.rb | 33 ++++++++++++++++++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/jobs/webhooks/whatsapp_events_job.rb b/app/jobs/webhooks/whatsapp_events_job.rb index 4a2c50065..b84e9cde5 100644 --- a/app/jobs/webhooks/whatsapp_events_job.rb +++ b/app/jobs/webhooks/whatsapp_events_job.rb @@ -2,7 +2,7 @@ class Webhooks::WhatsappEventsJob < ApplicationJob queue_as :low def perform(params = {}) - channel = find_channel_from_whatsapp_business_payload(params) || find_channel(params) + channel = find_channel_from_whatsapp_business_payload(params) return if channel_is_inactive?(channel) case channel.provider @@ -23,7 +23,7 @@ class Webhooks::WhatsappEventsJob < ApplicationJob false end - def find_channel(params) + def find_channel_by_url_param(params) return unless params[:phone_number] Channel::Whatsapp.find_by(phone_number: params[:phone_number]) @@ -33,9 +33,9 @@ class Webhooks::WhatsappEventsJob < ApplicationJob # for the case where facebook cloud api support multiple numbers for a single app # https://github.com/chatwoot/chatwoot/issues/4712#issuecomment-1173838350 # we will give priority to the phone_number in the payload - return unless params[:object] == 'whatsapp_business_account' + return get_channel_from_wb_payload(params) if params[:object] == 'whatsapp_business_account' - get_channel_from_wb_payload(params) + find_channel_by_url_param(params) end def get_channel_from_wb_payload(wb_params) diff --git a/spec/factories/channel/channel_whatsapp.rb b/spec/factories/channel/channel_whatsapp.rb index 58f569ba3..b2d482e1d 100644 --- a/spec/factories/channel/channel_whatsapp.rb +++ b/spec/factories/channel/channel_whatsapp.rb @@ -2,7 +2,7 @@ FactoryBot.define do factory :channel_whatsapp, class: 'Channel::Whatsapp' do sequence(:phone_number) { |n| "+123456789#{n}1" } account - provider_config { { 'api_key' => 'test_key' } } + provider_config { { 'api_key' => 'test_key', 'phone_number_id' => 'random_id' } } message_templates do [{ 'name' => 'sample_shipping_confirmation', 'status' => 'approved', diff --git a/spec/jobs/webhooks/whatsapp_events_job_spec.rb b/spec/jobs/webhooks/whatsapp_events_job_spec.rb index d98005427..187d4c62c 100644 --- a/spec/jobs/webhooks/whatsapp_events_job_spec.rb +++ b/spec/jobs/webhooks/whatsapp_events_job_spec.rb @@ -4,7 +4,24 @@ RSpec.describe Webhooks::WhatsappEventsJob, type: :job do subject(:job) { described_class } let(:channel) { create(:channel_whatsapp, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false) } - let(:params) { { phone_number: channel.phone_number } } + let(:params) do + { + object: 'whatsapp_business_account', + phone_number: channel.phone_number, + entry: [{ + changes: [ + { + value: { + metadata: { + phone_number_id: channel.provider_config['phone_number_id'], + display_phone_number: channel.phone_number.delete('+') + } + } + } + ] + }] + } + end let(:process_service) { double } before do @@ -24,6 +41,20 @@ RSpec.describe Webhooks::WhatsappEventsJob, type: :job do job.perform_now(params) end + it 'will not enqueue message jobs based on phone number in the URL if the entry payload is not present' do + params = { + object: 'whatsapp_business_account', + phone_number: channel.phone_number, + entry: [{ changes: [{}] }] + } + allow(Whatsapp::IncomingMessageWhatsappCloudService).to receive(:new) + allow(Whatsapp::IncomingMessageService).to receive(:new) + + expect(Whatsapp::IncomingMessageWhatsappCloudService).not_to receive(:new) + expect(Whatsapp::IncomingMessageService).not_to receive(:new) + job.perform_now(params) + end + it 'will not enqueue Whatsapp::IncomingMessageWhatsappCloudService if channel reauthorization required' do channel.prompt_reauthorization! allow(Whatsapp::IncomingMessageWhatsappCloudService).to receive(:new).and_return(process_service) From e6505fc7a42ca9f3de1735939b488a18a979adcb Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Tue, 18 Apr 2023 19:44:57 -0700 Subject: [PATCH 003/101] chore: Cache the dashboard app on the first load (#6774) --- .../components/widgets/DashboardApp/Frame.vue | 14 +++++++++++++- .../widgets/conversation/ConversationBox.vue | 10 ++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/DashboardApp/Frame.vue b/app/javascript/dashboard/components/widgets/DashboardApp/Frame.vue index c1db1ad4d..395006704 100644 --- a/app/javascript/dashboard/components/widgets/DashboardApp/Frame.vue +++ b/app/javascript/dashboard/components/widgets/DashboardApp/Frame.vue @@ -1,5 +1,5 @@