Feature: Inbox greeting message (#927)

Co-authored-by: Pranav Raj S <pranav@thoughtwoot.com>
This commit is contained in:
Sojan Jose 2020-06-09 23:54:35 +05:30 committed by GitHub
parent 8b022311c0
commit 432dad203b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 262 additions and 120 deletions

View file

@ -10,7 +10,12 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
def create def create
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
channel = web_widgets.create!(permitted_params[:channel].except(:type)) if permitted_params[:channel][:type] == 'web_widget' channel = web_widgets.create!(permitted_params[:channel].except(:type)) if permitted_params[:channel][:type] == 'web_widget'
@inbox = Current.account.inboxes.build(name: permitted_params[:name], channel: channel) @inbox = Current.account.inboxes.build(
name: permitted_params[:name],
greeting_message: permitted_params[:greeting_message],
greeting_enabled: permitted_params[:greeting_enabled],
channel: channel
)
@inbox.avatar.attach(permitted_params[:avatar]) @inbox.avatar.attach(permitted_params[:avatar])
@inbox.save! @inbox.save!
end end
@ -56,11 +61,12 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
end end
def permitted_params def permitted_params
params.permit(:id, :avatar, :name, channel: [:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :agent_away_message]) params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, channel:
[:type, :website_url, :widget_color, :welcome_title, :welcome_tagline])
end end
def inbox_update_params def inbox_update_params
params.permit(:enable_auto_assignment, :name, :avatar, channel: [:website_url, :widget_color, :welcome_title, params.permit(:enable_auto_assignment, :name, :avatar, :greeting_message, :greeting_enabled,
:welcome_tagline, :agent_away_message]) channel: [:website_url, :widget_color, :welcome_title, :welcome_tagline])
end end
end end

View file

@ -54,7 +54,7 @@
"LABEL": "Καλώς ήλθατε (Tagline)", "LABEL": "Καλώς ήλθατε (Tagline)",
"PLACEHOLDER": "Είναι απλό να συνδεθείτε μαζί μας. Ζητήστε μας οτιδήποτε, ή μοιραστείτε την εμπειρία σας." "PLACEHOLDER": "Είναι απλό να συνδεθείτε μαζί μας. Ζητήστε μας οτιδήποτε, ή μοιραστείτε την εμπειρία σας."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Μήνυμα όταν δεν υπάρχουν πράκτορες", "LABEL": "Μήνυμα όταν δεν υπάρχουν πράκτορες",
"PLACEHOLDER": "Τυπικά απαντάμε σε μερικές ώρες." "PLACEHOLDER": "Τυπικά απαντάμε σε μερικές ώρες."
}, },

View file

@ -63,10 +63,16 @@
"LABEL": "Welcome Tagline", "LABEL": "Welcome Tagline",
"PLACEHOLDER": "We make it simple to connect with us. Ask us anything, or share your feedback." "PLACEHOLDER": "We make it simple to connect with us. Ask us anything, or share your feedback."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Agents Away Message", "LABEL": "Channel greeting message",
"PLACEHOLDER": "Acme Inc typically replies in a few hours." "PLACEHOLDER": "Acme Inc typically replies in a few hours."
}, },
"CHANNEL_GREETING_TOGGLE": {
"LABEL": "Enable channel greeting",
"HELP_TEXT": "Send a greeting message to the user when he starts the conversation.",
"ENABLED": "Enabled",
"DISABLED": "Disabled"
},
"WIDGET_COLOR": { "WIDGET_COLOR": {
"LABEL": "Widget Color", "LABEL": "Widget Color",
"PLACEHOLDER": "Update the widget color used in widget" "PLACEHOLDER": "Update the widget color used in widget"

View file

@ -63,7 +63,7 @@
"LABEL": "Bienvenido Tagline", "LABEL": "Bienvenido Tagline",
"PLACEHOLDER": "Facilitamos la conexión con nosotros. Pídanos cualquier cosa o comparte tus comentarios." "PLACEHOLDER": "Facilitamos la conexión con nosotros. Pídanos cualquier cosa o comparte tus comentarios."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Mensaje de Agentes Ausentes", "LABEL": "Mensaje de Agentes Ausentes",
"PLACEHOLDER": "Acme Inc normalmente responde en unas pocas horas." "PLACEHOLDER": "Acme Inc normalmente responde en unas pocas horas."
}, },

View file

@ -54,7 +54,7 @@
"LABEL": "Slogan d'accueil", "LABEL": "Slogan d'accueil",
"PLACEHOLDER": "C'est simple de rentrer en contact avec nous. Demandez-nous quoi que ce soit ou partagez vos commentaires." "PLACEHOLDER": "C'est simple de rentrer en contact avec nous. Demandez-nous quoi que ce soit ou partagez vos commentaires."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Message lorsque les agents sont absents", "LABEL": "Message lorsque les agents sont absents",
"PLACEHOLDER": "Acme Inc répond en général en quelques heures." "PLACEHOLDER": "Acme Inc répond en général en quelques heures."
}, },

View file

@ -54,9 +54,15 @@
"LABEL": "Welkom Tagline", "LABEL": "Welkom Tagline",
"PLACEHOLDER": "We maken het eenvoudig om met ons te verbinden. Vraag ons iets of deel uw feedback." "PLACEHOLDER": "We maken het eenvoudig om met ons te verbinden. Vraag ons iets of deel uw feedback."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Agents Afwezig Bericht", "LABEL": "Kanaalbegroeting",
"PLACEHOLDER": "Acme Inc reageert meestal binnen een paar uur." "PLACEHOLDER": "Acme Inc antwoordt meestal binnen een paar uur."
},
"CHANNEL_GREETING_TOGGLE": {
"LABEL": "Kanaalbegroeting inschakelen",
"HELP_TEXT": "Stuur een begroetingsbericht naar de gebruiker wanneer hij het gesprek start.",
"ENABLED": "Ingeschakeld",
"DISABLED": "Gehandicapt"
}, },
"WIDGET_COLOR": { "WIDGET_COLOR": {
"LABEL": "Kleur van widget", "LABEL": "Kleur van widget",

View file

@ -54,7 +54,7 @@
"LABEL": "Bem-vindo Slogan", "LABEL": "Bem-vindo Slogan",
"PLACEHOLDER": "Nós simplificamos nos conectar com a gente. Pergunte a nós qualquer coisa ou compartilhe seus comentários." "PLACEHOLDER": "Nós simplificamos nos conectar com a gente. Pergunte a nós qualquer coisa ou compartilhe seus comentários."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Mensagem Ausente dos Agentes", "LABEL": "Mensagem Ausente dos Agentes",
"PLACEHOLDER": "Acme Inc normalmente responde em algumas horas." "PLACEHOLDER": "Acme Inc normalmente responde em algumas horas."
}, },

View file

@ -54,7 +54,7 @@
"LABEL": "Bem-vindo, saudação", "LABEL": "Bem-vindo, saudação",
"PLACEHOLDER": "Nós tornamos simples a conexão conosco. Pergunte qualquer assunto ou compartilhe seus comentários." "PLACEHOLDER": "Nós tornamos simples a conexão conosco. Pergunte qualquer assunto ou compartilhe seus comentários."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Mensagem de agente ausente", "LABEL": "Mensagem de agente ausente",
"PLACEHOLDER": "Acme Inc tipicamente retorna em algumas horas." "PLACEHOLDER": "Acme Inc tipicamente retorna em algumas horas."
}, },

View file

@ -54,7 +54,7 @@
"LABEL": "Tagline de Bun Venit", "LABEL": "Tagline de Bun Venit",
"PLACEHOLDER": "Noi facem conectarea cu noi simplă. Întreabă-ne orice, sau partajează-ți feedback-ul." "PLACEHOLDER": "Noi facem conectarea cu noi simplă. Întreabă-ne orice, sau partajează-ți feedback-ul."
}, },
"CHANNEL_AGENT_AWAY_MESSAGE": { "CHANNEL_GREETING_MESSAGE": {
"LABEL": "Mesaj Agent Indisponibil", "LABEL": "Mesaj Agent Indisponibil",
"PLACEHOLDER": "De obicei, Acme Inc răspunde în câteva ore." "PLACEHOLDER": "De obicei, Acme Inc răspunde în câteva ore."
}, },

View file

@ -18,7 +18,7 @@
<woot-input <woot-input
v-if="isAWidgetInbox" v-if="isAWidgetInbox"
v-model.trim="selectedInboxName" v-model.trim="selectedInboxName"
class="medium-12 columns" class="medium-9 columns"
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')" :label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')"
:placeholder=" :placeholder="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER') $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
@ -27,7 +27,7 @@
<woot-input <woot-input
v-if="isAWidgetInbox" v-if="isAWidgetInbox"
v-model.trim="channelWebsiteUrl" v-model.trim="channelWebsiteUrl"
class="medium-12 columns" class="medium-9 columns"
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')" :label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
:placeholder=" :placeholder="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER') $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.PLACEHOLDER')
@ -36,7 +36,7 @@
<woot-input <woot-input
v-if="isAWidgetInbox" v-if="isAWidgetInbox"
v-model.trim="channelWelcomeTitle" v-model.trim="channelWelcomeTitle"
class="medium-12 columns" class="medium-9 columns"
:label=" :label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL') $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TITLE.LABEL')
" "
@ -46,46 +46,61 @@
) )
" "
/> />
<woot-input
v-if="isAWidgetInbox"
v-model.trim="channelWelcomeTagline"
class="medium-12 columns"
:label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.LABEL')
"
:placeholder="
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_WELCOME_TAGLINE.PLACEHOLDER'
)
"
/>
<woot-input <label v-if="isAWidgetInbox" class="medium-9 columns">
v-if="isAWidgetInbox"
v-model.trim="channelAgentAwayMessage"
class="medium-12 columns"
:label="
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL'
)
"
:placeholder="
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER'
)
"
/>
<label v-if="isAWidgetInbox" class="medium-12 columns">
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }} {{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
<woot-color-picker v-model="inbox.widget_color" /> <woot-color-picker v-model="inbox.widget_color" />
</label> </label>
<label class="medium-12 columns">
<label class="medium-9 columns">
{{
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.LABEL')
}}
<select v-model="greetingEnabled">
<option :value="true">
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.ENABLED'
)
}}
</option>
<option :value="false">
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.DISABLED'
)
}}
</option>
</select>
<p class="help-text">
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.HELP_TEXT'
)
}}
</p>
</label>
<woot-input
v-if="greetingEnabled"
v-model.trim="greetingMessage"
class="medium-9 columns"
:label="
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_MESSAGE.LABEL')
"
:placeholder="
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_MESSAGE.PLACEHOLDER'
)
"
/>
<label class="medium-9 columns">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }} {{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
<select v-model="autoAssignment"> <select v-model="autoAssignment">
<option value="true"> <option :value="true">
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED') }} {{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED') }}
</option> </option>
<option value="false"> <option :value="false">
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED') }} {{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED') }}
</option> </option>
</select> </select>
@ -183,13 +198,14 @@ export default {
avatarFile: null, avatarFile: null,
avatarUrl: '', avatarUrl: '',
selectedAgents: [], selectedAgents: [],
greetingEnabled: true,
greetingMessage: '',
autoAssignment: false, autoAssignment: false,
isAgentListUpdating: false, isAgentListUpdating: false,
selectedInboxName: '', selectedInboxName: '',
channelWebsiteUrl: '', channelWebsiteUrl: '',
channelWelcomeTitle: '', channelWelcomeTitle: '',
channelWelcomeTagline: '', channelWelcomeTagline: '',
channelAgentAwayMessage: '',
autoAssignmentOptions: [ autoAssignmentOptions: [
{ {
value: true, value: true,
@ -247,11 +263,12 @@ export default {
this.fetchAttachedAgents(); this.fetchAttachedAgents();
this.avatarUrl = this.inbox.avatar_url; this.avatarUrl = this.inbox.avatar_url;
this.selectedInboxName = this.inbox.name; this.selectedInboxName = this.inbox.name;
this.greetingEnabled = this.inbox.greeting_enabled;
this.greetingMessage = this.inbox.greeting_message;
this.autoAssignment = this.inbox.enable_auto_assignment; this.autoAssignment = this.inbox.enable_auto_assignment;
this.channelWebsiteUrl = this.inbox.website_url; this.channelWebsiteUrl = this.inbox.website_url;
this.channelWelcomeTitle = this.inbox.welcome_title; this.channelWelcomeTitle = this.inbox.welcome_title;
this.channelWelcomeTagline = this.inbox.welcome_tagline; this.channelWelcomeTagline = this.inbox.welcome_tagline;
this.channelAgentAwayMessage = this.inbox.agent_away_message;
}); });
}, },
async fetchAttachedAgents() { async fetchAttachedAgents() {
@ -294,12 +311,13 @@ export default {
id: this.currentInboxId, id: this.currentInboxId,
name: this.selectedInboxName, name: this.selectedInboxName,
enable_auto_assignment: this.autoAssignment, enable_auto_assignment: this.autoAssignment,
greeting_enabled: this.greetingEnabled,
greeting_message: this.greetingMessage,
channel: { channel: {
widget_color: this.inbox.widget_color, widget_color: this.inbox.widget_color,
website_url: this.channelWebsiteUrl, website_url: this.channelWebsiteUrl,
welcome_title: this.channelWelcomeTitle, welcome_title: this.channelWelcomeTitle,
welcome_tagline: this.channelWelcomeTagline, welcome_tagline: this.channelWelcomeTagline,
agent_away_message: this.channelAgentAwayMessage,
}, },
}; };
if (this.avatarFile) { if (this.avatarFile) {

View file

@ -6,9 +6,8 @@
/> />
<woot-loading-state <woot-loading-state
v-if="uiFlags.isCreating" v-if="uiFlags.isCreating"
:message="$('INBOX_MGMT.ADD.WEBSITE_CHANNEL.LOADING_MESSAGE')" :message="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.LOADING_MESSAGE')"
> />
</woot-loading-state>
<form <form
v-if="!uiFlags.isCreating" v-if="!uiFlags.isCreating"
class="row" class="row"
@ -76,19 +75,43 @@
/> />
</label> </label>
</div> </div>
<div class="medium-12 columns"> <label class="medium-12 columns">
<label> {{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.LABEL') }}
<select v-model="greetingEnabled">
<option :value="true">
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.ENABLED'
)
}}
</option>
<option :value="false">
{{
$t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.DISABLED'
)
}}
</option>
</select>
<p class="help-text">
{{ {{
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.LABEL' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_TOGGLE.HELP_TEXT'
) )
}} }}
</p>
</label>
<div v-if="greetingEnabled" class="medium-12 columns">
<label>
{{
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_MESSAGE.LABEL')
}}
<input <input
v-model.trim="channelAgentAwayMessage" v-model.trim="greetingMessage"
type="text" type="text"
:placeholder=" :placeholder="
$t( $t(
'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_AGENT_AWAY_MESSAGE.PLACEHOLDER' 'INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_GREETING_MESSAGE.PLACEHOLDER'
) )
" "
/> />
@ -124,7 +147,8 @@ export default {
channelWidgetColor: '#009CE0', channelWidgetColor: '#009CE0',
channelWelcomeTitle: '', channelWelcomeTitle: '',
channelWelcomeTagline: '', channelWelcomeTagline: '',
channelAgentAwayMessage: '', greetingEnabled: false,
greetingMessage: '',
}; };
}, },
computed: { computed: {
@ -138,13 +162,14 @@ export default {
'inboxes/createWebsiteChannel', 'inboxes/createWebsiteChannel',
{ {
name: this.inboxName, name: this.inboxName,
greeting_enabled: this.greetingEnabled,
greeting_message: this.greetingMessage,
channel: { channel: {
type: 'web_widget', type: 'web_widget',
website_url: this.channelWebsiteUrl, website_url: this.channelWebsiteUrl,
widget_color: this.channelWidgetColor, widget_color: this.channelWidgetColor,
welcome_title: this.channelWelcomeTitle, welcome_title: this.channelWelcomeTitle,
welcome_tagline: this.channelWelcomeTagline, welcome_tagline: this.channelWelcomeTagline,
agent_away_message: this.channelAgentAwayMessage,
}, },
} }
); );

View file

@ -7,6 +7,8 @@
# id :integer not null, primary key # id :integer not null, primary key
# channel_type :string # channel_type :string
# enable_auto_assignment :boolean default(TRUE) # enable_auto_assignment :boolean default(TRUE)
# greeting_enabled :boolean default(FALSE)
# greeting_message :string
# name :string not null # name :string not null
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null

View file

@ -71,11 +71,9 @@ class Message < ApplicationRecord
has_many :attachments, dependent: :destroy, autosave: true, before_add: :validate_attachments_limit has_many :attachments, dependent: :destroy, autosave: true, before_add: :validate_attachments_limit
after_create :reopen_conversation, after_create :reopen_conversation,
:execute_message_template_hooks,
:notify_via_mail :notify_via_mail
# we need to wait for the active storage attachments to be available after_create_commit :execute_after_create_commit_callbacks
after_create_commit :dispatch_create_events, :send_reply
after_update :dispatch_update_event after_update :dispatch_update_event
@ -117,6 +115,14 @@ class Message < ApplicationRecord
private private
def execute_after_create_commit_callbacks
# rails issue with order of active record callbacks being executed
# https://github.com/rails/rails/issues/20911
dispatch_create_events
send_reply
execute_message_template_hooks
end
def dispatch_create_events def dispatch_create_events
Rails.configuration.dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self) Rails.configuration.dispatcher.dispatch(MESSAGE_CREATED, Time.zone.now, message: self)

View file

@ -23,7 +23,7 @@ class Facebook::SendReplyService
def outgoing_message_from_chatwoot? def outgoing_message_from_chatwoot?
# messages sent directly from chatwoot won't have source_id. # messages sent directly from chatwoot won't have source_id.
message.outgoing? && !message.source_id (message.outgoing? || message.template?) && !message.source_id
end end
# def reopen_lock # def reopen_lock

View file

@ -4,6 +4,8 @@ class MessageTemplates::HookExecutionService
def perform def perform
return if inbox.agent_bot_inbox&.active? return if inbox.agent_bot_inbox&.active?
::MessageTemplates::Template::Greeting.new(conversation: conversation).perform if should_send_greeting?
::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if should_send_email_collect? ::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if should_send_email_collect?
end end
@ -16,8 +18,16 @@ class MessageTemplates::HookExecutionService
conversation.messages.outgoing.count.zero? && conversation.messages.template.count.zero? conversation.messages.outgoing.count.zero? && conversation.messages.template.count.zero?
end end
def should_send_greeting?
first_message_from_contact? && conversation.inbox.greeting_enabled?
end
def email_collect_was_sent?
conversation.messages.where(content_type: 'input_email').present?
end
def should_send_email_collect? def should_send_email_collect?
!contact_has_email? && conversation.inbox.web_widget? && first_message_from_contact? !contact_has_email? && conversation.inbox.web_widget? && !email_collect_was_sent?
end end
def contact_has_email? def contact_has_email?

View file

@ -3,7 +3,6 @@ class MessageTemplates::Template::EmailCollect
def perform def perform
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
conversation.messages.create!(typical_reply_message_params)
conversation.messages.create!(ways_to_reach_you_message_params) conversation.messages.create!(ways_to_reach_you_message_params)
conversation.messages.create!(email_input_box_template_message_params) conversation.messages.create!(email_input_box_template_message_params)
end end
@ -17,21 +16,6 @@ class MessageTemplates::Template::EmailCollect
delegate :contact, :account, to: :conversation delegate :contact, :account, to: :conversation
delegate :inbox, to: :message delegate :inbox, to: :message
def typical_reply_message_params
content = @conversation.inbox&.channel&.agent_away_message
if content.blank?
content = I18n.t('conversations.templates.typical_reply_message_body',
account_name: account.name)
end
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: content
}
end
def ways_to_reach_you_message_params def ways_to_reach_you_message_params
content = I18n.t('conversations.templates.ways_to_reach_you_message_body', content = I18n.t('conversations.templates.ways_to_reach_you_message_body',
account_name: account.name) account_name: account.name)

View file

@ -0,0 +1,32 @@
class MessageTemplates::Template::Greeting
pattr_initialize [:conversation!]
def perform
ActiveRecord::Base.transaction do
conversation.messages.create!(greeting_message_params)
end
rescue StandardError => e
Raven.capture_exception(e)
true
end
private
delegate :contact, :account, to: :conversation
delegate :inbox, to: :message
def greeting_message_params
content = @conversation.inbox&.greeting_message
if content.blank?
content = I18n.t('conversations.templates.greeting_message_body',
account_name: account.name)
end
{
account_id: @conversation.account_id,
inbox_id: @conversation.inbox_id,
message_type: :template,
content: content
}
end
end

View file

@ -5,7 +5,7 @@ class Twilio::OutgoingMessageService
return if message.private return if message.private
return if message.source_id return if message.source_id
return if inbox.channel.class.to_s != 'Channel::TwilioSms' return if inbox.channel.class.to_s != 'Channel::TwilioSms'
return unless message.outgoing? return unless outgoing_message?
twilio_message = client.messages.create(message_params) twilio_message = client.messages.create(message_params)
message.update!(source_id: twilio_message.sid) message.update!(source_id: twilio_message.sid)
@ -39,6 +39,10 @@ class Twilio::OutgoingMessageService
@channel ||= inbox.channel @channel ||= inbox.channel
end end
def outgoing_message?
message.outgoing? || message.template?
end
def client def client
::Twilio::REST::Client.new(channel.account_sid, channel.auth_token) ::Twilio::REST::Client.new(channel.account_sid, channel.auth_token)
end end

View file

@ -64,7 +64,7 @@ class Twitter::DirectMessageParserService < Twitter::WebhooksBaseService
end end
def set_conversation def set_conversation
@conversation = @contact_inbox.conversations.first @conversation = @contact_inbox.conversations.where("additional_attributes ->> 'type' = 'direct_message'").first
return if @conversation return if @conversation
@conversation = ::Conversation.create!(conversation_params) @conversation = ::Conversation.create!(conversation_params)

View file

@ -56,7 +56,7 @@ class Twitter::SendReplyService
end end
def outgoing_message_from_chatwoot? def outgoing_message_from_chatwoot?
message.outgoing? (message.outgoing? || message.template?)
end end
delegate :additional_attributes, to: :contact delegate :additional_attributes, to: :contact

View file

@ -2,12 +2,13 @@ json.id @inbox.id
json.channel_id @inbox.channel_id json.channel_id @inbox.channel_id
json.name @inbox.name json.name @inbox.name
json.channel_type @inbox.channel_type json.channel_type @inbox.channel_type
json.greeting_enabled @inbox.greeting_enabled
json.greeting_message @inbox.greeting_message
json.avatar_url @inbox.try(:avatar_url) json.avatar_url @inbox.try(:avatar_url)
json.website_token @inbox.channel.try(:website_token) json.website_token @inbox.channel.try(:website_token)
json.widget_color @inbox.channel.try(:widget_color) json.widget_color @inbox.channel.try(:widget_color)
json.website_url @inbox.channel.try(:website_url) json.website_url @inbox.channel.try(:website_url)
json.welcome_title @inbox.channel.try(:welcome_title) json.welcome_title @inbox.channel.try(:welcome_title)
json.welcome_tagline @inbox.channel.try(:welcome_tagline) json.welcome_tagline @inbox.channel.try(:welcome_tagline)
json.agent_away_message @inbox.channel.try(:agent_away_message)
json.web_widget_script @inbox.channel.try(:web_widget_script) json.web_widget_script @inbox.channel.try(:web_widget_script)
json.enable_auto_assignment @inbox.enable_auto_assignment json.enable_auto_assignment @inbox.enable_auto_assignment

View file

@ -4,13 +4,14 @@ json.payload do
json.channel_id inbox.channel_id json.channel_id inbox.channel_id
json.name inbox.name json.name inbox.name
json.channel_type inbox.channel_type json.channel_type inbox.channel_type
json.greeting_enabled inbox.greeting_enabled
json.greeting_message inbox.greeting_message
json.avatar_url inbox.try(:avatar_url) json.avatar_url inbox.try(:avatar_url)
json.page_id inbox.channel.try(:page_id) json.page_id inbox.channel.try(:page_id)
json.widget_color inbox.channel.try(:widget_color) json.widget_color inbox.channel.try(:widget_color)
json.website_url inbox.channel.try(:website_url) json.website_url inbox.channel.try(:website_url)
json.welcome_title inbox.channel.try(:welcome_title) json.welcome_title inbox.channel.try(:welcome_title)
json.welcome_tagline inbox.channel.try(:welcome_tagline) json.welcome_tagline inbox.channel.try(:welcome_tagline)
json.agent_away_message inbox.channel.try(:agent_away_message)
json.enable_auto_assignment inbox.enable_auto_assignment json.enable_auto_assignment inbox.enable_auto_assignment
json.web_widget_script inbox.channel.try(:web_widget_script) json.web_widget_script inbox.channel.try(:web_widget_script)
json.phone_number inbox.channel.try(:phone_number) json.phone_number inbox.channel.try(:phone_number)

View file

@ -2,12 +2,13 @@ json.id @inbox.id
json.channel_id @inbox.channel_id json.channel_id @inbox.channel_id
json.name @inbox.name json.name @inbox.name
json.channel_type @inbox.channel_type json.channel_type @inbox.channel_type
json.greeting_enabled @inbox.greeting_enabled
json.greeting_message @inbox.greeting_message
json.avatar_url @inbox.try(:avatar_url) json.avatar_url @inbox.try(:avatar_url)
json.website_token @inbox.channel.try(:website_token) json.website_token @inbox.channel.try(:website_token)
json.widget_color @inbox.channel.try(:widget_color) json.widget_color @inbox.channel.try(:widget_color)
json.website_url @inbox.channel.try(:website_url) json.website_url @inbox.channel.try(:website_url)
json.welcome_title @inbox.channel.try(:welcome_title) json.welcome_title @inbox.channel.try(:welcome_title)
json.welcome_tagline @inbox.channel.try(:welcome_tagline) json.welcome_tagline @inbox.channel.try(:welcome_tagline)
json.agent_away_message @inbox.channel.try(:agent_away_message)
json.web_widget_script @inbox.channel.try(:web_widget_script) json.web_widget_script @inbox.channel.try(:web_widget_script)
json.enable_auto_assignment @inbox.enable_auto_assignment json.enable_auto_assignment @inbox.enable_auto_assignment

View file

@ -36,6 +36,6 @@ ca:
assigned: "Assignada a %{assignee_name} per %{user_name}" assigned: "Assignada a %{assignee_name} per %{user_name}"
removed: "%{user_name} ha tret l'assignació de la conversa" removed: "%{user_name} ha tret l'assignació de la conversa"
templates: templates:
typical_reply_message_body: "%{account_name} normalment respon a les poques hores." greeting_message_body: "%{account_name} normalment respon a les poques hores."
ways_to_reach_you_message_body: "Fes saber a l'equip la forma de posar-nos en contacte amb tu." ways_to_reach_you_message_body: "Fes saber a l'equip la forma de posar-nos en contacte amb tu."
email_input_box_message_body: "Rep les notificacions per correu electrònic" email_input_box_message_body: "Rep les notificacions per correu electrònic"

View file

@ -36,6 +36,6 @@ cs:
assigned: "Přiřazeno k %{assignee_name} uživatelem %{user_name}" assigned: "Přiřazeno k %{assignee_name} uživatelem %{user_name}"
removed: "Konverzace zrušena uživatelem %{user_name}" removed: "Konverzace zrušena uživatelem %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} obvykle odpovídá za několik hodin." greeting_message_body: "%{account_name} obvykle odpovídá za několik hodin."
ways_to_reach_you_message_body: "Dejte týmu způsob, jak se k vám dostat." ways_to_reach_you_message_body: "Dejte týmu způsob, jak se k vám dostat."
email_input_box_message_body: "Dostat upozornění e-mailem" email_input_box_message_body: "Dostat upozornění e-mailem"

View file

@ -51,6 +51,6 @@ de:
assigned: "%{user_name} von %{assignee_name} zugewiesen" assigned: "%{user_name} von %{assignee_name} zugewiesen"
removed: "Gespräch nicht zugewiesen von %{user_name}" removed: "Gespräch nicht zugewiesen von %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} Antworten in der Regel in wenigen Stunden." greeting_message_body: "%{account_name} Antworten in der Regel in wenigen Stunden."
ways_to_reach_you_message_body: "Geben Sie dem Team einen Weg, Sie zu erreichen." ways_to_reach_you_message_body: "Geben Sie dem Team einen Weg, Sie zu erreichen."
email_input_box_message_body: "Lassen Sie sich per E-Mail benachrichtigen" email_input_box_message_body: "Lassen Sie sich per E-Mail benachrichtigen"

View file

@ -36,7 +36,7 @@ el:
assigned: "Ανατέθηκε στον %{assignee_name} από τον %{user_name}" assigned: "Ανατέθηκε στον %{assignee_name} από τον %{user_name}"
removed: "Η συνομιλία σημάνθηκε ως μη ανατεθειμένη από τον %{user_name}" removed: "Η συνομιλία σημάνθηκε ως μη ανατεθειμένη από τον %{user_name}"
templates: templates:
typical_reply_message_body: "Ο/Η %{account_name} συνήθως απαντάει σε μερικές ώρες." greeting_message_body: "Ο/Η %{account_name} συνήθως απαντάει σε μερικές ώρες."
ways_to_reach_you_message_body: "Δώστε στην ομάδα ένα τρόπο να φτάσει σε σας." ways_to_reach_you_message_body: "Δώστε στην ομάδα ένα τρόπο να φτάσει σε σας."
email_input_box_message_body: "Ειδοποιηθείτε με email" email_input_box_message_body: "Ειδοποιηθείτε με email"
reply: reply:

View file

@ -51,7 +51,7 @@ en:
assigned: "Assigned to %{assignee_name} by %{user_name}" assigned: "Assigned to %{assignee_name} by %{user_name}"
removed: "Conversation unassigned by %{user_name}" removed: "Conversation unassigned by %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} typically replies in a few hours." greeting_message_body: "%{account_name} typically replies in a few hours."
ways_to_reach_you_message_body: "Give the team a way to reach you." ways_to_reach_you_message_body: "Give the team a way to reach you."
email_input_box_message_body: "Get notified by email" email_input_box_message_body: "Get notified by email"
reply: reply:

View file

@ -36,7 +36,7 @@ es:
assigned: "Asignado a %{assignee_name} por %{user_name}" assigned: "Asignado a %{assignee_name} por %{user_name}"
removed: "Conversación no asignada por %{user_name}" removed: "Conversación no asignada por %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} normalmente responde en unas pocas horas." greeting_message_body: "%{account_name} normalmente responde en unas pocas horas."
ways_to_reach_you_message_body: "Dale al equipo una forma de llegar a ti." ways_to_reach_you_message_body: "Dale al equipo una forma de llegar a ti."
email_input_box_message_body: "Recibir notificaciones por correo electrónico" email_input_box_message_body: "Recibir notificaciones por correo electrónico"
reply: reply:

View file

@ -36,7 +36,7 @@ fr:
assigned: "Assigné à %{assignee_name} par %{user_name}" assigned: "Assigné à %{assignee_name} par %{user_name}"
removed: "Responsable de la conversation supprimé par %{user_name}" removed: "Responsable de la conversation supprimé par %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} répond généralement en quelques heures." greeting_message_body: "%{account_name} répond généralement en quelques heures."
ways_to_reach_you_message_body: "Donnez à l'équipe un moyen de vous recontacter." ways_to_reach_you_message_body: "Donnez à l'équipe un moyen de vous recontacter."
email_input_box_message_body: "Recevez des notifications par courriel" email_input_box_message_body: "Recevez des notifications par courriel"
reply: reply:

View file

@ -36,6 +36,6 @@ it:
assigned: "Assegnato a %{assignee_name} da %{user_name}" assigned: "Assegnato a %{assignee_name} da %{user_name}"
removed: "Conversazione non assegnata da %{user_name}" removed: "Conversazione non assegnata da %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} risponde tipicamente tra qualche ora." greeting_message_body: "%{account_name} risponde tipicamente tra qualche ora."
ways_to_reach_you_message_body: "Offri alla squadra un modo per raggiungerti." ways_to_reach_you_message_body: "Offri alla squadra un modo per raggiungerti."
email_input_box_message_body: "Ricevi una notifica via email" email_input_box_message_body: "Ricevi una notifica via email"

View file

@ -36,6 +36,6 @@ ml:
assigned: "%{assignee_name} %{user_name}-നെ നിയുക്തനാക്കി " assigned: "%{assignee_name} %{user_name}-നെ നിയുക്തനാക്കി "
removed: "%{user_name} സംഭാഷണം നിയുക്തമല്ലാതാക്കി" removed: "%{user_name} സംഭാഷണം നിയുക്തമല്ലാതാക്കി"
templates: templates:
typical_reply_message_body: "%{account_name} സാധാരണ കുറച്ച് മണിക്കൂറിനുള്ളിൽ മറുപടി നൽകുന്നു." greeting_message_body: "%{account_name} സാധാരണ കുറച്ച് മണിക്കൂറിനുള്ളിൽ മറുപടി നൽകുന്നു."
ways_to_reach_you_message_body: "നിങ്ങളിലേക്ക് എത്താൻ ടീമിന് ഒരു വഴി നൽകുക." ways_to_reach_you_message_body: "നിങ്ങളിലേക്ക് എത്താൻ ടീമിന് ഒരു വഴി നൽകുക."
email_input_box_message_body: "ഇമെയിൽ വഴി അറിയിപ്പ് നേടുക" email_input_box_message_body: "ഇമെയിൽ വഴി അറിയിപ്പ് നേടുക"

View file

@ -36,6 +36,6 @@ nl:
assigned: "Toegewezen aan %{assignee_name} door %{user_name}" assigned: "Toegewezen aan %{assignee_name} door %{user_name}"
removed: "Gesprek niet toegewezen door %{user_name}" removed: "Gesprek niet toegewezen door %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} reageert meestal binnen een paar uur." greeting_message_body: "%{account_name} reageert meestal binnen een paar uur."
ways_to_reach_you_message_body: "Geef het team een manier om je te bereiken." ways_to_reach_you_message_body: "Geef het team een manier om je te bereiken."
email_input_box_message_body: "Ontvang een melding via e-mail" email_input_box_message_body: "Ontvang een melding via e-mail"

View file

@ -36,6 +36,6 @@ pl:
assigned: "Przypisane do %{assignee_name} przez %{user_name}" assigned: "Przypisane do %{assignee_name} przez %{user_name}"
removed: "Rozmowa nieprzypisana przez %{user_name}" removed: "Rozmowa nieprzypisana przez %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} zazwyczaj odpowiada w kilka godzin." greeting_message_body: "%{account_name} zazwyczaj odpowiada w kilka godzin."
ways_to_reach_you_message_body: "Daj drużynie możliwość dotarcia do Ciebie." ways_to_reach_you_message_body: "Daj drużynie możliwość dotarcia do Ciebie."
email_input_box_message_body: "Otrzymuj powiadomienia przez e-mail" email_input_box_message_body: "Otrzymuj powiadomienia przez e-mail"

View file

@ -36,6 +36,6 @@ pt:
assigned: "Atribuído a %{assignee_name} por %{user_name}" assigned: "Atribuído a %{assignee_name} por %{user_name}"
removed: "Conversa não atribuída por %{user_name}" removed: "Conversa não atribuída por %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} normalmente responde em algumas horas." greeting_message_body: "%{account_name} normalmente responde em algumas horas."
ways_to_reach_you_message_body: "Dê à equipe um jeito de contatá-lo." ways_to_reach_you_message_body: "Dê à equipe um jeito de contatá-lo."
email_input_box_message_body: "Seja notificado por e-mail" email_input_box_message_body: "Seja notificado por e-mail"

View file

@ -36,6 +36,6 @@ pt-BR:
assigned: "Atribuído a %{assignee_name} por %{user_name}" assigned: "Atribuído a %{assignee_name} por %{user_name}"
removed: "Conversa não atribuída por %{user_name}" removed: "Conversa não atribuída por %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} normalmente responde em algumas horas." greeting_message_body: "%{account_name} normalmente responde em algumas horas."
ways_to_reach_you_message_body: "Informe uma forma para entrarmos em contato com você." ways_to_reach_you_message_body: "Informe uma forma para entrarmos em contato com você."
email_input_box_message_body: "Seja notificado por e-mail" email_input_box_message_body: "Seja notificado por e-mail"

View file

@ -36,7 +36,7 @@ ro:
assigned: "Atribuit lui %{assignee_name} de %{user_name}" assigned: "Atribuit lui %{assignee_name} de %{user_name}"
removed: "Conversație neasociată de %{user_name}" removed: "Conversație neasociată de %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} răspunde de obicei în câteva ore." greeting_message_body: "%{account_name} răspunde de obicei în câteva ore."
ways_to_reach_you_message_body: "Dă-i echipei o modalitate de a te contacta." ways_to_reach_you_message_body: "Dă-i echipei o modalitate de a te contacta."
email_input_box_message_body: "Primește notificări prin e-mail" email_input_box_message_body: "Primește notificări prin e-mail"
reply: reply:

View file

@ -36,6 +36,6 @@ sv:
assigned: "Tilldelad till %{assignee_name} av %{user_name}" assigned: "Tilldelad till %{assignee_name} av %{user_name}"
removed: "Konversation otilldelad av %{user_name}" removed: "Konversation otilldelad av %{user_name}"
templates: templates:
typical_reply_message_body: "%{account_name} svarar vanligtvis om några timmar." greeting_message_body: "%{account_name} svarar vanligtvis om några timmar."
ways_to_reach_you_message_body: "Ge laget ett sätt att nå dig." ways_to_reach_you_message_body: "Ge laget ett sätt att nå dig."
email_input_box_message_body: "Få meddelande via e-post" email_input_box_message_body: "Få meddelande via e-post"

View file

@ -0,0 +1,21 @@
class AgentAwayMessageToAutoReply < ActiveRecord::Migration[6.0]
def change
add_column :inboxes, :greeting_enabled, :boolean, default: false # rubocop:disable Rails/BulkChangeTable
add_column :inboxes, :greeting_message, :string
migrate_agent_away_to_greeting
remove_column :channel_web_widgets, :agent_away_message, :string
end
def migrate_agent_away_to_greeting
::Channel::WebWidget.find_in_batches do |widget_batch|
widget_batch.each do |widget|
inbox = widget.inbox
inbox.greeting_enabled = true
inbox.greeting_message = widget.agent_away_message
widget.save!
end
end
end
end

View file

@ -161,7 +161,6 @@ ActiveRecord::Schema.define(version: 2020_06_07_140737) do
t.string "widget_color", default: "#1f93ff" t.string "widget_color", default: "#1f93ff"
t.string "welcome_title" t.string "welcome_title"
t.string "welcome_tagline" t.string "welcome_tagline"
t.string "agent_away_message"
t.index ["website_token"], name: "index_channel_web_widgets_on_website_token", unique: true t.index ["website_token"], name: "index_channel_web_widgets_on_website_token", unique: true
end end
@ -245,6 +244,8 @@ ActiveRecord::Schema.define(version: 2020_06_07_140737) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "channel_type" t.string "channel_type"
t.boolean "enable_auto_assignment", default: true t.boolean "enable_auto_assignment", default: true
t.boolean "greeting_enabled", default: false
t.string "greeting_message"
t.index ["account_id"], name: "index_inboxes_on_account_id" t.index ["account_id"], name: "index_inboxes_on_account_id"
end end

View file

@ -24,8 +24,8 @@ RSpec.describe '/api/v1/widget/messages', type: :request do
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
json_response = JSON.parse(response.body) json_response = JSON.parse(response.body)
# 2 messages created + 3 messages by the template hook # 2 messages created + 2 messages by the email hook
expect(json_response.length).to eq(5) expect(json_response.length).to eq(4)
end end
end end
end end

View file

@ -15,7 +15,7 @@ describe ::MessageFinder do
create(:message, account: account, inbox: inbox, conversation: conversation) create(:message, account: account, inbox: inbox, conversation: conversation)
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation) create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation) create(:message, message_type: 'activity', account: account, inbox: inbox, conversation: conversation)
# this outgoing message creates 3 additional messages because of the hook execution service # this outgoing message creates 2 additional messages because of the email hook execution service
create(:message, message_type: 'outgoing', account: account, inbox: inbox, conversation: conversation) create(:message, message_type: 'outgoing', account: account, inbox: inbox, conversation: conversation)
end end
@ -25,7 +25,7 @@ describe ::MessageFinder do
it 'filter conversations by status' do it 'filter conversations by status' do
result = message_finder.perform result = message_finder.perform
expect(result.count).to be 7 expect(result.count).to be 6
end end
end end
@ -34,7 +34,7 @@ describe ::MessageFinder do
it 'filter conversations by status' do it 'filter conversations by status' do
result = message_finder.perform result = message_finder.perform
expect(result.count).to be 5 expect(result.count).to be 4
end end
end end
@ -44,7 +44,7 @@ describe ::MessageFinder do
it 'filter conversations by status' do it 'filter conversations by status' do
result = message_finder.perform result = message_finder.perform
expect(result.count).to be 7 expect(result.count).to be 6
end end
end end
end end

View file

@ -7,7 +7,7 @@ describe Webhooks::Twitter do
let!(:account) { create(:account) } let!(:account) { create(:account) }
# FIX ME: recipient id is set to 1 inside event factories # FIX ME: recipient id is set to 1 inside event factories
let!(:twitter_channel) { create(:channel_twitter_profile, account: account, profile_id: '1') } let!(:twitter_channel) { create(:channel_twitter_profile, account: account, profile_id: '1') }
let!(:twitter_inbox) { create(:inbox, channel: twitter_channel, account: account) } let!(:twitter_inbox) { create(:inbox, channel: twitter_channel, account: account, greeting_enabled: false) }
let!(:dm_params) { build(:twitter_message_create_event).with_indifferent_access } let!(:dm_params) { build(:twitter_message_create_event).with_indifferent_access }
let!(:tweet_params) { build(:tweet_create_event).with_indifferent_access } let!(:tweet_params) { build(:tweet_create_event).with_indifferent_access }

View file

@ -6,7 +6,7 @@ RSpec.describe ConversationMailbox, type: :mailbox do
describe 'add mail as reply in a conversation' do describe 'add mail as reply in a conversation' do
let(:agent) { create(:user, email: 'agent1@example.com') } let(:agent) { create(:user, email: 'agent1@example.com') }
let(:reply_mail) { create_inbound_email_from_fixture('reply.eml') } let(:reply_mail) { create_inbound_email_from_fixture('reply.eml') }
let(:conversation) { create(:conversation, assignee: agent) } let(:conversation) { create(:conversation, assignee: agent, inbox: create(:inbox, greeting_enabled: false)) }
let(:described_subject) { described_class.receive reply_mail } let(:described_subject) { described_class.receive reply_mail }
let(:serialized_attributes) { %w[text_content html_content number_of_attachments subject date to from in_reply_to cc bcc message_id] } let(:serialized_attributes) { %w[text_content html_content number_of_attachments subject date to from in_reply_to cc bcc message_id] }

View file

@ -5,17 +5,22 @@ describe ::MessageTemplates::HookExecutionService do
it 'calls ::MessageTemplates::Template::EmailCollect' do it 'calls ::MessageTemplates::Template::EmailCollect' do
contact = create(:contact, email: nil) contact = create(:contact, email: nil)
conversation = create(:conversation, contact: contact) conversation = create(:conversation, contact: contact)
message = create(:message, conversation: conversation)
# this hook will only get executed for conversations with out any template messages # ensure greeting hook is enabled
message.conversation.messages.template.destroy_all conversation.inbox.update(greeting_enabled: true)
email_collect_service = double email_collect_service = double
greeting_service = double
allow(::MessageTemplates::Template::EmailCollect).to receive(:new).and_return(email_collect_service) allow(::MessageTemplates::Template::EmailCollect).to receive(:new).and_return(email_collect_service)
allow(email_collect_service).to receive(:perform).and_return(true) allow(email_collect_service).to receive(:perform).and_return(true)
allow(::MessageTemplates::Template::Greeting).to receive(:new).and_return(greeting_service)
allow(greeting_service).to receive(:perform).and_return(true)
described_class.new(message: message).perform # described class gets called in message after commit
message = create(:message, conversation: conversation)
expect(::MessageTemplates::Template::Greeting).to have_received(:new).with(conversation: message.conversation)
expect(greeting_service).to have_received(:perform)
expect(::MessageTemplates::Template::EmailCollect).to have_received(:new).with(conversation: message.conversation) expect(::MessageTemplates::Template::EmailCollect).to have_received(:new).with(conversation: message.conversation)
expect(email_collect_service).to have_received(:perform) expect(email_collect_service).to have_received(:perform)
end end

View file

@ -6,7 +6,7 @@ describe ::MessageTemplates::Template::EmailCollect do
it 'creates the email collect messages' do it 'creates the email collect messages' do
described_class.new(conversation: conversation).perform described_class.new(conversation: conversation).perform
expect(conversation.messages.count).to eq(3) expect(conversation.messages.count).to eq(2)
end end
end end
end end

View file

@ -0,0 +1,12 @@
require 'rails_helper'
describe ::MessageTemplates::Template::Greeting do
context 'when this hook is called' do
let(:conversation) { create(:conversation) }
it 'creates the email collect messages' do
described_class.new(conversation: conversation).perform
expect(conversation.messages.count).to eq(1)
end
end
end

View file

@ -3,7 +3,8 @@ require 'rails_helper'
describe Twilio::IncomingMessageService do describe Twilio::IncomingMessageService do
let!(:account) { create(:account) } let!(:account) { create(:account) }
let!(:twilio_sms) do let!(:twilio_sms) do
create(:channel_twilio_sms, account: account, phone_number: '+1234567890', account_sid: 'ACxxx') create(:channel_twilio_sms, account: account, phone_number: '+1234567890', account_sid: 'ACxxx',
inbox: create(:inbox, account: account, greeting_enabled: false))
end end
let!(:contact) { create(:contact, account: account, phone_number: '+12345') } let!(:contact) { create(:contact, account: account, phone_number: '+12345') }
let(:contact_inbox) { create(:contact_inbox, source_id: '+12345', contact: contact, inbox: twilio_sms.inbox) } let(:contact_inbox) { create(:contact_inbox, source_id: '+12345', contact: contact, inbox: twilio_sms.inbox) }