Merge branch 'develop' into feat/email-forwarding
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
class CsatSurveyService
|
||||
pattr_initialize [:conversation!]
|
||||
|
||||
def perform
|
||||
return unless should_send_csat_survey?
|
||||
|
||||
if within_messaging_window?
|
||||
::MessageTemplates::Template::CsatSurvey.new(conversation: conversation).perform
|
||||
else
|
||||
create_csat_not_sent_activity_message
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :inbox, :contact, to: :conversation
|
||||
|
||||
def should_send_csat_survey?
|
||||
conversation_allows_csat? && csat_enabled? && !csat_already_sent?
|
||||
end
|
||||
|
||||
def conversation_allows_csat?
|
||||
conversation.resolved? && !conversation.tweet?
|
||||
end
|
||||
|
||||
def csat_enabled?
|
||||
inbox.csat_survey_enabled?
|
||||
end
|
||||
|
||||
def csat_already_sent?
|
||||
conversation.messages.where(content_type: :input_csat).present?
|
||||
end
|
||||
|
||||
def within_messaging_window?
|
||||
conversation.can_reply?
|
||||
end
|
||||
|
||||
def create_csat_not_sent_activity_message
|
||||
content = I18n.t('conversations.activity.csat.not_sent_due_to_messaging_window')
|
||||
activity_message_params = {
|
||||
account_id: conversation.account_id,
|
||||
inbox_id: conversation.inbox_id,
|
||||
message_type: :activity,
|
||||
content: content
|
||||
}
|
||||
::Conversations::ActivityMessageJob.perform_later(conversation, activity_message_params) if content
|
||||
end
|
||||
end
|
||||
@@ -47,12 +47,29 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService
|
||||
def fb_text_message_params
|
||||
{
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: { text: message.content },
|
||||
message: fb_text_message_payload,
|
||||
messaging_type: 'MESSAGE_TAG',
|
||||
tag: 'ACCOUNT_UPDATE'
|
||||
}
|
||||
end
|
||||
|
||||
def fb_text_message_payload
|
||||
if message.content_type == 'input_select' && message.content_attributes['items'].any?
|
||||
{
|
||||
text: message.content,
|
||||
quick_replies: message.content_attributes['items'].map do |item|
|
||||
{
|
||||
content_type: 'text',
|
||||
payload: item['title'],
|
||||
title: item['title']
|
||||
}
|
||||
end
|
||||
}
|
||||
else
|
||||
{ text: message.outgoing_content }
|
||||
end
|
||||
end
|
||||
|
||||
def external_error(response)
|
||||
# https://developers.facebook.com/docs/graph-api/guides/error-handling/
|
||||
error_message = response['error']['message']
|
||||
|
||||
@@ -30,7 +30,7 @@ class Instagram::BaseSendService < Base::SendOnChannelService
|
||||
params = {
|
||||
recipient: { id: contact.get_source_id(inbox.id) },
|
||||
message: {
|
||||
text: message.content
|
||||
text: message.outgoing_content
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,14 @@ class Line::SendOnLineService < Base::SendOnChannelService
|
||||
end
|
||||
|
||||
def build_payload
|
||||
if message.content_type == 'input_select' && message.content_attributes['items'].any?
|
||||
build_input_select_payload
|
||||
else
|
||||
build_text_payload
|
||||
end
|
||||
end
|
||||
|
||||
def build_text_payload
|
||||
if message.content && message.attachments.any?
|
||||
[text_message, *attachments]
|
||||
elsif message.content.nil? && message.attachments.any?
|
||||
@@ -48,10 +56,47 @@ class Line::SendOnLineService < Base::SendOnChannelService
|
||||
def text_message
|
||||
{
|
||||
type: 'text',
|
||||
text: message.content
|
||||
text: message.outgoing_content
|
||||
}
|
||||
end
|
||||
|
||||
# https://developers.line.biz/en/reference/messaging-api/#flex-message
|
||||
def build_input_select_payload
|
||||
{
|
||||
type: 'flex',
|
||||
altText: message.content,
|
||||
contents: {
|
||||
type: 'bubble',
|
||||
body: {
|
||||
type: 'box',
|
||||
layout: 'vertical',
|
||||
contents: [
|
||||
{
|
||||
type: 'text',
|
||||
text: message.content
|
||||
},
|
||||
*input_select_to_button
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def input_select_to_button
|
||||
message.content_attributes['items'].map do |item|
|
||||
{
|
||||
type: 'button',
|
||||
style: 'link',
|
||||
height: 'sm',
|
||||
action: {
|
||||
type: 'message',
|
||||
label: item['title'],
|
||||
text: item['value']
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# https://developers.line.biz/en/reference/messaging-api/#error-responses
|
||||
def external_error(error)
|
||||
# Message containing information about the error. See https://developers.line.biz/en/reference/messaging-api/#error-messages
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
class Liquid::CampaignTemplateService
|
||||
pattr_initialize [:campaign!, :contact!]
|
||||
|
||||
def call(message)
|
||||
process_liquid_in_content(message_drops, message)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message_drops
|
||||
{
|
||||
'contact' => ContactDrop.new(contact),
|
||||
'agent' => UserDrop.new(campaign.sender),
|
||||
'inbox' => InboxDrop.new(campaign.inbox),
|
||||
'account' => AccountDrop.new(campaign.account)
|
||||
}
|
||||
end
|
||||
|
||||
def process_liquid_in_content(drops, message)
|
||||
message = message.gsub(/`(.*?)`/m, '{% raw %}`\\1`{% endraw %}')
|
||||
template = Liquid::Template.parse(message)
|
||||
template.render(drops)
|
||||
rescue Liquid::Error
|
||||
message
|
||||
end
|
||||
end
|
||||
@@ -17,7 +17,6 @@ class MessageTemplates::HookExecutionService
|
||||
::MessageTemplates::Template::OutOfOffice.new(conversation: conversation).perform if should_send_out_of_office_message?
|
||||
::MessageTemplates::Template::Greeting.new(conversation: conversation).perform if should_send_greeting?
|
||||
::MessageTemplates::Template::EmailCollect.new(conversation: conversation).perform if inbox.enable_email_collect && should_send_email_collect?
|
||||
::MessageTemplates::Template::CsatSurvey.new(conversation: conversation).perform if should_send_csat_survey?
|
||||
end
|
||||
|
||||
def should_send_out_of_office_message?
|
||||
@@ -55,23 +54,5 @@ class MessageTemplates::HookExecutionService
|
||||
def contact_has_email?
|
||||
contact.email
|
||||
end
|
||||
|
||||
def csat_enabled_conversation?
|
||||
return false unless conversation.resolved?
|
||||
# should not sent since the link will be public
|
||||
return false if conversation.tweet?
|
||||
return false unless inbox.csat_survey_enabled?
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def should_send_csat_survey?
|
||||
return unless csat_enabled_conversation?
|
||||
|
||||
# only send CSAT once in a conversation
|
||||
return if conversation.messages.where(content_type: :input_csat).present?
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
MessageTemplates::HookExecutionService.prepend_mod_with('MessageTemplates::HookExecutionService')
|
||||
|
||||
@@ -22,7 +22,8 @@ class Sms::OneoffSmsCampaignService
|
||||
campaign.account.contacts.tagged_with(audience_labels, any: true).each do |contact|
|
||||
next if contact.phone_number.blank?
|
||||
|
||||
send_message(to: contact.phone_number, content: campaign.message)
|
||||
content = Liquid::CampaignTemplateService.new(campaign: campaign, contact: contact).call(campaign.message)
|
||||
send_message(to: contact.phone_number, content: content)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -94,13 +94,25 @@ class Telegram::IncomingMessageService
|
||||
end
|
||||
|
||||
def file_content_type
|
||||
return :image if params[:message][:photo].present? || params.dig(:message, :sticker, :thumb).present?
|
||||
return :audio if params[:message][:voice].present? || params[:message][:audio].present?
|
||||
return :video if params[:message][:video].present?
|
||||
return :image if image_message?
|
||||
return :audio if audio_message?
|
||||
return :video if video_message?
|
||||
|
||||
file_type(params[:message][:document][:mime_type])
|
||||
end
|
||||
|
||||
def image_message?
|
||||
params[:message][:photo].present? || params.dig(:message, :sticker, :thumb).present?
|
||||
end
|
||||
|
||||
def audio_message?
|
||||
params[:message][:voice].present? || params[:message][:audio].present?
|
||||
end
|
||||
|
||||
def video_message?
|
||||
params[:message][:video].present? || params[:message][:video_note].present?
|
||||
end
|
||||
|
||||
def attach_files
|
||||
return unless file
|
||||
|
||||
@@ -174,6 +186,9 @@ class Telegram::IncomingMessageService
|
||||
end
|
||||
|
||||
def visual_media_params
|
||||
params[:message][:photo].presence&.last || params.dig(:message, :sticker, :thumb).presence || params[:message][:video].presence
|
||||
params[:message][:photo].presence&.last ||
|
||||
params.dig(:message, :sticker, :thumb).presence ||
|
||||
params[:message][:video].presence ||
|
||||
params[:message][:video_note].presence
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,7 +22,8 @@ class Twilio::OneoffSmsCampaignService
|
||||
campaign.account.contacts.tagged_with(audience_labels, any: true).each do |contact|
|
||||
next if contact.phone_number.blank?
|
||||
|
||||
channel.send_message(to: contact.phone_number, body: campaign.message)
|
||||
content = Liquid::CampaignTemplateService.new(campaign: campaign, contact: contact).call(campaign.message)
|
||||
channel.send_message(to: contact.phone_number, body: content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ class Twilio::SendOnTwilioService < Base::SendOnChannelService
|
||||
|
||||
def message_params
|
||||
{
|
||||
body: message.content,
|
||||
body: message.outgoing_content,
|
||||
to: contact_inbox.source_id,
|
||||
media_url: attachments
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class Twitter::SendOnTwitterService < Base::SendOnChannelService
|
||||
def send_direct_message
|
||||
twitter_client.send_direct_message(
|
||||
recipient_id: contact_inbox.source_id,
|
||||
message: message.content
|
||||
message: message.outgoing_content
|
||||
)
|
||||
end
|
||||
|
||||
@@ -52,7 +52,7 @@ class Twitter::SendOnTwitterService < Base::SendOnChannelService
|
||||
def send_tweet_reply
|
||||
response = twitter_client.send_tweet_reply(
|
||||
reply_to_tweet_id: reply_to_message.source_id,
|
||||
tweet: "#{screen_name} #{message.content}"
|
||||
tweet: "#{screen_name} #{message.outgoing_content}"
|
||||
)
|
||||
if response.status == '200'
|
||||
tweet_data = response.body
|
||||
|
||||
@@ -93,14 +93,14 @@ class Whatsapp::Providers::BaseService
|
||||
def create_button_payload(message)
|
||||
buttons = create_buttons(message.content_attributes['items'])
|
||||
json_hash = { 'buttons' => buttons }
|
||||
create_payload('button', message.content, JSON.generate(json_hash))
|
||||
create_payload('button', message.outgoing_content, JSON.generate(json_hash))
|
||||
end
|
||||
|
||||
def create_list_payload(message)
|
||||
rows = create_rows(message.content_attributes['items'])
|
||||
section1 = { 'rows' => rows }
|
||||
sections = [section1]
|
||||
json_hash = { :button => 'Choose an item', 'sections' => sections }
|
||||
create_payload('list', message.content, JSON.generate(json_hash))
|
||||
json_hash = { :button => I18n.t('conversations.messages.whatsapp.list_button_label'), 'sections' => sections }
|
||||
create_payload('list', message.outgoing_content, JSON.generate(json_hash))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,7 +63,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS
|
||||
headers: api_headers,
|
||||
body: {
|
||||
to: phone_number,
|
||||
text: { body: message.content },
|
||||
text: { body: message.outgoing_content },
|
||||
type: 'text'
|
||||
}.to_json
|
||||
)
|
||||
@@ -77,7 +77,7 @@ class Whatsapp::Providers::Whatsapp360DialogService < Whatsapp::Providers::BaseS
|
||||
type_content = {
|
||||
'link': attachment.download_url
|
||||
}
|
||||
type_content['caption'] = message.content unless %w[audio sticker].include?(type)
|
||||
type_content['caption'] = message.outgoing_content unless %w[audio sticker].include?(type)
|
||||
type_content['filename'] = attachment.file.filename if type == 'document'
|
||||
|
||||
response = HTTParty.post(
|
||||
|
||||
@@ -82,7 +82,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi
|
||||
messaging_product: 'whatsapp',
|
||||
context: whatsapp_reply_context(message),
|
||||
to: phone_number,
|
||||
text: { body: message.content },
|
||||
text: { body: message.outgoing_content },
|
||||
type: 'text'
|
||||
}.to_json
|
||||
)
|
||||
@@ -96,7 +96,7 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi
|
||||
type_content = {
|
||||
'link': attachment.download_url
|
||||
}
|
||||
type_content['caption'] = message.content unless %w[audio sticker].include?(type)
|
||||
type_content['caption'] = message.outgoing_content unless %w[audio sticker].include?(type)
|
||||
type_content['filename'] = attachment.file.filename if type == 'document'
|
||||
response = HTTParty.post(
|
||||
"#{phone_id_path}/messages",
|
||||
|
||||
@@ -61,7 +61,7 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
|
||||
return if body_object.blank?
|
||||
|
||||
template_match_regex = build_template_match_regex(body_object['text'])
|
||||
message.content.match(template_match_regex)
|
||||
message.outgoing_content.match(template_match_regex)
|
||||
end
|
||||
|
||||
def build_template_match_regex(template_text)
|
||||
|
||||
Reference in New Issue
Block a user