2018-10-16 08:45:15 +00:00
|
|
|
class Channel::Driver::Sms::Twilio
|
|
|
|
NAME = 'sms/twilio'.freeze
|
|
|
|
|
|
|
|
def fetchable?(_channel)
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
|
|
|
def send(options, attr, _notification = false)
|
|
|
|
Rails.logger.info "Sending SMS to recipient #{attr[:recipient]}"
|
|
|
|
|
|
|
|
return true if Setting.get('import_mode')
|
|
|
|
|
|
|
|
Rails.logger.info "Backend sending Twilio SMS to #{attr[:recipient]}"
|
|
|
|
begin
|
|
|
|
if Setting.get('developer_mode') != true
|
|
|
|
result = api(options).messages.create(
|
|
|
|
from: options[:sender],
|
2018-12-19 17:31:51 +00:00
|
|
|
to: attr[:recipient],
|
2018-10-16 08:45:15 +00:00
|
|
|
body: attr[:message],
|
|
|
|
)
|
|
|
|
|
|
|
|
raise result.error_message if result.error_code.positive?
|
|
|
|
end
|
|
|
|
|
|
|
|
true
|
|
|
|
rescue => e
|
|
|
|
Rails.logger.debug "Twilio error: #{e.inspect}"
|
|
|
|
raise e
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def process(_options, attr, channel)
|
|
|
|
Rails.logger.info "Receiving SMS frim recipient #{attr[:From]}"
|
|
|
|
|
|
|
|
# prevent already created articles
|
|
|
|
if Ticket::Article.find_by(message_id: attr[:SmsMessageSid])
|
|
|
|
return ['application/xml; charset=UTF-8;', Twilio::TwiML::MessagingResponse.new.to_s]
|
|
|
|
end
|
|
|
|
|
|
|
|
# find sender
|
|
|
|
user = User.where(mobile: attr[:From]).order(:updated_at).first
|
|
|
|
if !user
|
2019-06-28 11:38:49 +00:00
|
|
|
_from_comment, preferences = Cti::CallerId.get_comment_preferences(attr[:From], 'from')
|
2018-10-16 08:45:15 +00:00
|
|
|
if preferences && preferences['from'] && preferences['from'][0]
|
|
|
|
if preferences['from'][0]['level'] == 'known' && preferences['from'][0]['object'] == 'User'
|
|
|
|
user = User.find_by(id: preferences['from'][0]['o_id'])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if !user
|
|
|
|
user = User.create!(
|
|
|
|
firstname: attr[:From],
|
2018-12-19 17:31:51 +00:00
|
|
|
mobile: attr[:From],
|
2018-10-16 08:45:15 +00:00
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
UserInfo.current_user_id = user.id
|
|
|
|
|
|
|
|
# find ticket
|
|
|
|
article_type_sms = Ticket::Article::Type.find_by(name: 'sms')
|
|
|
|
state_ids = Ticket::State.where(name: %w[closed merged removed]).pluck(:id)
|
|
|
|
ticket = Ticket.where(customer_id: user.id, create_article_type_id: article_type_sms.id).where.not(state_id: state_ids).order(:updated_at).first
|
|
|
|
if ticket
|
|
|
|
new_state = Ticket::State.find_by(default_create: true)
|
|
|
|
if ticket.state_id != new_state.id
|
|
|
|
ticket.state = Ticket::State.find_by(default_follow_up: true)
|
|
|
|
ticket.save!
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if channel.group_id.blank?
|
|
|
|
raise Exceptions::UnprocessableEntity, 'Group needed in channel definition!'
|
|
|
|
end
|
|
|
|
|
|
|
|
group = Group.find_by(id: channel.group_id)
|
|
|
|
if !group
|
|
|
|
raise Exceptions::UnprocessableEntity, 'Group is invalid!'
|
|
|
|
end
|
|
|
|
|
|
|
|
title = attr[:Body]
|
|
|
|
if title.length > 40
|
|
|
|
title = "#{title[0, 40]}..."
|
|
|
|
end
|
|
|
|
ticket = Ticket.new(
|
2018-12-19 17:31:51 +00:00
|
|
|
group_id: channel.group_id,
|
|
|
|
title: title,
|
|
|
|
state_id: Ticket::State.find_by(default_create: true).id,
|
2018-10-16 08:45:15 +00:00
|
|
|
priority_id: Ticket::Priority.find_by(default_create: true).id,
|
|
|
|
customer_id: user.id,
|
|
|
|
preferences: {
|
|
|
|
channel_id: channel.id,
|
2018-12-19 17:31:51 +00:00
|
|
|
sms: {
|
2018-10-16 08:45:15 +00:00
|
|
|
AccountSid: attr['AccountSid'],
|
2018-12-19 17:31:51 +00:00
|
|
|
From: attr['From'],
|
|
|
|
To: attr['To'],
|
2018-10-16 08:45:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
ticket.save!
|
|
|
|
end
|
|
|
|
|
|
|
|
Ticket::Article.create!(
|
2018-12-19 17:31:51 +00:00
|
|
|
ticket_id: ticket.id,
|
|
|
|
type: article_type_sms,
|
|
|
|
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
|
|
|
body: attr[:Body],
|
|
|
|
from: attr[:From],
|
|
|
|
to: attr[:To],
|
|
|
|
message_id: attr[:SmsMessageSid],
|
2018-10-16 08:45:15 +00:00
|
|
|
content_type: 'text/plain',
|
2018-12-19 17:31:51 +00:00
|
|
|
preferences: {
|
2018-10-16 08:45:15 +00:00
|
|
|
channel_id: channel.id,
|
2018-12-19 17:31:51 +00:00
|
|
|
sms: {
|
2018-10-16 08:45:15 +00:00
|
|
|
AccountSid: attr['AccountSid'],
|
2018-12-19 17:31:51 +00:00
|
|
|
From: attr['From'],
|
|
|
|
To: attr['To'],
|
2018-10-16 08:45:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
['application/xml; charset=UTF-8;', Twilio::TwiML::MessagingResponse.new.to_s]
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.definition
|
|
|
|
{
|
2018-12-19 17:31:51 +00:00
|
|
|
name: 'twilio',
|
|
|
|
adapter: 'sms/twilio',
|
|
|
|
account: [
|
2018-10-16 08:45:15 +00:00
|
|
|
{ name: 'options::webhook_token', display: 'Webhook Token', tag: 'input', type: 'text', limit: 200, null: false, default: Digest::MD5.hexdigest(rand(999_999_999_999).to_s), disabled: true, readonly: true },
|
|
|
|
{ name: 'options::account_id', display: 'Account SID', tag: 'input', type: 'text', limit: 200, null: false, placeholder: 'XXXXXX' },
|
|
|
|
{ name: 'options::token', display: 'Token', tag: 'input', type: 'text', limit: 200, null: false },
|
|
|
|
{ name: 'options::sender', display: 'Sender', tag: 'input', type: 'text', limit: 200, null: false, placeholder: '+491710000000' },
|
|
|
|
{ name: 'group_id', display: 'Destination Group', tag: 'select', null: false, relation: 'Group', nulloption: true, filter: { active: true } },
|
|
|
|
],
|
|
|
|
notification: [
|
|
|
|
{ name: 'options::account_id', display: 'Account SID', tag: 'input', type: 'text', limit: 200, null: false, placeholder: 'XXXXXX' },
|
|
|
|
{ name: 'options::token', display: 'Token', tag: 'input', type: 'text', limit: 200, null: false },
|
|
|
|
{ name: 'options::sender', display: 'Sender', tag: 'input', type: 'text', limit: 200, null: false, placeholder: '+491710000000' },
|
|
|
|
],
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def api(options)
|
|
|
|
@api ||= ::Twilio::REST::Client.new options[:account_id], options[:token]
|
|
|
|
end
|
|
|
|
end
|