feat: Ability to toggle conversation continuity via email (#3817)

Fixes: #3368
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Sojan Jose 2022-01-26 15:59:48 -08:00 committed by GitHub
parent 34e8ad9dc5
commit 59deffc7e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 113 additions and 50 deletions

View file

@ -310,6 +310,10 @@
"ENABLED": "Enabled",
"DISABLED": "Disabled"
},
"ENABLE_CONTINUITY_VIA_EMAIL": {
"ENABLED": "Enabled",
"DISABLED": "Disabled"
},
"ENABLE_HMAC": {
"LABEL": "Enable"
}
@ -356,6 +360,8 @@
"AUTO_ASSIGNMENT": "Enable auto assignment",
"ENABLE_CSAT": "Enable CSAT",
"ENABLE_CSAT_SUB_TEXT": "Enable/Disable CSAT(Customer satisfaction) survey after resolving a conversation",
"ENABLE_CONTINUITY_VIA_EMAIL": "Enable conversation continuity via email",
"ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT": "Conversations will continue over email if the contact email address is available.",
"INBOX_UPDATE_TITLE": "Inbox Settings",
"INBOX_UPDATE_SUB_TEXT": "Update your inbox settings",
"AUTO_ASSIGNMENT_SUB_TEXT": "Enable or disable the automatic assignment of new conversations to the agents added to this inbox.",

View file

@ -215,7 +215,7 @@
</p>
</label>
<label class="medium-9 columns">
<label v-if="isAWebWidgetInbox" class="medium-9 columns">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ALLOW_MESSAGES_AFTER_RESOLVED') }}
<select v-model="allowMessagesAfterResolved">
<option :value="true">
@ -234,6 +234,25 @@
</p>
</label>
<label v-if="isAWebWidgetInbox" class="medium-9 columns">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ENABLE_CONTINUITY_VIA_EMAIL') }}
<select v-model="continuityViaEmail">
<option :value="true">
{{ $t('INBOX_MGMT.EDIT.ENABLE_CONTINUITY_VIA_EMAIL.ENABLED') }}
</option>
<option :value="false">
{{ $t('INBOX_MGMT.EDIT.ENABLE_CONTINUITY_VIA_EMAIL.DISABLED') }}
</option>
</select>
<p class="help-text">
{{
$t(
'INBOX_MGMT.SETTINGS_POPUP.ENABLE_CONTINUITY_VIA_EMAIL_SUB_TEXT'
)
}}
</p>
</label>
<label v-if="isAWebWidgetInbox">
{{ $t('INBOX_MGMT.FEATURES.LABEL') }}
</label>
@ -440,6 +459,7 @@ export default {
isAgentListUpdating: false,
csatSurveyEnabled: false,
allowMessagesAfterResolved: true,
continuityViaEmail: true,
selectedInboxName: '',
channelWebsiteUrl: '',
webhookUrl: '',
@ -604,6 +624,7 @@ export default {
this.emailCollectEnabled = this.inbox.enable_email_collect;
this.csatSurveyEnabled = this.inbox.csat_survey_enabled;
this.allowMessagesAfterResolved = this.inbox.allow_messages_after_resolved;
this.continuityViaEmail = this.inbox.continuity_via_email;
this.channelWebsiteUrl = this.inbox.website_url;
this.channelWelcomeTitle = this.inbox.welcome_title;
this.channelWelcomeTagline = this.inbox.welcome_tagline;
@ -659,6 +680,7 @@ export default {
reply_time: this.replyTime || 'in_a_few_minutes',
hmac_mandatory: this.hmacMandatory,
tweets_enabled: this.tweetsEnabled,
continuity_via_email: this.continuityViaEmail,
},
};
if (this.avatarFile) {

View file

@ -3,6 +3,7 @@
# Table name: channel_web_widgets
#
# id :integer not null, primary key
# continuity_via_email :boolean default(TRUE), not null
# feature_flags :integer default(3), not null
# hmac_mandatory :boolean default(FALSE)
# hmac_token :string
@ -29,7 +30,8 @@ class Channel::WebWidget < ApplicationRecord
include FlagShihTzu
self.table_name = 'channel_web_widgets'
EDITABLE_ATTRS = [:website_url, :widget_color, :welcome_title, :welcome_tagline, :reply_time, :pre_chat_form_enabled, :hmac_mandatory,
EDITABLE_ATTRS = [:website_url, :widget_color, :welcome_title, :welcome_tagline, :reply_time, :pre_chat_form_enabled,
:continuity_via_email, :hmac_mandatory,
{ pre_chat_form_options: [:pre_chat_message, :require_email] },
{ selected_feature_flags: [] }].freeze

View file

@ -185,6 +185,14 @@ class Message < ApplicationRecord
::MessageTemplates::HookExecutionService.new(message: self).perform
end
def email_notifiable_webwidget?
inbox.web_widget? && inbox.channel.continuity_via_email
end
def email_notifiable_channel?
email_notifiable_webwidget? || %w[Email].include?(inbox.inbox_type)
end
def email_notifiable_message?
return false unless outgoing? || input_csat?
return false if private?
@ -194,7 +202,8 @@ class Message < ApplicationRecord
def can_notify_via_mail?
return unless email_notifiable_message?
return false if conversation.contact.email.blank? || !(%w[Website Email].include? inbox.inbox_type)
return unless email_notifiable_channel?
return if conversation.contact.email.blank?
true
end

View file

@ -34,36 +34,43 @@ if resource.web_widget?
json.hmac_token resource.channel.try(:hmac_token)
json.pre_chat_form_enabled resource.channel.try(:pre_chat_form_enabled)
json.pre_chat_form_options resource.channel.try(:pre_chat_form_options)
json.continuity_via_email resource.channel.try(:continuity_via_email)
end
## Facebook Attributes
json.page_id resource.channel.try(:page_id)
json.reauthorization_required resource.channel.try(:reauthorization_required?) if resource.facebook?
if resource.facebook?
json.page_id resource.channel.try(:page_id)
json.reauthorization_required resource.channel.try(:reauthorization_required?)
end
## Twilio Attributes
json.phone_number resource.channel.try(:phone_number)
json.medium resource.channel.try(:medium) if resource.twilio?
## Email Channel Attributes
json.forward_to_email resource.channel.try(:forward_to_email)
json.email resource.channel.try(:email) if resource.email?
if resource.email?
## Email Channel Attributes
json.forward_to_email resource.channel.try(:forward_to_email)
json.email resource.channel.try(:email)
## IMAP
json.imap_email resource.channel.try(:imap_email) if resource.email?
json.imap_password resource.channel.try(:imap_password) if resource.email?
json.imap_address resource.channel.try(:imap_address) if resource.email?
json.imap_port resource.channel.try(:imap_port) if resource.email?
json.imap_enabled resource.channel.try(:imap_enabled) if resource.email?
json.imap_enable_ssl resource.channel.try(:imap_enable_ssl) if resource.email?
## IMAP
json.imap_email resource.channel.try(:imap_email)
json.imap_password resource.channel.try(:imap_password)
json.imap_address resource.channel.try(:imap_address)
json.imap_port resource.channel.try(:imap_port)
json.imap_enabled resource.channel.try(:imap_enabled)
json.imap_enable_ssl resource.channel.try(:imap_enable_ssl)
## SMTP
json.smtp_email resource.channel.try(:smtp_email) if resource.email?
json.smtp_password resource.channel.try(:smtp_password) if resource.email?
json.smtp_address resource.channel.try(:smtp_address) if resource.email?
json.smtp_port resource.channel.try(:smtp_port) if resource.email?
json.smtp_enabled resource.channel.try(:smtp_enabled) if resource.email?
json.smtp_domain resource.channel.try(:smtp_domain) if resource.email?
## SMTP
json.smtp_email resource.channel.try(:smtp_email)
json.smtp_password resource.channel.try(:smtp_password)
json.smtp_address resource.channel.try(:smtp_address)
json.smtp_port resource.channel.try(:smtp_port)
json.smtp_enabled resource.channel.try(:smtp_enabled)
json.smtp_domain resource.channel.try(:smtp_domain)
end
## API Channel Attributes
json.webhook_url resource.channel.try(:webhook_url) if resource.api?
json.inbox_identifier resource.channel.try(:identifier) if resource.api?
if resource.api?
json.webhook_url resource.channel.try(:webhook_url)
json.inbox_identifier resource.channel.try(:identifier)
end

View file

@ -305,11 +305,11 @@ Rails.application.routes.draw do
resources :users, only: [:index, :new, :create, :show, :edit, :update]
resources :access_tokens, only: [:index, :show]
resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update]
resources :agent_bots, only: [:index, :new, :create, :show, :edit, :update]
resources :platform_apps, only: [:index, :new, :create, :show, :edit, :update]
# resources that doesn't appear in primary navigation in super admin
resources :account_users, only: [:new, :create, :destroy]
resources :agent_bots, only: [:index, :new, :create, :show, :edit, :update]
resources :platform_apps, only: [:index, :new, :create, :show, :edit, :update]
end
authenticated :super_admin do
mount Sidekiq::Web => '/monitoring/sidekiq'

View file

@ -0,0 +1,5 @@
class EnableConversationContinuity < ActiveRecord::Migration[6.1]
def change
add_column :channel_web_widgets, :continuity_via_email, :boolean, null: false, default: true
end
end

View file

@ -274,6 +274,7 @@ ActiveRecord::Schema.define(version: 2022_01_21_055444) do
t.boolean "pre_chat_form_enabled", default: false
t.jsonb "pre_chat_form_options", default: {}
t.boolean "hmac_mandatory", default: false
t.boolean "continuity_via_email", default: true, null: false
t.index ["hmac_token"], name: "index_channel_web_widgets_on_hmac_token", unique: true
t.index ["website_token"], name: "index_channel_web_widgets_on_website_token", unique: true
end

View file

@ -56,13 +56,23 @@ RSpec.describe Message, type: :model do
expect(hook_execution_service).to have_received(:perform)
end
it 'calls notify email method on after save for outgoing messages' do
context 'with conversation continuity' do
it 'calls notify email method on after save for outgoing messages in website channel' do
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
message.message_type = 'outgoing'
message.save!
expect(ConversationReplyEmailWorker).to have_received(:perform_in)
end
it 'does not call notify email for website channel if continuity is disabled' do
message.inbox = create(:inbox, account: message.account,
channel: build(:channel_widget, account: message.account, continuity_via_email: false))
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
message.message_type = 'outgoing'
message.save!
expect(ConversationReplyEmailWorker).not_to have_received(:perform_in)
end
it 'wont call notify email method for private notes' do
message.private = true
allow(ConversationReplyEmailWorker).to receive(:perform_in).and_return(true)
@ -85,6 +95,7 @@ RSpec.describe Message, type: :model do
expect(ConversationReplyEmailWorker).not_to have_received(:perform_in)
end
end
end
context 'when content_type is blank' do
let(:message) { build(:message, content_type: nil, account: create(:account)) }