From 4250c40d1d550511eb0d9788c7353e94846dca78 Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Wed, 27 Apr 2022 18:33:22 +0530 Subject: [PATCH 01/11] chore: Upgrade rails to 6.1.5.1 (#4570) --- Gemfile.lock | 116 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2789f09da..9edce0f36 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,63 +9,63 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (6.1.4.7) - actionpack (= 6.1.4.7) - activesupport (= 6.1.4.7) + actioncable (6.1.5.1) + actionpack (= 6.1.5.1) + activesupport (= 6.1.5.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.4.7) - actionpack (= 6.1.4.7) - activejob (= 6.1.4.7) - activerecord (= 6.1.4.7) - activestorage (= 6.1.4.7) - activesupport (= 6.1.4.7) + actionmailbox (6.1.5.1) + actionpack (= 6.1.5.1) + activejob (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) mail (>= 2.7.1) - actionmailer (6.1.4.7) - actionpack (= 6.1.4.7) - actionview (= 6.1.4.7) - activejob (= 6.1.4.7) - activesupport (= 6.1.4.7) + actionmailer (6.1.5.1) + actionpack (= 6.1.5.1) + actionview (= 6.1.5.1) + activejob (= 6.1.5.1) + activesupport (= 6.1.5.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.4.7) - actionview (= 6.1.4.7) - activesupport (= 6.1.4.7) + actionpack (6.1.5.1) + actionview (= 6.1.5.1) + activesupport (= 6.1.5.1) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.4.7) - actionpack (= 6.1.4.7) - activerecord (= 6.1.4.7) - activestorage (= 6.1.4.7) - activesupport (= 6.1.4.7) + actiontext (6.1.5.1) + actionpack (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) nokogiri (>= 1.8.5) - actionview (6.1.4.7) - activesupport (= 6.1.4.7) + actionview (6.1.5.1) + activesupport (= 6.1.5.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) active_record_query_trace (1.8) - activejob (6.1.4.7) - activesupport (= 6.1.4.7) + activejob (6.1.5.1) + activesupport (= 6.1.5.1) globalid (>= 0.3.6) - activemodel (6.1.4.7) - activesupport (= 6.1.4.7) - activerecord (6.1.4.7) - activemodel (= 6.1.4.7) - activesupport (= 6.1.4.7) + activemodel (6.1.5.1) + activesupport (= 6.1.5.1) + activerecord (6.1.5.1) + activemodel (= 6.1.5.1) + activesupport (= 6.1.5.1) activerecord-import (1.3.0) activerecord (>= 4.2) - activestorage (6.1.4.7) - actionpack (= 6.1.4.7) - activejob (= 6.1.4.7) - activerecord (= 6.1.4.7) - activesupport (= 6.1.4.7) - marcel (~> 1.0.0) + activestorage (6.1.5.1) + actionpack (= 6.1.5.1) + activejob (= 6.1.5.1) + activerecord (= 6.1.5.1) + activesupport (= 6.1.5.1) + marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (6.1.4.7) + activesupport (6.1.5.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -136,7 +136,7 @@ GEM climate_control (1.0.1) coderay (1.1.3) commonmarker (0.23.4) - concurrent-ruby (1.1.9) + concurrent-ruby (1.1.10) connection_pool (2.2.5) crack (0.4.5) rexml @@ -349,7 +349,7 @@ GEM listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.14.0) + loofah (2.16.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -419,31 +419,31 @@ GEM rack-test (1.1.0) rack (>= 1.0, < 3) rack-timeout (0.6.0) - rails (6.1.4.7) - actioncable (= 6.1.4.7) - actionmailbox (= 6.1.4.7) - actionmailer (= 6.1.4.7) - actionpack (= 6.1.4.7) - actiontext (= 6.1.4.7) - actionview (= 6.1.4.7) - activejob (= 6.1.4.7) - activemodel (= 6.1.4.7) - activerecord (= 6.1.4.7) - activestorage (= 6.1.4.7) - activesupport (= 6.1.4.7) + rails (6.1.5.1) + actioncable (= 6.1.5.1) + actionmailbox (= 6.1.5.1) + actionmailer (= 6.1.5.1) + actionpack (= 6.1.5.1) + actiontext (= 6.1.5.1) + actionview (= 6.1.5.1) + activejob (= 6.1.5.1) + activemodel (= 6.1.5.1) + activerecord (= 6.1.5.1) + activestorage (= 6.1.5.1) + activesupport (= 6.1.5.1) bundler (>= 1.15.0) - railties (= 6.1.4.7) + railties (= 6.1.5.1) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) rails-html-sanitizer (1.4.2) loofah (~> 2.3) - railties (6.1.4.7) - actionpack (= 6.1.4.7) - activesupport (= 6.1.4.7) + railties (6.1.5.1) + actionpack (= 6.1.5.1) + activesupport (= 6.1.5.1) method_source - rake (>= 0.13) + rake (>= 12.2) thor (~> 1.0) rainbow (3.1.1) rake (13.0.6) @@ -755,4 +755,4 @@ RUBY VERSION ruby 3.0.2p107 BUNDLED WITH - 2.3.8 + 2.3.9 From 95c7a24dd1fc05fb2a692c5b4e14bda8ce85be2b Mon Sep 17 00:00:00 2001 From: "Aswin Dev P.S" Date: Wed, 27 Apr 2022 18:56:35 +0530 Subject: [PATCH 02/11] fix: Unattendeed conversation count in agent metrics (#4568) --- app/builders/v2/report_builder.rb | 2 +- .../api/v2/accounts/report_controller_spec.rb | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/app/builders/v2/report_builder.rb b/app/builders/v2/report_builder.rb index 475a34ccb..5cd8b4a63 100644 --- a/app/builders/v2/report_builder.rb +++ b/app/builders/v2/report_builder.rb @@ -96,7 +96,7 @@ class V2::ReportBuilder def conversations @open_conversations = scope.conversations.where(account_id: @account.id).open - first_response_count = scope.reporting_events.where(name: 'first_response', conversation_id: @open_conversations.pluck('id')).count + first_response_count = @account.reporting_events.where(name: 'first_response', conversation_id: @open_conversations.pluck('id')).count metric = { open: @open_conversations.count, unattended: @open_conversations.count - first_response_count diff --git a/spec/controllers/api/v2/accounts/report_controller_spec.rb b/spec/controllers/api/v2/accounts/report_controller_spec.rb index acad237ec..c14b570d2 100644 --- a/spec/controllers/api/v2/accounts/report_controller_spec.rb +++ b/spec/controllers/api/v2/accounts/report_controller_spec.rb @@ -58,7 +58,11 @@ RSpec.describe 'Reports API', type: :request do expect(current_day_metric.length).to eq(1) expect(current_day_metric[0]['value']).to eq(10) end + end + end + describe 'GET /api/v2/accounts/:account_id/reports/conversations' do + context 'when it is an authenticated user' do it 'return conversation metrics in account level' do unassigned_conversation = create(:conversation, account: account, inbox: inbox, assignee: nil, created_at: Time.zone.today) @@ -102,25 +106,45 @@ RSpec.describe 'Reports API', type: :request do expect(user_metrics['metric']['open']).to eq(2) expect(user_metrics['metric']['unattended']).to eq(2) end + end - it 'return conversation metrics for specific user in account level' do - create_list(:conversation, 2, account: account, inbox: inbox, - assignee: admin, created_at: Time.zone.today) + context 'when an agent1 associated to conversation having first reply from agent2' do + let(:listener) { ReportingEventListener.instance } + let(:account) { create(:account) } + let(:admin) { create(:user, account: account, role: :administrator) } + + it 'returns unattended conversation count zero for agent1' do + agent1 = create(:user, account: account, role: :agent) + agent2 = create(:user, account: account, role: :agent) + conversation = create(:conversation, account: account, + inbox: inbox, assignee: agent2) + + create(:message, message_type: 'incoming', content: 'Hi', + account: account, inbox: inbox, + conversation: conversation) + first_reply_message = create(:message, message_type: 'outgoing', content: 'Hi', + account: account, inbox: inbox, sender: agent2, + conversation: conversation) + + event = Events::Base.new('first.reply.created', Time.zone.now, message: first_reply_message) + listener.first_reply_created(event) + + conversation.assignee_id = agent1.id + conversation.save! get "/api/v2/accounts/#{account.id}/reports/conversations", params: { - type: :agent, - user_id: user.id + type: :agent }, headers: admin.create_new_auth_token, as: :json - expect(response).to have_http_status(:success) - json_response = JSON.parse(response.body) - expect(json_response.blank?).to be false - expect(json_response[0]['metric']['open']).to eq(10) - expect(json_response[0]['metric']['unattended']).to eq(10) + user_metrics = json_response.find { |item| item['name'] == agent1[:name] } + expect(user_metrics.present?).to be true + + expect(user_metrics['metric']['open']).to eq(1) + expect(user_metrics['metric']['unattended']).to eq(0) end end end From 8348392d43b79950bb6c307629201b711aaabe40 Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Wed, 27 Apr 2022 20:10:40 +0530 Subject: [PATCH 03/11] fix: Disable automation on tweets (#4571) Fixes #4565 --- .../automation_rules/action_service.rb | 10 ++ .../automation_rule_listener_spec.rb | 110 +++++++++--------- 2 files changed, 66 insertions(+), 54 deletions(-) diff --git a/app/services/automation_rules/action_service.rb b/app/services/automation_rules/action_service.rb index e88ca06dd..12bb95cb9 100644 --- a/app/services/automation_rules/action_service.rb +++ b/app/services/automation_rules/action_service.rb @@ -22,6 +22,8 @@ class AutomationRules::ActionService private def send_attachment(blob_ids) + return if conversation_a_tweet? + return unless @rule.files.attached? blob = ActiveStorage::Blob.find(blob_ids) @@ -61,6 +63,8 @@ class AutomationRules::ActionService end def send_message(message) + return if conversation_a_tweet? + params = { content: message[0], private: false, content_attributes: { automation_rule_id: @rule.id } } mb = Messages::MessageBuilder.new(nil, @conversation, params) mb.perform @@ -101,4 +105,10 @@ class AutomationRules::ActionService def team_belongs_to_account?(team_ids) @account.team_ids.include?(team_ids[0]) end + + def conversation_a_tweet? + return false if @conversation.additional_attributes.blank? + + @conversation.additional_attributes['type'] == 'tweet' + end end diff --git a/spec/listeners/automation_rule_listener_spec.rb b/spec/listeners/automation_rule_listener_spec.rb index 6213e4450..6ab931554 100644 --- a/spec/listeners/automation_rule_listener_spec.rb +++ b/spec/listeners/automation_rule_listener_spec.rb @@ -4,9 +4,8 @@ describe AutomationRuleListener do let!(:account) { create(:account) } let(:inbox) { create(:inbox, account: account) } let(:contact) { create(:contact, account: account, identifier: '123') } - let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: inbox) } - let(:conversation) { create(:conversation, contact_inbox: contact_inbox, inbox: inbox, account: account) } - let(:automation_rule) { create(:automation_rule, account: account, name: 'Test Automation Rule') } + let(:conversation) { create(:conversation, inbox: inbox, account: account) } + let!(:automation_rule) { create(:automation_rule, account: account, name: 'Test Automation Rule') } let(:team) { create(:team, account: account) } let(:user_1) { create(:user, role: 0) } let(:user_2) { create(:user, role: 0) } @@ -214,30 +213,23 @@ describe AutomationRuleListener do context 'when rule matches' do it 'triggers automation rule to assign team' do expect(conversation.team_id).not_to eq(team.id) - - automation_rule listener.conversation_updated(event) - conversation.reload + expect(conversation.team_id).to eq(team.id) end it 'triggers automation rule to add label' do expect(conversation.labels).to eq([]) - - automation_rule listener.conversation_updated(event) - conversation.reload + expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer') end it 'triggers automation rule to assign best agents' do expect(conversation.assignee).to be_nil - - automation_rule listener.conversation_updated(event) - conversation.reload expect(conversation.assignee).to eq(user_1) @@ -245,21 +237,14 @@ describe AutomationRuleListener do it 'triggers automation rule send email transcript to the mentioned email' do mailer = double - - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.conversation_updated(event) - conversation.reload allow(mailer).to receive(:conversation_transcript) end it 'triggers automation rule send email to the team' do - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) listener.conversation_updated(event) @@ -267,13 +252,8 @@ describe AutomationRuleListener do it 'triggers automation rule send message to the contacts' do expect(conversation.messages).to be_empty - - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.conversation_updated(event) - conversation.reload expect(conversation.messages.first.content).to eq('Send this message.') @@ -299,38 +279,26 @@ describe AutomationRuleListener do context 'when rule matches' do it 'triggers automation rule to assign team' do expect(conversation.team_id).not_to eq(team.id) - - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.message_created(event) - conversation.reload + expect(conversation.team_id).to eq(team.id) end it 'triggers automation rule to add label' do expect(conversation.labels).to eq([]) - - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.message_created(event) - conversation.reload + expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer') end it 'triggers automation rule to assign best agent' do expect(conversation.assignee).to be_nil - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.message_created(event) - conversation.reload expect(conversation.assignee).to eq(user_1) @@ -338,13 +306,8 @@ describe AutomationRuleListener do it 'triggers automation rule send email transcript to the mentioned email' do mailer = double - - automation_rule - expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation) - listener.message_created(event) - conversation.reload allow(mailer).to receive(:conversation_transcript) @@ -381,21 +344,18 @@ describe AutomationRuleListener do context 'when rule matches' do it 'triggers automation rule send email transcript to the mentioned email' do mailer = double - - automation_rule + allow(ConversationReplyMailer).to receive(:with).and_return(mailer) + allow(mailer).to receive(:conversation_transcript) listener.message_created(event) - conversation.reload - allow(mailer).to receive(:conversation_transcript) + expect(mailer).to have_received(:conversation_transcript).with(conversation, 'new_agent@example.com') end it 'triggers automation rule send message to the contacts' do expect(conversation.messages.count).to eq(1) - listener.message_created(event) - conversation.reload expect(conversation.messages.count).to eq(2) @@ -416,9 +376,7 @@ describe AutomationRuleListener do it 'triggers automation rule but wont send message' do expect(conversation.messages.count).to eq(1) - listener.message_created(event) - conversation.reload expect(conversation.messages.count).to eq(1) @@ -455,14 +413,14 @@ describe AutomationRuleListener do context 'when rule matches' do it 'triggers automation rule send email transcript to the mentioned email' do mailer = double - - automation_rule + allow(ConversationReplyMailer).to receive(:with).and_return(mailer) + allow(mailer).to receive(:conversation_transcript) listener.conversation_created(event) conversation.reload - allow(mailer).to receive(:conversation_transcript) + expect(mailer).to have_received(:conversation_transcript).with(conversation, 'new_agent@example.com') end it 'triggers automation rule send message to the contacts' do @@ -501,4 +459,48 @@ describe AutomationRuleListener do end end end + + describe '#message_created for tweet events' do + before do + automation_rule.update!( + event_name: 'message_created', + name: 'Call actions message created', + description: 'Send Message in the conversation', + conditions: [ + { attribute_key: 'status', filter_operator: 'equal_to', values: ['open'], query_operator: nil }.with_indifferent_access + ], + actions: [ + { 'action_name' => 'send_message', 'action_params' => ['Send this message.'] }, + { 'action_name' => 'send_attachment', 'action_params' => [123] }, + { 'action_name' => 'send_email_transcript', 'action_params' => ['new_agent@example.com'] } + ] + ) + end + + context 'when rule matches' do + let(:tweet) { create(:conversation, additional_attributes: { type: 'tweet' }, inbox: inbox, account: account) } + let(:event) { Events::Base.new('message_created', Time.zone.now, { conversation: tweet, message: message }) } + let!(:message) { create(:message, account: account, conversation: tweet, message_type: 'incoming') } + + it 'triggers automation rule except send_message and send_attachment' do + mailer = double + allow(ConversationReplyMailer).to receive(:with).and_return(mailer) + allow(mailer).to receive(:conversation_transcript) + + listener.message_created(event) + expect(mailer).to have_received(:conversation_transcript).with(tweet, 'new_agent@example.com') + end + + it 'does not triggers automation rule send message or send attachment' do + expect(tweet.messages.count).to eq(1) + + listener.message_created(event) + + tweet.reload + + expect(tweet.messages.count).to eq(1) + expect(tweet.messages.last.content).to eq(message.content) + end + end + end end From cb38ec32679605ed579d680a6b70ae41a5e70da2 Mon Sep 17 00:00:00 2001 From: Tejaswini Chile Date: Thu, 28 Apr 2022 01:14:03 +0530 Subject: [PATCH 04/11] chore: Allow Facebook channel to receive standby messages (#4511) --- app/models/channel/facebook_page.rb | 2 +- lib/integrations/facebook/message_parser.rb | 19 ++++++++++--------- .../slack/incoming_message_builder.rb | 6 +++++- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/app/models/channel/facebook_page.rb b/app/models/channel/facebook_page.rb index 6b36a3a54..ed599e6e2 100644 --- a/app/models/channel/facebook_page.rb +++ b/app/models/channel/facebook_page.rb @@ -54,7 +54,7 @@ class Channel::FacebookPage < ApplicationRecord response = Facebook::Messenger::Subscriptions.subscribe( access_token: page_access_token, subscribed_fields: %w[ - messages message_deliveries message_echoes message_reads + messages message_deliveries message_echoes message_reads standby messaging_handovers ] ) rescue => e diff --git a/lib/integrations/facebook/message_parser.rb b/lib/integrations/facebook/message_parser.rb index d2b943c00..ea70ca442 100644 --- a/lib/integrations/facebook/message_parser.rb +++ b/lib/integrations/facebook/message_parser.rb @@ -3,43 +3,44 @@ class Integrations::Facebook::MessageParser def initialize(response_json) @response = JSON.parse(response_json) + @messaging = @response['messaging'] || @response['standby'] end def sender_id - @response.dig 'messaging', 'sender', 'id' + @messaging.dig('sender', 'id') end def recipient_id - @response.dig 'messaging', 'recipient', 'id' + @messaging.dig('recipient', 'id') end def time_stamp - @response.dig 'messaging', 'timestamp' + @messaging['timestamp'] end def content - @response.dig 'messaging', 'message', 'text' + @messaging.dig('message', 'text') end def sequence - @response.dig 'messaging', 'message', 'seq' + @messaging.dig('message', 'seq') end def attachments - @response.dig 'messaging', 'message', 'attachments' + @messaging.dig('message', 'attachments') end def identifier - @response.dig 'messaging', 'message', 'mid' + @messaging.dig('message', 'mid') end def echo? - @response.dig 'messaging', 'message', 'is_echo' + @messaging.dig('message', 'is_echo') end # TODO : i don't think the payload contains app_id. if not remove def app_id - @response.dig 'messaging', 'message', 'app_id' + @messaging.dig('message', 'app_id') end # TODO : does this work ? diff --git a/lib/integrations/slack/incoming_message_builder.rb b/lib/integrations/slack/incoming_message_builder.rb index e655eef45..66d96be4a 100644 --- a/lib/integrations/slack/incoming_message_builder.rb +++ b/lib/integrations/slack/incoming_message_builder.rb @@ -34,7 +34,11 @@ class Integrations::Slack::IncomingMessageBuilder end def supported_message? - SUPPORTED_MESSAGE_TYPES.include?(message[:type]) if message.present? + if message.present? + SUPPORTED_MESSAGE_TYPES.include?(message[:type]) + else + params[:event][:files].any? + end end def hook_verification? From 8d04894744860c8979936227f9c7017dd7103062 Mon Sep 17 00:00:00 2001 From: "Aswin Dev P.S" Date: Thu, 28 Apr 2022 16:58:06 +0530 Subject: [PATCH 05/11] fix: Add index in conversation and reporting event (#4577) Fixes chatwoot/product#422 --- app/models/conversation.rb | 1 + app/models/reporting_event.rb | 11 ++++++----- ...5_add_index_to_conversation_and_reporting_event.rb | 6 ++++++ db/schema.rb | 4 +++- 4 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20220428101325_add_index_to_conversation_and_reporting_event.rb diff --git a/app/models/conversation.rb b/app/models/conversation.rb index cf3a4c256..ac02260a5 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -31,6 +31,7 @@ # index_conversations_on_assignee_id_and_account_id (assignee_id,account_id) # index_conversations_on_campaign_id (campaign_id) # index_conversations_on_contact_inbox_id (contact_inbox_id) +# index_conversations_on_last_activity_at (last_activity_at) # index_conversations_on_status_and_account_id (status,account_id) # index_conversations_on_team_id (team_id) # diff --git a/app/models/reporting_event.rb b/app/models/reporting_event.rb index 02f6e4d20..3568d2a06 100644 --- a/app/models/reporting_event.rb +++ b/app/models/reporting_event.rb @@ -17,11 +17,12 @@ # # Indexes # -# index_reporting_events_on_account_id (account_id) -# index_reporting_events_on_created_at (created_at) -# index_reporting_events_on_inbox_id (inbox_id) -# index_reporting_events_on_name (name) -# index_reporting_events_on_user_id (user_id) +# index_reporting_events_on_account_id (account_id) +# index_reporting_events_on_conversation_id (conversation_id) +# index_reporting_events_on_created_at (created_at) +# index_reporting_events_on_inbox_id (inbox_id) +# index_reporting_events_on_name (name) +# index_reporting_events_on_user_id (user_id) # class ReportingEvent < ApplicationRecord diff --git a/db/migrate/20220428101325_add_index_to_conversation_and_reporting_event.rb b/db/migrate/20220428101325_add_index_to_conversation_and_reporting_event.rb new file mode 100644 index 000000000..f1b982a8b --- /dev/null +++ b/db/migrate/20220428101325_add_index_to_conversation_and_reporting_event.rb @@ -0,0 +1,6 @@ +class AddIndexToConversationAndReportingEvent < ActiveRecord::Migration[6.1] + def change + add_index :conversations, :last_activity_at + add_index :reporting_events, :conversation_id + end +end diff --git a/db/schema.rb b/db/schema.rb index a30f6e6cf..cc619bc18 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_04_24_081117) do +ActiveRecord::Schema.define(version: 2022_04_28_101325) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" @@ -361,6 +361,7 @@ ActiveRecord::Schema.define(version: 2022_04_24_081117) do t.index ["assignee_id", "account_id"], name: "index_conversations_on_assignee_id_and_account_id" t.index ["campaign_id"], name: "index_conversations_on_campaign_id" t.index ["contact_inbox_id"], name: "index_conversations_on_contact_inbox_id" + t.index ["last_activity_at"], name: "index_conversations_on_last_activity_at" t.index ["status", "account_id"], name: "index_conversations_on_status_and_account_id" t.index ["team_id"], name: "index_conversations_on_team_id" end @@ -662,6 +663,7 @@ ActiveRecord::Schema.define(version: 2022_04_24_081117) do t.datetime "event_start_time" t.datetime "event_end_time" t.index ["account_id"], name: "index_reporting_events_on_account_id" + t.index ["conversation_id"], name: "index_reporting_events_on_conversation_id" t.index ["created_at"], name: "index_reporting_events_on_created_at" t.index ["inbox_id"], name: "index_reporting_events_on_inbox_id" t.index ["name"], name: "index_reporting_events_on_name" From 04194e7247715d53565de8e9c44b3e338c22eca8 Mon Sep 17 00:00:00 2001 From: Shivam Chahar Date: Thu, 28 Apr 2022 21:02:17 +0530 Subject: [PATCH 06/11] Fix: attachment name for incoming messages Use original_filename to get the name of the file attached to the message. Had to add the message_type method to the WhatsApp/incoming_message_service due to the Assignment Branch Condition linter error for the attach_files method. Fixes #4183 --- app/services/sms/incoming_message_service.rb | 2 +- app/services/telegram/incoming_message_service.rb | 2 +- app/services/whatsapp/incoming_message_service.rb | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/services/sms/incoming_message_service.rb b/app/services/sms/incoming_message_service.rb index eb0b5512b..a21f76b58 100644 --- a/app/services/sms/incoming_message_service.rb +++ b/app/services/sms/incoming_message_service.rb @@ -87,7 +87,7 @@ class Sms::IncomingMessageService file_type: file_type(attachment_file.content_type), file: { io: attachment_file, - filename: attachment_file, + filename: attachment_file.original_filename, content_type: attachment_file.content_type } ) diff --git a/app/services/telegram/incoming_message_service.rb b/app/services/telegram/incoming_message_service.rb index 1647623be..7ff7a6155 100644 --- a/app/services/telegram/incoming_message_service.rb +++ b/app/services/telegram/incoming_message_service.rb @@ -105,7 +105,7 @@ class Telegram::IncomingMessageService file_type: file_content_type, file: { io: attachment_file, - filename: attachment_file, + filename: attachment_file.original_filename, content_type: attachment_file.content_type } ) diff --git a/app/services/whatsapp/incoming_message_service.rb b/app/services/whatsapp/incoming_message_service.rb index 1a750b41a..c96e6e771 100644 --- a/app/services/whatsapp/incoming_message_service.rb +++ b/app/services/whatsapp/incoming_message_service.rb @@ -77,7 +77,6 @@ class Whatsapp::IncomingMessageService end def attach_files - message_type = params[:messages].first[:type] return if %w[text button interactive].include?(message_type) attachment_payload = params[:messages].first[message_type.to_sym] @@ -89,9 +88,13 @@ class Whatsapp::IncomingMessageService file_type: file_content_type(message_type), file: { io: attachment_file, - filename: attachment_file, + filename: attachment_file.original_filename, content_type: attachment_file.content_type } ) end + + def message_type + params[:messages].first[:type] + end end From e5136c2691da01ec22a5bda7e2b238d348a43eb7 Mon Sep 17 00:00:00 2001 From: Tejaswini Chile Date: Thu, 28 Apr 2022 21:09:39 +0530 Subject: [PATCH 07/11] Fix: File upload from slack (#4494) When you upload a file from slack chat it's not appearing in the chatwoot inbox. This is because Slack updated the webhook event format --- spec/support/slack_stubs.rb | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/spec/support/slack_stubs.rb b/spec/support/slack_stubs.rb index 7644b6872..e37676c92 100644 --- a/spec/support/slack_stubs.rb +++ b/spec/support/slack_stubs.rb @@ -22,17 +22,7 @@ module SlackStubs end def slack_attachment_stub - { - token: '[FILTERED]', - team_id: 'TLST3048H', - api_app_id: 'A012S5UETV4', - event: message_event, - type: 'event_callback', - event_id: 'Ev013QUX3WV6', - event_time: 1_588_623_033, - authed_users: '[FILTERED]', - webhook: {} - } + slack_message_stub.merge({ event: message_event_without_blocks }) end def slack_message_stub_without_thread_ts @@ -95,15 +85,26 @@ module SlackStubs elements: [ { type: 'rich_text_section', - elements: [ - { - type: 'text', - text: 'this is test' - } - ] + elements: [{ + type: 'text', + text: 'this is test' + }] } ] } ] end + + def message_event_without_blocks + { + client_msg_id: 'ffc6e64e-6f0c-4a3d-b594-faa6b44e48ab', + type: 'message', + text: 'this is test Hey <@U019KT237LP|Sojan> Test again', + user: 'ULYPAKE5S', + ts: '1588623033.006000', + files: file_stub, + thread_ts: '1588623023.005900', + channel: 'G01354F6A6Q' + } + end end From b5e0921d0d9e5831aa477a015bb03fa06c84a994 Mon Sep 17 00:00:00 2001 From: Shivam Chahar Date: Fri, 29 Apr 2022 00:43:10 +0530 Subject: [PATCH 08/11] fix: sidekiq cron deprecation warnings (#4581) Updates sidekiq-cron to fix the deprecation warnings Fixes #4090 --- Gemfile | 2 +- Gemfile.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index e94303f45..9bc330d93 100644 --- a/Gemfile +++ b/Gemfile @@ -104,7 +104,7 @@ gem 'sentry-sidekiq' ##-- background job processing --## gem 'sidekiq', '~> 6.4.0' # We want cron jobs -gem 'sidekiq-cron' +gem 'sidekiq-cron', '~> 1.3' ##-- Push notification service --## gem 'fcm' diff --git a/Gemfile.lock b/Gemfile.lock index 9edce0f36..ba8f04ec9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -183,7 +183,7 @@ GEM email_reply_trimmer (0.1.13) erubi (1.10.0) erubis (2.7.0) - et-orbi (1.2.6) + et-orbi (1.2.7) tzinfo execjs (2.8.1) facebook-messenger (2.0.1) @@ -210,8 +210,8 @@ GEM ruby_parser (~> 3.0) sexp_processor (~> 4.0) foreman (0.87.2) - fugit (1.5.2) - et-orbi (~> 1.1, >= 1.1.8) + fugit (1.5.3) + et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) gapic-common (0.3.4) google-protobuf (~> 3.12, >= 3.12.2) @@ -551,8 +551,8 @@ GEM connection_pool (>= 2.2.2) rack (~> 2.0) redis (>= 4.2.0) - sidekiq-cron (1.2.0) - fugit (~> 1.1) + sidekiq-cron (1.4.0) + fugit (~> 1) sidekiq (>= 4.2.1) signet (0.16.0) addressable (~> 2.8) @@ -731,7 +731,7 @@ DEPENDENCIES sentry-sidekiq shoulda-matchers sidekiq (~> 6.4.0) - sidekiq-cron + sidekiq-cron (~> 1.3) simplecov (= 0.17.1) slack-ruby-client spring From 45099f40f1575c8730e9795a54ea35ca69b395a1 Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Fri, 29 Apr 2022 14:38:10 +0530 Subject: [PATCH 09/11] fix: ce spec action for PRs from forks (#4587) CE spec action was failing for PRs from external forks at the checkout stage. This PR modifies the checkout action to use the full repo name and branch. #4586 --- .github/workflows/run_foss_spec.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run_foss_spec.yml b/.github/workflows/run_foss_spec.yml index 3a6ff5f7b..395e063e7 100644 --- a/.github/workflows/run_foss_spec.yml +++ b/.github/workflows/run_foss_spec.yml @@ -42,7 +42,8 @@ jobs: steps: - uses: actions/checkout@v3 with: - ref: ${{ github.head_ref }} + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} - uses: ruby/setup-ruby@v1 with: From c1cc94e37c5da6d553df51f59ab0068e7b53bbc5 Mon Sep 17 00:00:00 2001 From: Shivam Chahar Date: Fri, 29 Apr 2022 20:54:12 +0530 Subject: [PATCH 10/11] Fix: Accept phone number in public contact api (#4580) This PR makes it possible to pass a phone number to the public contacts API. Fixes #4023 --- .../public/api/v1/inboxes/contacts_controller.rb | 2 +- app/views/public/api/v1/models/_contact.json.jbuilder | 1 + .../public/api/v1/inbox/contacts_controller_spec.rb | 8 +++++--- .../request/public/contact/create_update_payload.yml | 5 ++++- swagger/swagger.json | 4 ++++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/controllers/public/api/v1/inboxes/contacts_controller.rb b/app/controllers/public/api/v1/inboxes/contacts_controller.rb index 6932386fd..eb794f2a0 100644 --- a/app/controllers/public/api/v1/inboxes/contacts_controller.rb +++ b/app/controllers/public/api/v1/inboxes/contacts_controller.rb @@ -43,6 +43,6 @@ class Public::Api::V1::Inboxes::ContactsController < Public::Api::V1::InboxesCon end def permitted_params - params.permit(:identifier, :identifier_hash, :email, :name, :avatar_url, custom_attributes: {}) + params.permit(:identifier, :identifier_hash, :email, :name, :avatar_url, :phone_number, custom_attributes: {}) end end diff --git a/app/views/public/api/v1/models/_contact.json.jbuilder b/app/views/public/api/v1/models/_contact.json.jbuilder index c35705c6c..fc9dbb2f2 100644 --- a/app/views/public/api/v1/models/_contact.json.jbuilder +++ b/app/views/public/api/v1/models/_contact.json.jbuilder @@ -1,3 +1,4 @@ json.id resource.id json.name resource.name json.email resource.email +json.phone_number resource.phone_number diff --git a/spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb b/spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb index 151a2eec5..5e412a65d 100644 --- a/spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb +++ b/spec/controllers/public/api/v1/inbox/contacts_controller_spec.rb @@ -10,7 +10,8 @@ RSpec.describe 'Public Inbox Contacts API', type: :request do post "/public/api/v1/inboxes/#{api_channel.identifier}/contacts" expect(response).to have_http_status(:success) - data = JSON.parse(response.body) + data = response.parsed_body + expect(data.keys).to include('email', 'id', 'name', 'phone_number', 'pubsub_token', 'source_id') expect(data['source_id']).not_to eq nil expect(data['pubsub_token']).not_to eq nil end @@ -21,7 +22,8 @@ RSpec.describe 'Public Inbox Contacts API', type: :request do get "/public/api/v1/inboxes/#{api_channel.identifier}/contacts/#{contact_inbox.source_id}" expect(response).to have_http_status(:success) - data = JSON.parse(response.body) + data = response.parsed_body + expect(data.keys).to include('email', 'id', 'name', 'phone_number', 'pubsub_token', 'source_id') expect(data['source_id']).to eq contact_inbox.source_id expect(data['pubsub_token']).to eq contact_inbox.pubsub_token end @@ -33,7 +35,7 @@ RSpec.describe 'Public Inbox Contacts API', type: :request do params: { name: 'John Smith' } expect(response).to have_http_status(:success) - data = JSON.parse(response.body) + data = response.parsed_body expect(data['name']).to eq 'John Smith' end end diff --git a/swagger/definitions/request/public/contact/create_update_payload.yml b/swagger/definitions/request/public/contact/create_update_payload.yml index 9f1f820de..48c6e4550 100644 --- a/swagger/definitions/request/public/contact/create_update_payload.yml +++ b/swagger/definitions/request/public/contact/create_update_payload.yml @@ -10,9 +10,12 @@ properties: email: type: string description: Email of the contact - name: + name: type: string description: Name of the contact + phone_number: + type: string + description: Phone number of the contact avatar_url: type: string description: The url to a jpeg, png file for the user avatar diff --git a/swagger/swagger.json b/swagger/swagger.json index 81f19149c..ec1bf8a25 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -5268,6 +5268,10 @@ "type": "string", "description": "Name of the contact" }, + "phone_number": { + "type": "string", + "description": "Phone number of the contact" + }, "avatar_url": { "type": "string", "description": "The url to a jpeg, png file for the user avatar" From b3c8c8383099cc3bd42589e7feda778b25cb005c Mon Sep 17 00:00:00 2001 From: giquieu Date: Mon, 2 May 2022 04:44:04 -0300 Subject: [PATCH 11/11] fix: unable to send audio messages on Telegram (#4493) - Changed the lib used to record the audio (videojs-record). - Changed the audio recording format to .ogg, this will keep compatibility with sending to channels, Telegram, Whatsapp, Web Widget and API. - Changed the visualization of recording waves, it is now using bars, the same format used by applications (Whatsapp and Telegram) Fixes: #4115 --- .../assets/scss/widgets/_reply-box.scss | 10 + .../widgets/WootWriter/AudioRecorder.vue | 295 +++++++++--------- .../widgets/conversation/ReplyBox.vue | 32 +- .../FluentIcon/dashboard-icons.json | 6 +- app/models/channel/telegram.rb | 2 + config/webpack/environment.js | 9 + package.json | 5 +- 7 files changed, 184 insertions(+), 175 deletions(-) diff --git a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss index 8a53545fe..1d2c3f63d 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss @@ -27,6 +27,16 @@ padding: 0 $space-small; } + .video-js { + background: transparent; + // Override min-height : 50px in foundation + // + max-height: $space-mega * 2.4; + min-height: 4.8rem; + padding: var(--space-normal) 0 0; + resize: none; + } + >textarea { @include ghost-input(); @include margin(0); diff --git a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue index 4d6df7793..8796065ac 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue +++ b/app/javascript/dashboard/components/widgets/WootWriter/AudioRecorder.vue @@ -1,16 +1,29 @@