Skip to content

Commit

Permalink
add signalwire, WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
vova4kin committed Sep 2, 2020
1 parent cb6fc9f commit f20057b
Show file tree
Hide file tree
Showing 13 changed files with 417 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.1
2.7.1@chatwoot_signalwire
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ gem 'twitty'
gem 'koala'
# slack client
gem 'slack-ruby-client'
# signal wire client
gem 'signalwire'

##--- gems for debugging and error reporting ---##
# static analysis
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ GEM
railties (>= 3.2, < 6.1)
equalizer (0.0.11)
erubi (1.9.0)
eventmachine (1.2.7)
execjs (2.7.0)
facebook-messenger (1.5.0)
httparty (~> 0.13, >= 0.13.7)
Expand All @@ -192,6 +193,9 @@ GEM
multipart-post (>= 1.2, < 3)
faraday_middleware (1.0.0)
faraday (~> 1.0)
faye-websocket (0.11.0)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
fcm (1.0.1)
faraday (~> 1.0.0)
ffi (1.13.1)
Expand Down Expand Up @@ -232,6 +236,7 @@ GEM
activesupport (>= 5)
haikunator (1.1.0)
hana (1.3.6)
has-guarded-handlers (1.6.3)
hashdiff (1.0.1)
hashie (4.1.0)
hkdf (0.3.0)
Expand Down Expand Up @@ -279,6 +284,7 @@ GEM
listen (3.2.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.4.2)
loofah (2.6.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand Down Expand Up @@ -457,6 +463,12 @@ GEM
rack (~> 2.0)
rack-protection (>= 2.0.0)
redis (>= 4.1.0)
signalwire (2.3.3)
concurrent-ruby (~> 1.1)
faye-websocket (~> 0.10)
has-guarded-handlers (~> 1.6.3)
logger (~> 1.3)
twilio-ruby (~> 5.0)
signet (0.14.0)
addressable (~> 2.3)
faraday (>= 0.17.3, < 2.0)
Expand Down Expand Up @@ -611,6 +623,7 @@ DEPENDENCIES
sentry-raven
shoulda-matchers
sidekiq
signalwire
simplecov (= 0.17.1)
slack-ruby-client
spring
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
class Api::V1::Accounts::Channels::SignalwireChannelsController < Api::V1::Accounts::BaseController
before_action :authorize_request

module Twilio::REST
class SignalwireError < ::Twilio::REST::TwilioError
end
end

def create
ActiveRecord::Base.transaction do
authenticate_signal_wire
build_inbox
setup_webhooks if @signal_wire_channel.sms?
rescue Signalwire::REST::SignalwireError => e
render_could_not_create_error(e.message)
rescue StandardError => e
render_could_not_create_error(e.message)
end
end

private

def authorize_request
authorize ::Inbox
end

def authenticate_signal_wire
client = Signalwire::REST::Client.new(
permitted_params[:account_sid] || 'ce607000-9d51-4699-85d3-f628a36da245',
permitted_params[:auth_token] || 'PT672ccf03259864f6910563ec9da1cbea282ce0e8a7bfed55',
signalwire_space_url: permitted_params[:space_url] || 'chatwoot-integration.signalwire.com'
)
client.messages.list(limit: 1)
end

def setup_webhooks
::Signalwire::WebhookSetupService.new(inbox: @inbox).perform
end

def medium
permitted_params[:medium]
end

def build_inbox
@signal_wire_channel = Current.account.signalwire_sms.create!(
account_sid: permitted_params[:account_sid],
auth_token: permitted_params[:auth_token],
phone_number: permitted_params[:phone_number],
space_url: permitted_params[:space_url],
medium: medium
)
@inbox = Current.account.inboxes.create(
name: permitted_params[:name],
channel: @signal_wire_channel
)
end

def permitted_params
params.require(:signal_wire_channel).permit(
:account_id, :phone_number, :account_sid, :space_url, :phone_number, :auth_token, :name, :medium
)
end
end
1 change: 1 addition & 0 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Account < ApplicationRecord
has_many :facebook_pages, dependent: :destroy, class_name: '::Channel::FacebookPage'
has_many :telegram_bots, dependent: :destroy
has_many :twilio_sms, dependent: :destroy, class_name: '::Channel::TwilioSms'
has_many :signalwire_sms, dependent: :destroy, class_name: '::Channel::SignalwireSms'
has_many :twitter_profiles, dependent: :destroy, class_name: '::Channel::TwitterProfile'
has_many :web_widgets, dependent: :destroy, class_name: '::Channel::WebWidget'
has_many :email_channels, dependent: :destroy, class_name: '::Channel::Email'
Expand Down
42 changes: 42 additions & 0 deletions app/models/channel/signalwire_sms.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# == Schema Information
#
# Table name: channel_signalwire_sms
#
# id :bigint not null, primary key
# account_sid :string not null
# auth_token :string not null
# medium :integer default("sms"), not null
# phone_number :string not null
# space_url :string not null
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
#
# Indexes
#
# index_channel_signalwire_sms_on_account_id_and_phone_number (account_id,phone_number) UNIQUE
# index_channel_signalwire_sms_on_medium (medium)
#
class Channel::SignalwireSms < ApplicationRecord
self.table_name = 'channel_signalwire_sms'

validates :account_id, presence: true
validates :account_sid, presence: true
validates :space_url, presence: true
validates :auth_token, presence: true
validates :phone_number, uniqueness: { scope: :account_id }, presence: true

enum medium: { sms: 0 }

belongs_to :account

has_one :inbox, as: :channel, dependent: :destroy

def has_24_hour_messaging_window?
true
end

def name
'SignalWire SMS'
end
end
109 changes: 109 additions & 0 deletions app/services/signalwire/incoming_message_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
class Signalwire::IncomingMessageService
include ::FileTypeHelper

pattr_initialize [:params!]

def perform
set_contact
set_conversation
@message = @conversation.messages.create(
content: params[:Body],
account_id: @inbox.account_id,
inbox_id: @inbox.id,
message_type: :incoming,
sender: @contact,
source_id: params[:SmsSid]
)
attach_files
end

private

def signalwire_inbox
@signalwire_inbox ||= ::Channel::SignalwireSms.find_by!(
account_sid: params[:AccountSid],
phone_number: params[:To]
)
end

def inbox
@inbox ||= signalwire_inbox.inbox
end

def account
@account ||= inbox.account
end

def formatted_phone_number
TelephoneNumber.parse(params[:From]).international_number
end

def set_contact
contact_inbox = ::ContactBuilder.new(
source_id: params[:From],
inbox: inbox,
contact_attributes: contact_attributes
).perform

@contact_inbox = contact_inbox
@contact = contact_inbox.contact
end

def conversation_params
{
account_id: @inbox.account_id,
inbox_id: @inbox.id,
contact_id: @contact.id,
contact_inbox_id: @contact_inbox.id,
additional_attributes: additional_attributes
}
end

def set_conversation
@conversation = @contact_inbox.conversations.first
return if @conversation

@conversation = ::Conversation.create!(conversation_params)
end

def contact_attributes
{
name: formatted_phone_number,
phone_number: params[:From],
additional_attributes: additional_attributes
}
end

def additional_attributes
if signalwire_inbox.sms?
{
from_zip_code: params[:FromZip],
from_country: params[:FromCountry],
from_state: params[:FromState]
}
else
{}
end
end

def attach_files
return if params[:MediaUrl0].blank?

file_resource = LocalResource.new(params[:MediaUrl0], params[:MediaContentType0])

attachment = @message.attachments.new(
account_id: @message.account_id,
file_type: file_type(params[:MediaContentType0])
)

attachment.file.attach(
io: file_resource.file,
filename: file_resource.tmp_filename,
content_type: file_resource.encoding
)

@message.save!
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED => e
Rails.logger.info "invalid url #{file_url} : #{e.message}"
end
end
37 changes: 37 additions & 0 deletions app/services/signalwire/send_on_signalwire_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class Signalwire::SendOnSignalwireService < Base::SendOnChannelService
private

def channel_class
Channel::SignalwireSms
end

def perform_reply
signalwire_message = client.messages.create(message_params)
message.update!(source_id: signalwire_message.sid)
end

def message_params
params = {
body: message.content,
from: channel.phone_number,
to: contact_inbox.source_id
}
params
end

def inbox
@inbox ||= message.inbox
end

def channel
@channel ||= inbox.channel
end

def outgoing_message?
message.outgoing? || message.template?
end

def client
::Signalwire::REST::Client.new(channel.account_sid, channel.auth_token, signalwire_space_url: channel.space_url)
end
end
36 changes: 36 additions & 0 deletions app/services/signalwire/webhook_setup_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Signalwire::WebhookSetupService
include Rails.application.routes.url_helpers

pattr_initialize [:inbox!]

def perform
if phone_numbers.empty?
Rails.logger.info "SIGNALWIRE_PHONE_NUMBER_NOT_FOUND: #{channel.phone_number}"
else
signalwire_client
.incoming_phone_numbers(phonenumber_sid)
.update(sms_method: 'POST', sms_url: twilio_callback_index_url)
# ToDo: twilio_callback_index_url clarify for signalwire
end
rescue Signalwire::REST::SignalwireError => e
Rails.logger.info "SIGNALWIRE_FAILURE: #{e.message}"
end

private

def phonenumber_sid
phone_numbers.first.sid
end

def phone_numbers
@phone_numbers ||= signalwire_client.incoming_phone_numbers.list(phone_number: channel.phone_number)
end

def channel
@channel ||= inbox.channel
end

def signalwire_client
@signalwire_client ||= ::Twilio::REST::Client.new(channel.account_sid, channel.auth_token)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
json.id @inbox.id
json.channel_id @inbox.channel_id
json.name @inbox.name
json.channel_type @inbox.channel_type
json.enable_auto_assignment @inbox.enable_auto_assignment
json.phone_number @inbox.channel.phone_number
14 changes: 14 additions & 0 deletions db/migrate/20200901193206_create_channel_signalwire_sms.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateChannelSignalwireSms < ActiveRecord::Migration[6.0]
def change
create_table :channel_signalwire_sms do |t|
t.string :phone_number, null: false
t.string :auth_token, null: false
t.string :account_sid, null: false
t.string :space_url, null: false
t.integer :account_id, null: false
t.integer :medium, null: false, index: true, default: 0
t.timestamps
end
add_index :channel_signalwire_sms, [:account_id, :phone_number], unique: true
end
end
Loading

0 comments on commit f20057b

Please sign in to comment.